MegaBites-AI/Windows-powershell
0308
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4#region Using directives5 6using System;7using System.Collections.Concurrent;8using System.Collections.Generic;9using System.Globalization;10using System.Management.Automation;11using System.Management.Automation.Runspaces;12using Microsoft.Management.Infrastructure.Options;13 14#endregion15 16namespace Microsoft.Management.Infrastructure.CimCmdlets17{18 #region CimSessionWrapper19 20 internal class CimSessionWrapper21 {22 #region members23 24 /// <summary>25 /// Id of the cimsession.26 /// </summary>27 public uint SessionId { get; }28 29 /// <summary>30 /// InstanceId of the cimsession.31 /// </summary>32 public Guid InstanceId { get; }33 34 /// <summary>35 /// Name of the cimsession.36 /// </summary>37 public string Name { get; }38 39 /// <summary>40 /// Computer name of the cimsession.41 /// </summary>42 public string ComputerName { get; }43 44 /// <summary>45 /// Wrapped cimsession object.46 /// </summary>47 public CimSession CimSession { get; }48 49 /// <summary>50 /// Computer name of the cimsession.51 /// </summary>52 public string Protocol53 {54 get55 {56 switch (protocol)57 {58 case ProtocolType.Dcom:59 return "DCOM";60 case ProtocolType.Default:61 case ProtocolType.Wsman:62 default:63 return "WSMAN";64 }65 }66 }67 68 internal ProtocolType GetProtocolType()69 {70 return protocol;71 }72 73 private readonly ProtocolType protocol;74 75 /// <summary>76 /// PSObject that wrapped the cimSession.77 /// </summary>78 private PSObject psObject;79 80 #endregion81 82 internal CimSessionWrapper(83 uint theSessionId,84 Guid theInstanceId,85 string theName,86 string theComputerName,87 CimSession theCimSession,88 ProtocolType theProtocol)89 {90 this.SessionId = theSessionId;91 this.InstanceId = theInstanceId;92 this.Name = theName;93 this.ComputerName = theComputerName;94 this.CimSession = theCimSession;95 this.psObject = null;96 this.protocol = theProtocol;97 }98 99 internal PSObject GetPSObject()100 {101 if (psObject == null)102 {103 psObject = new PSObject(this.CimSession);104 psObject.Properties.Add(new PSNoteProperty(CimSessionState.idPropName, this.SessionId));105 psObject.Properties.Add(new PSNoteProperty(CimSessionState.namePropName, this.Name));106 psObject.Properties.Add(new PSNoteProperty(CimSessionState.instanceidPropName, this.InstanceId));107 psObject.Properties.Add(new PSNoteProperty(CimSessionState.computernamePropName, this.ComputerName));108 psObject.Properties.Add(new PSNoteProperty(CimSessionState.protocolPropName, this.Protocol));109 }110 else111 {112 psObject.Properties[CimSessionState.idPropName].Value = this.SessionId;113 psObject.Properties[CimSessionState.namePropName].Value = this.Name;114 psObject.Properties[CimSessionState.instanceidPropName].Value = this.InstanceId;115 psObject.Properties[CimSessionState.computernamePropName].Value = this.ComputerName;116 psObject.Properties[CimSessionState.protocolPropName].Value = this.Protocol;117 }118 119 return psObject;120 }121 }122 123 #endregion124 125 #region CimSessionState126 127 /// <summary>128 /// <para>129 /// Class used to hold all cimsession related status data related to a runspace.130 /// Including the CimSession cache, session counters for generating session name.131 /// </para>132 /// </summary>133 internal class CimSessionState : IDisposable134 {135 #region private members136 137 /// <summary>138 /// Default session name.139 /// If a name is not passed, then the session is given the name CimSession<int>,140 /// where <int> is the next available session number.141 /// For example, CimSession1, CimSession2, etc...142 /// </summary>143 internal static readonly string CimSessionClassName = "CimSession";144 145 /// <summary>146 /// CimSession object name.147 /// </summary>148 internal static readonly string CimSessionObject = "{CimSession Object}";149 150 /// <summary>151 /// <para>152 /// CimSession object path, which is identifying a cimsession object153 /// </para>154 /// </summary>155 internal static readonly string SessionObjectPath = @"CimSession id = {0}, name = {2}, ComputerName = {3}, instance id = {1}";156 157 /// <summary>158 /// Id property name of cimsession wrapper object.159 /// </summary>160 internal static readonly string idPropName = "Id";161 162 /// <summary>163 /// Instanceid property name of cimsession wrapper object.164 /// </summary>165 internal static readonly string instanceidPropName = "InstanceId";166 167 /// <summary>168 /// Name property name of cimsession wrapper object.169 /// </summary>170 internal static readonly string namePropName = "Name";171 172 /// <summary>173 /// Computer name property name of cimsession object.174 /// </summary>175 internal static readonly string computernamePropName = "ComputerName";176 177 /// <summary>178 /// Protocol name property name of cimsession object.179 /// </summary>180 internal static readonly string protocolPropName = "Protocol";181 182 /// <summary>183 /// <para>184 /// Session counter bound to current runspace.185 /// </para>186 /// </summary>187 private uint sessionNameCounter;188 189 /// <summary>190 /// <para>191 /// Dictionary used to holds all CimSessions in current runspace by session name.192 /// </para>193 /// </summary>194 private readonly Dictionary<string, HashSet<CimSessionWrapper>> curCimSessionsByName;195 196 /// <summary>197 /// <para>198 /// Dictionary used to holds all CimSessions in current runspace by computer name.199 /// </para>200 /// </summary>201 private readonly Dictionary<string, HashSet<CimSessionWrapper>> curCimSessionsByComputerName;202 203 /// <summary>204 /// <para>205 /// Dictionary used to holds all CimSessions in current runspace by instance ID.206 /// </para>207 /// </summary>208 private readonly Dictionary<Guid, CimSessionWrapper> curCimSessionsByInstanceId;209 210 /// <summary>211 /// <para>212 /// Dictionary used to holds all CimSessions in current runspace by session id.213 /// </para>214 /// </summary>215 private readonly Dictionary<uint, CimSessionWrapper> curCimSessionsById;216 217 /// <summary>218 /// <para>219 /// Dictionary used to link CimSession object with PSObject.220 /// </para>221 /// </summary>222 private readonly Dictionary<CimSession, CimSessionWrapper> curCimSessionWrapper;223 224 #endregion225 226 /// <summary>227 /// Initializes a new instance of the <see cref="CimSessionState"/> class.228 /// </summary>229 internal CimSessionState()230 {231 sessionNameCounter = 1;232 curCimSessionsByName = new Dictionary<string, HashSet<CimSessionWrapper>>(233 StringComparer.OrdinalIgnoreCase);234 curCimSessionsByComputerName = new Dictionary<string, HashSet<CimSessionWrapper>>(235 StringComparer.OrdinalIgnoreCase);236 curCimSessionsByInstanceId = new Dictionary<Guid, CimSessionWrapper>();237 curCimSessionsById = new Dictionary<uint, CimSessionWrapper>();238 curCimSessionWrapper = new Dictionary<CimSession, CimSessionWrapper>();239 }240 241 /// <summary>242 /// <para>243 /// Get sessions count.244 /// </para>245 /// </summary>246 /// <returns>The count of session objects in current runspace.</returns>247 internal int GetSessionsCount()248 {249 return this.curCimSessionsById.Count;250 }251 252 /// <summary>253 /// <para>254 /// Generates an unique session id.255 /// </para>256 /// </summary>257 /// <returns>Unique session id under current runspace.</returns>258 internal uint GenerateSessionId()259 {260 return this.sessionNameCounter++;261 }262 #region IDisposable263 264 /// <summary>265 /// <para>266 /// Indicates whether this object was disposed or not.267 /// </para>268 /// </summary>269 private bool _disposed;270 271 /// <summary>272 /// <para>273 /// Dispose() calls Dispose(true).274 /// Implement IDisposable. Do not make this method virtual.275 /// A derived class should not be able to override this method.276 /// </para>277 /// </summary>278 public void Dispose()279 {280 Dispose(true);281 // This object will be cleaned up by the Dispose method.282 // Therefore, you should call GC.SuppressFinalize to283 // take this object off the finalization queue284 // and prevent finalization code for this object285 // from executing a second time.286 GC.SuppressFinalize(this);287 }288 289 /// <summary>290 /// <para>291 /// Dispose(bool disposing) executes in two distinct scenarios.292 /// If disposing equals true, the method has been called directly293 /// or indirectly by a user's code. Managed and unmanaged resources294 /// can be disposed.295 /// If disposing equals false, the method has been called by the296 /// runtime from inside the finalizer and you should not reference297 /// other objects. Only unmanaged resources can be disposed.298 /// </para>299 /// </summary>300 /// <param name="disposing">Whether it is directly called.</param>301 protected virtual void Dispose(bool disposing)302 {303 if (!this._disposed)304 {305 if (disposing)306 {307 // free managed resources308 Cleanup();309 this._disposed = true;310 }311 // free native resources if there are any312 }313 }314 315 /// <summary>316 /// <para>317 /// Performs application-defined tasks associated with freeing, releasing, or318 /// resetting unmanaged resources.319 /// </para>320 /// </summary>321 public void Cleanup()322 {323 foreach (CimSession session in curCimSessionWrapper.Keys)324 {325 session.Dispose();326 }327 328 curCimSessionWrapper.Clear();329 curCimSessionsByName.Clear();330 curCimSessionsByComputerName.Clear();331 curCimSessionsByInstanceId.Clear();332 curCimSessionsById.Clear();333 sessionNameCounter = 1;334 }335 336 #endregion337 338 #region Add CimSession to/remove CimSession from cache339 340 /// <summary>341 /// <para>342 /// Add new CimSession object to cache.343 /// </para>344 /// </summary>345 /// <param name="session"></param>346 /// <param name="sessionId"></param>347 /// <param name="instanceId"></param>348 /// <param name="name"></param>349 /// <param name="computerName"></param>350 /// <param name="protocol"></param>351 /// <returns></returns>352 internal PSObject AddObjectToCache(353 CimSession session,354 uint sessionId,355 Guid instanceId,356 string name,357 string computerName,358 ProtocolType protocol)359 {360 CimSessionWrapper wrapper = new(361 sessionId, instanceId, name, computerName, session, protocol);362 363 HashSet<CimSessionWrapper> objects;364 if (!this.curCimSessionsByComputerName.TryGetValue(computerName, out objects))365 {366 objects = new HashSet<CimSessionWrapper>();367 this.curCimSessionsByComputerName.Add(computerName, objects);368 }369 370 objects.Add(wrapper);371 372 if (!this.curCimSessionsByName.TryGetValue(name, out objects))373 {374 objects = new HashSet<CimSessionWrapper>();375 this.curCimSessionsByName.Add(name, objects);376 }377 378 objects.Add(wrapper);379 380 this.curCimSessionsByInstanceId.Add(instanceId, wrapper);381 this.curCimSessionsById.Add(sessionId, wrapper);382 this.curCimSessionWrapper.Add(session, wrapper);383 return wrapper.GetPSObject();384 }385 386 /// <summary>387 /// <para>388 /// Generates remove session message by given wrapper object.389 /// </para>390 /// </summary>391 /// <param name="psObject"></param>392 internal string GetRemoveSessionObjectTarget(PSObject psObject)393 {394 string message = string.Empty;395 if (psObject.BaseObject is CimSession)396 {397 uint id = 0x0;398 Guid instanceId = Guid.Empty;399 string name = string.Empty;400 string computerName = string.Empty;401 if (psObject.Properties[idPropName].Value is uint)402 {403 id = Convert.ToUInt32(psObject.Properties[idPropName].Value, null);404 }405 406 if (psObject.Properties[instanceidPropName].Value is Guid)407 {408 instanceId = (Guid)psObject.Properties[instanceidPropName].Value;409 }410 411 if (psObject.Properties[namePropName].Value is string)412 {413 name = (string)psObject.Properties[namePropName].Value;414 }415 416 if (psObject.Properties[computernamePropName].Value is string)417 {418 computerName = (string)psObject.Properties[computernamePropName].Value;419 }420 421 message = string.Format(CultureInfo.CurrentUICulture, SessionObjectPath, id, instanceId, name, computerName);422 }423 424 return message;425 }426 427 /// <summary>428 /// <para>429 /// Remove given <see cref="PSObject"/> object from cache.430 /// </para>431 /// </summary>432 /// <param name="psObject"></param>433 internal void RemoveOneSessionObjectFromCache(PSObject psObject)434 {435 DebugHelper.WriteLogEx();436 437 if (psObject.BaseObject is CimSession)438 {439 RemoveOneSessionObjectFromCache(psObject.BaseObject as CimSession);440 }441 }442 443 /// <summary>444 /// <para>445 /// Remove given <see cref="CimSession"/> object from cache.446 /// </para>447 /// </summary>448 /// <param name="session"></param>449 internal void RemoveOneSessionObjectFromCache(CimSession session)450 {451 DebugHelper.WriteLogEx();452 453 if (!this.curCimSessionWrapper.ContainsKey(session))454 {455 return;456 }457 458 CimSessionWrapper wrapper = this.curCimSessionWrapper[session];459 string name = wrapper.Name;460 string computerName = wrapper.ComputerName;461 462 DebugHelper.WriteLog("name {0}, computername {1}, id {2}, instanceId {3}", 1, name, computerName, wrapper.SessionId, wrapper.InstanceId);463 464 HashSet<CimSessionWrapper> objects;465 if (this.curCimSessionsByComputerName.TryGetValue(computerName, out objects))466 {467 objects.Remove(wrapper);468 }469 470 if (this.curCimSessionsByName.TryGetValue(name, out objects))471 {472 objects.Remove(wrapper);473 }474 475 RemoveSessionInternal(session, wrapper);476 }477 478 /// <summary>479 /// <para>480 /// Remove given <see cref="CimSession"/> object from partial of the cache only.481 /// </para>482 /// </summary>483 /// <param name="session"></param>484 /// <param name="psObject"></param>485 private void RemoveSessionInternal(CimSession session, CimSessionWrapper wrapper)486 {487 DebugHelper.WriteLogEx();488 489 this.curCimSessionsByInstanceId.Remove(wrapper.InstanceId);490 this.curCimSessionsById.Remove(wrapper.SessionId);491 this.curCimSessionWrapper.Remove(session);492 session.Dispose();493 }494 495 #endregion496 497 #region Query CimSession from cache498 499 /// <summary>500 /// <para>501 /// Add ErrorRecord to list.502 /// </para>503 /// </summary>504 /// <param name="errRecords"></param>505 /// <param name="propertyName"></param>506 /// <param name="propertyValue"></param>507 private static void AddErrorRecord(508 ref List<ErrorRecord> errRecords,509 string propertyName,510 object propertyValue)511 {512 errRecords.Add(513 new ErrorRecord(514 new CimException(string.Format(CultureInfo.CurrentUICulture, CimCmdletStrings.CouldNotFindCimsessionObject, propertyName, propertyValue)),515 string.Empty,516 ErrorCategory.ObjectNotFound,517 null));518 }519 520 /// <summary>521 /// Query session list by given id array.522 /// </summary>523 /// <param name="ids"></param>524 /// <returns>List of session wrapper objects.</returns>525 internal IEnumerable<PSObject> QuerySession(526 IEnumerable<uint> ids,527 out IEnumerable<ErrorRecord> errorRecords)528 {529 HashSet<PSObject> sessions = new();530 HashSet<uint> sessionIds = new();531 List<ErrorRecord> errRecords = new();532 errorRecords = errRecords;533 // NOTES: use template function to implement this will save duplicate code534 foreach (uint id in ids)535 {536 if (this.curCimSessionsById.ContainsKey(id))537 {538 if (sessionIds.Add(id))539 {540 sessions.Add(this.curCimSessionsById[id].GetPSObject());541 }542 }543 else544 {545 AddErrorRecord(ref errRecords, idPropName, id);546 }547 }548 549 return sessions;550 }551 552 /// <summary>553 /// Query session list by given instance id array.554 /// </summary>555 /// <param name="instanceIds"></param>556 /// <returns>List of session wrapper objects.</returns>557 internal IEnumerable<PSObject> QuerySession(558 IEnumerable<Guid> instanceIds,559 out IEnumerable<ErrorRecord> errorRecords)560 {561 HashSet<PSObject> sessions = new();562 HashSet<uint> sessionIds = new();563 List<ErrorRecord> errRecords = new();564 errorRecords = errRecords;565 foreach (Guid instanceid in instanceIds)566 {567 if (this.curCimSessionsByInstanceId.ContainsKey(instanceid))568 {569 CimSessionWrapper wrapper = this.curCimSessionsByInstanceId[instanceid];570 if (!sessionIds.Contains(wrapper.SessionId))571 {572 sessionIds.Add(wrapper.SessionId);573 sessions.Add(wrapper.GetPSObject());574 }575 }576 else577 {578 AddErrorRecord(ref errRecords, instanceidPropName, instanceid);579 }580 }581 582 return sessions;583 }584 585 /// <summary>586 /// Query session list by given name array.587 /// </summary>588 /// <param name="nameArray"></param>589 /// <returns>List of session wrapper objects.</returns>590 internal IEnumerable<PSObject> QuerySession(IEnumerable<string> nameArray,591 out IEnumerable<ErrorRecord> errorRecords)592 {593 HashSet<PSObject> sessions = new();594 HashSet<uint> sessionIds = new();595 List<ErrorRecord> errRecords = new();596 errorRecords = errRecords;597 foreach (string name in nameArray)598 {599 bool foundSession = false;600 WildcardPattern pattern = new(name, WildcardOptions.IgnoreCase);601 foreach (KeyValuePair<string, HashSet<CimSessionWrapper>> kvp in this.curCimSessionsByName)602 {603 if (pattern.IsMatch(kvp.Key))604 {605 HashSet<CimSessionWrapper> wrappers = kvp.Value;606 foundSession = wrappers.Count > 0;607 foreach (CimSessionWrapper wrapper in wrappers)608 {609 if (!sessionIds.Contains(wrapper.SessionId))610 {611 sessionIds.Add(wrapper.SessionId);612 sessions.Add(wrapper.GetPSObject());613 }614 }615 }616 }617 618 if (!foundSession && !WildcardPattern.ContainsWildcardCharacters(name))619 {620 AddErrorRecord(ref errRecords, namePropName, name);621 }622 }623 624 return sessions;625 }626 627 /// <summary>628 /// Query session list by given computer name array.629 /// </summary>630 /// <param name="computernameArray"></param>631 /// <returns>List of session wrapper objects.</returns>632 internal IEnumerable<PSObject> QuerySessionByComputerName(633 IEnumerable<string> computernameArray,634 out IEnumerable<ErrorRecord> errorRecords)635 {636 HashSet<PSObject> sessions = new();637 HashSet<uint> sessionIds = new();638 List<ErrorRecord> errRecords = new();639 errorRecords = errRecords;640 foreach (string computername in computernameArray)641 {642 bool foundSession = false;643 if (this.curCimSessionsByComputerName.ContainsKey(computername))644 {645 HashSet<CimSessionWrapper> wrappers = this.curCimSessionsByComputerName[computername];646 foundSession = wrappers.Count > 0;647 foreach (CimSessionWrapper wrapper in wrappers)648 {649 if (!sessionIds.Contains(wrapper.SessionId))650 {651 sessionIds.Add(wrapper.SessionId);652 sessions.Add(wrapper.GetPSObject());653 }654 }655 }656 657 if (!foundSession)658 {659 AddErrorRecord(ref errRecords, computernamePropName, computername);660 }661 }662 663 return sessions;664 }665 666 /// <summary>667 /// Query session list by given session objects array.668 /// </summary>669 /// <param name="cimsessions"></param>670 /// <returns>List of session wrapper objects.</returns>671 internal IEnumerable<PSObject> QuerySession(IEnumerable<CimSession> cimsessions,672 out IEnumerable<ErrorRecord> errorRecords)673 {674 HashSet<PSObject> sessions = new();675 HashSet<uint> sessionIds = new();676 List<ErrorRecord> errRecords = new();677 errorRecords = errRecords;678 foreach (CimSession cimsession in cimsessions)679 {680 if (this.curCimSessionWrapper.ContainsKey(cimsession))681 {682 CimSessionWrapper wrapper = this.curCimSessionWrapper[cimsession];683 if (!sessionIds.Contains(wrapper.SessionId))684 {685 sessionIds.Add(wrapper.SessionId);686 sessions.Add(wrapper.GetPSObject());687 }688 }689 else690 {691 AddErrorRecord(ref errRecords, CimSessionClassName, CimSessionObject);692 }693 }694 695 return sessions;696 }697 698 /// <summary>699 /// Query session wrapper object.700 /// </summary>701 /// <param name="cimsessions"></param>702 /// <returns>Session wrapper.</returns>703 internal CimSessionWrapper QuerySession(CimSession cimsession)704 {705 CimSessionWrapper wrapper;706 this.curCimSessionWrapper.TryGetValue(cimsession, out wrapper);707 return wrapper;708 }709 710 /// <summary>711 /// Query session object with given CimSessionInstanceID.712 /// </summary>713 /// <param name="cimSessionInstanceId"></param>714 /// <returns>CimSession object.</returns>715 internal CimSession QuerySession(Guid cimSessionInstanceId)716 {717 if (this.curCimSessionsByInstanceId.ContainsKey(cimSessionInstanceId))718 {719 CimSessionWrapper wrapper = this.curCimSessionsByInstanceId[cimSessionInstanceId];720 return wrapper.CimSession;721 }722 723 return null;724 }725 #endregion726 }727 728 #endregion729 730 #region CimSessionBase731 732 /// <summary>733 /// <para>734 /// Base class of all session operation classes.735 /// All sessions created will be held in a ConcurrentDictionary:cimSessions.736 /// It manages the lifecycle of the sessions being created for each737 /// runspace according to the state of the runspace.738 /// </para>739 /// </summary>740 internal class CimSessionBase741 {742 #region constructor743 744 /// <summary>745 /// Initializes a new instance of the <see cref="CimSessionBase"/> class.746 /// </summary>747 public CimSessionBase()748 {749 this.sessionState = cimSessions.GetOrAdd(750 CurrentRunspaceId,751 (Guid instanceId) =>752 {753 if (Runspace.DefaultRunspace != null)754 {755 Runspace.DefaultRunspace.StateChanged += DefaultRunspace_StateChanged;756 }757 758 return new CimSessionState();759 });760 }761 762 #endregion763 764 #region members765 766 /// <summary>767 /// <para>768 /// Thread safe static dictionary to store session objects associated769 /// with each runspace, which is identified by a GUID. NOTE: cmdlet770 /// can running parallelly under more than one runspace(s).771 /// </para>772 /// </summary>773 internal static readonly ConcurrentDictionary<Guid, CimSessionState> cimSessions774 = new();775 776 /// <summary>777 /// <para>778 /// Default runspace Id.779 /// </para>780 /// </summary>781 internal static readonly Guid defaultRunspaceId = Guid.Empty;782 783 /// <summary>784 /// <para>785 /// Object used to hold all CimSessions and status data bound786 /// to current runspace.787 /// </para>788 /// </summary>789 internal CimSessionState sessionState;790 791 /// <summary>792 /// Get current runspace id.793 /// </summary>794 private static Guid CurrentRunspaceId795 {796 get797 {798 if (Runspace.DefaultRunspace != null)799 {800 return Runspace.DefaultRunspace.InstanceId;801 }802 else803 {804 return CimSessionBase.defaultRunspaceId;805 }806 }807 }808 #endregion809 810 public static CimSessionState GetCimSessionState()811 {812 CimSessionState state = null;813 cimSessions.TryGetValue(CurrentRunspaceId, out state);814 return state;815 }816 817 /// <summary>818 /// <para>819 /// Clean up the dictionaries if the runspace is closed or broken.820 /// </para>821 /// </summary>822 /// <param name="sender">Runspace.</param>823 /// <param name="e">Event args.</param>824 private static void DefaultRunspace_StateChanged(object sender, RunspaceStateEventArgs e)825 {826 Runspace runspace = (Runspace)sender;827 switch (e.RunspaceStateInfo.State)828 {829 case RunspaceState.Broken:830 case RunspaceState.Closed:831 CimSessionState state;832 if (cimSessions.TryRemove(runspace.InstanceId, out state))833 {834 DebugHelper.WriteLog(string.Format(CultureInfo.CurrentUICulture, DebugHelper.runspaceStateChanged, runspace.InstanceId, e.RunspaceStateInfo.State));835 state.Dispose();836 }837 838 runspace.StateChanged -= DefaultRunspace_StateChanged;839 break;840 default:841 break;842 }843 }844 }845 846 #endregion847 848 #region CimTestConnection849 850 #endregion851 852 #region CimNewSession853 854 /// <summary>855 /// <para>856 /// <c>CimNewSession</c> is the class to create cimSession857 /// based on given <c>NewCimSessionCommand</c>.858 /// </para>859 /// </summary>860 internal class CimNewSession : CimSessionBase, IDisposable861 {862 /// <summary>863 /// CimTestCimSessionContext.864 /// </summary>865 internal class CimTestCimSessionContext : XOperationContextBase866 {867 /// <summary>868 /// Initializes a new instance of the <see cref="CimTestCimSessionContext"/> class.869 /// </summary>870 /// <param name="theProxy"></param>871 /// <param name="wrapper"></param>872 internal CimTestCimSessionContext(873 CimSessionProxy theProxy,874 CimSessionWrapper wrapper)875 {876 this.proxy = theProxy;877 this.CimSessionWrapper = wrapper;878 this.nameSpace = null;879 }880 881 /// <summary>882 /// <para>Namespace</para>883 /// </summary>884 internal CimSessionWrapper CimSessionWrapper { get; }885 }886 887 /// <summary>888 /// Initializes a new instance of the <see cref="CimNewSession"/> class.889 /// </summary>890 internal CimNewSession() : base()891 {892 this.cimTestSession = new CimTestSession();893 this.Disposed = false;894 }895 896 /// <summary>897 /// Create a new <see cref="CimSession"/> base on given cmdlet898 /// and its parameter.899 /// </summary>900 /// <param name="cmdlet"></param>901 /// <param name="sessionOptions"></param>902 /// <param name="credential"></param>903 internal void NewCimSession(NewCimSessionCommand cmdlet,904 CimSessionOptions sessionOptions,905 CimCredential credential)906 {907 DebugHelper.WriteLogEx();908 909 IEnumerable<string> computerNames = ConstValue.GetComputerNames(cmdlet.ComputerName);910 foreach (string computerName in computerNames)911 {912 CimSessionProxy proxy;913 if (sessionOptions == null)914 {915 DebugHelper.WriteLog("Create CimSessionOption due to NewCimSessionCommand has null sessionoption", 1);916 sessionOptions = CimSessionProxy.CreateCimSessionOption(computerName,917 cmdlet.OperationTimeoutSec, credential);918 }919 920 proxy = new CimSessionProxyTestConnection(computerName, sessionOptions);921 string computerNameValue = (computerName == ConstValue.NullComputerName) ? ConstValue.LocalhostComputerName : computerName;922 CimSessionWrapper wrapper = new(0, Guid.Empty, cmdlet.Name, computerNameValue, proxy.CimSession, proxy.Protocol);923 CimTestCimSessionContext context = new(proxy, wrapper);924 proxy.ContextObject = context;925 // Skip test the connection if user intend to926 if (cmdlet.SkipTestConnection.IsPresent)927 {928 AddSessionToCache(proxy.CimSession, context, new CmdletOperationBase(cmdlet));929 }930 else931 {932 // CimSession will be returned as part of TestConnection933 this.cimTestSession.TestCimSession(computerName, proxy);934 }935 }936 }937 938 /// <summary>939 /// <para>940 /// Add session to global cache,941 /// </para>942 /// </summary>943 /// <param name="cimSession"></param>944 /// <param name="context"></param>945 /// <param name="cmdlet"></param>946 internal void AddSessionToCache(CimSession cimSession, XOperationContextBase context, CmdletOperationBase cmdlet)947 {948 DebugHelper.WriteLogEx();949 950 CimTestCimSessionContext testCimSessionContext = context as CimTestCimSessionContext;951 uint sessionId = this.sessionState.GenerateSessionId();952 string originalSessionName = testCimSessionContext.CimSessionWrapper.Name;953 string sessionName = originalSessionName ?? string.Create(CultureInfo.CurrentUICulture, $"{CimSessionState.CimSessionClassName}{sessionId}");954 955 // detach CimSession from the proxy object956 CimSession createdCimSession = testCimSessionContext.Proxy.Detach();957 PSObject psObject = this.sessionState.AddObjectToCache(958 createdCimSession,959 sessionId,960 createdCimSession.InstanceId,961 sessionName,962 testCimSessionContext.CimSessionWrapper.ComputerName,963 testCimSessionContext.Proxy.Protocol);964 cmdlet.WriteObject(psObject, null);965 }966 967 /// <summary>968 /// <para>969 /// Process all actions in the action queue.970 /// </para>971 /// </summary>972 /// <param name="cmdletOperation">973 /// Wrapper of cmdlet, <seealso cref="CmdletOperationBase"/> for details.974 /// </param>975 public void ProcessActions(CmdletOperationBase cmdletOperation)976 {977 this.cimTestSession.ProcessActions(cmdletOperation);978 }979 980 /// <summary>981 /// <para>982 /// Process remaining actions until all operations are completed or983 /// current cmdlet is terminated by user.984 /// </para>985 /// </summary>986 /// <param name="cmdletOperation">987 /// Wrapper of cmdlet, <seealso cref="CmdletOperationBase"/> for details.988 /// </param>989 public void ProcessRemainActions(CmdletOperationBase cmdletOperation)990 {991 this.cimTestSession.ProcessRemainActions(cmdletOperation);992 }993 994 #region private members995 /// <summary>996 /// <para>997 /// <see cref="CimTestSession"/> object.998 /// </para>999 /// </summary>1000 private readonly CimTestSession cimTestSession;1001 #endregion // private members1002 1003 #region IDisposable1004 1005 /// <summary>1006 /// <para>1007 /// Indicates whether this object was disposed or not.1008 /// </para>1009 /// </summary>1010 protected bool Disposed { get; private set; }1011 1012 /// <summary>1013 /// <para>1014 /// Dispose() calls Dispose(true).1015 /// Implement IDisposable. Do not make this method virtual.1016 /// A derived class should not be able to override this method.1017 /// </para>1018 /// </summary>1019 public void Dispose()1020 {1021 Dispose(true);1022 // This object will be cleaned up by the Dispose method.1023 // Therefore, you should call GC.SuppressFinalize to1024 // take this object off the finalization queue1025 // and prevent finalization code for this object1026 // from executing a second time.1027 GC.SuppressFinalize(this);1028 }1029 1030 /// <summary>1031 /// <para>1032 /// Dispose(bool disposing) executes in two distinct scenarios.1033 /// If disposing equals true, the method has been called directly1034 /// or indirectly by a user's code. Managed and unmanaged resources1035 /// can be disposed.1036 /// If disposing equals false, the method has been called by the1037 /// runtime from inside the finalizer and you should not reference1038 /// other objects. Only unmanaged resources can be disposed.1039 /// </para>1040 /// </summary>1041 /// <param name="disposing">Whether it is directly called.</param>1042 protected virtual void Dispose(bool disposing)1043 {1044 if (!this.Disposed)1045 {1046 if (disposing)1047 {1048 // free managed resources1049 this.cimTestSession.Dispose();1050 this.Disposed = true;1051 }1052 // free native resources if there are any1053 }1054 }1055 #endregion1056 }1057 1058 #endregion1059 1060 #region CimGetSession1061 1062 /// <summary>1063 /// <para>1064 /// Get CimSession based on given id/instanceid/computername/name.1065 /// </para>1066 /// </summary>1067 internal class CimGetSession : CimSessionBase1068 {1069 /// <summary>1070 /// Initializes a new instance of the <see cref="CimGetSession"/> class.1071 /// </summary>1072 public CimGetSession() : base()1073 {1074 }1075 1076 /// <summary>1077 /// Get <see cref="CimSession"/> objects based on the given cmdlet1078 /// and its parameter.1079 /// </summary>1080 /// <param name="cmdlet"></param>1081 public void GetCimSession(GetCimSessionCommand cmdlet)1082 {1083 DebugHelper.WriteLogEx();1084 1085 IEnumerable<PSObject> sessionToGet = null;1086 IEnumerable<ErrorRecord> errorRecords = null;1087 switch (cmdlet.ParameterSetName)1088 {1089 case CimBaseCommand.ComputerNameSet:1090 if (cmdlet.ComputerName == null)1091 {1092 sessionToGet = this.sessionState.QuerySession(ConstValue.DefaultSessionName, out errorRecords);1093 }1094 else1095 {1096 sessionToGet = this.sessionState.QuerySessionByComputerName(cmdlet.ComputerName, out errorRecords);1097 }1098 1099 break;1100 case CimBaseCommand.SessionIdSet:1101 sessionToGet = this.sessionState.QuerySession(cmdlet.Id, out errorRecords);1102 break;1103 case CimBaseCommand.InstanceIdSet:1104 sessionToGet = this.sessionState.QuerySession(cmdlet.InstanceId, out errorRecords);1105 break;1106 case CimBaseCommand.NameSet:1107 sessionToGet = this.sessionState.QuerySession(cmdlet.Name, out errorRecords);1108 break;1109 default:1110 break;1111 }1112 1113 if (sessionToGet != null)1114 {1115 foreach (PSObject psobject in sessionToGet)1116 {1117 cmdlet.WriteObject(psobject);1118 }1119 }1120 1121 if (errorRecords != null)1122 {1123 foreach (ErrorRecord errRecord in errorRecords)1124 {1125 cmdlet.WriteError(errRecord);1126 }1127 }1128 }1129 1130 #region helper methods1131 1132 #endregion1133 }1134 1135 #endregion1136 1137 #region CimRemoveSession1138 1139 /// <summary>1140 /// <para>1141 /// Get CimSession based on given id/instanceid/computername/name.1142 /// </para>1143 /// </summary>1144 internal class CimRemoveSession : CimSessionBase1145 {1146 /// <summary>1147 /// Remove session action string.1148 /// </summary>1149 internal static readonly string RemoveCimSessionActionName = "Remove CimSession";1150 1151 /// <summary>1152 /// Initializes a new instance of the <see cref="CimRemoveSession"/> class.1153 /// </summary>1154 public CimRemoveSession() : base()1155 {1156 }1157 1158 /// <summary>1159 /// Remove the <see cref="CimSession"/> objects based on given cmdlet1160 /// and its parameter.1161 /// </summary>1162 /// <param name="cmdlet"></param>1163 public void RemoveCimSession(RemoveCimSessionCommand cmdlet)1164 {1165 DebugHelper.WriteLogEx();1166 1167 IEnumerable<PSObject> sessionToRemove = null;1168 IEnumerable<ErrorRecord> errorRecords = null;1169 switch (cmdlet.ParameterSetName)1170 {1171 case CimBaseCommand.CimSessionSet:1172 sessionToRemove = this.sessionState.QuerySession(cmdlet.CimSession, out errorRecords);1173 break;1174 case CimBaseCommand.ComputerNameSet:1175 sessionToRemove = this.sessionState.QuerySessionByComputerName(cmdlet.ComputerName, out errorRecords);1176 break;1177 case CimBaseCommand.SessionIdSet:1178 sessionToRemove = this.sessionState.QuerySession(cmdlet.Id, out errorRecords);1179 break;1180 case CimBaseCommand.InstanceIdSet:1181 sessionToRemove = this.sessionState.QuerySession(cmdlet.InstanceId, out errorRecords);1182 break;1183 case CimBaseCommand.NameSet:1184 sessionToRemove = this.sessionState.QuerySession(cmdlet.Name, out errorRecords);1185 break;1186 default:1187 break;1188 }1189 1190 if (sessionToRemove != null)1191 {1192 foreach (PSObject psobject in sessionToRemove)1193 {1194 if (cmdlet.ShouldProcess(this.sessionState.GetRemoveSessionObjectTarget(psobject), RemoveCimSessionActionName))1195 {1196 this.sessionState.RemoveOneSessionObjectFromCache(psobject);1197 }1198 }1199 }1200 