Advertisement
Guest User

Untitled

a guest
Apr 24th, 2019
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.30 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Management.Automation;
  4.  
  5. public class RunspaceSynchronizer
  6. {
  7. public static bool SourceActionEnabled = false;
  8. private static bool TargetActionEnabled = false;
  9.  
  10. // 'moduleCache' keeps track of all modules imported in the source Runspace.
  11. // when there is a `Import-Module -Force`, the new module object would be a
  12. // different instance with different hashcode, so we can tell if there is a
  13. // force loading of an already loaded module.
  14. private static HashSet<PSModuleInfo> moduleCache = new HashSet<PSModuleInfo>();
  15.  
  16. // 'variableCache' keeps all global scope variable names and their value type.
  17. // As long as the value type doesn't change, we don't need to update the variable
  18. // in the target Runspace, because all tab completion needs is the type information.
  19. private static Dictionary<string, Type> variableCache = new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase);
  20.  
  21. public static List<PSModuleInfo> moduleToImport = new List<PSModuleInfo>();
  22. public static List<PSVariable> variablesToSet = new List<PSVariable>();
  23.  
  24. private static EngineIntrinsics sourceEngineIntrinsics;
  25. private static EngineIntrinsics targetEngineIntrinsics;
  26.  
  27. private static object syncObj = new object();
  28. private static bool sourceEventSubscribed = false;
  29. private static bool targetEventSubscribed = false;
  30.  
  31. private static void CollectSourceRunspaceState(object sender, PSEventArgs args)
  32. {
  33. if (!SourceActionEnabled)
  34. {
  35. return;
  36. }
  37.  
  38. try
  39. {
  40. // Maybe also track the latest history item id ($h = Get-History -Count 1; $h.Id)
  41. // to make sure we do the collection only if there was actually any input.
  42.  
  43. var newOrChangedModules = new List<PSModuleInfo>();
  44. var newOrChangedVars = new List<PSVariable>();
  45.  
  46. var results = sourceEngineIntrinsics.InvokeCommand.InvokeScript("Get-Module");
  47. foreach (var res in results)
  48. {
  49. var module = (PSModuleInfo) res.BaseObject;
  50. if (moduleCache.Add(module))
  51. {
  52. newOrChangedModules.Add(module);
  53. }
  54. }
  55.  
  56. // Process variables to get those that need to be updated.
  57. // - first filter out the built-in variables.
  58. // - check against the existing variable cache, if the value type of a variable name remains the same,
  59. // then no need to update the variable.
  60. // - finally get a dictionary of new/updated variables.
  61.  
  62. if (newOrChangedModules.Count == 0 && newOrChangedVars.Count == 0)
  63. {
  64. return;
  65. }
  66.  
  67. lock (syncObj)
  68. {
  69. moduleToImport.AddRange(newOrChangedModules);
  70. variablesToSet.AddRange(newOrChangedVars);
  71. }
  72.  
  73. // Enable the action in target Runspace
  74. TargetActionEnabled = true;
  75. } catch (Exception ex) {
  76. Console.WriteLine(ex.Message);
  77. Console.WriteLine(ex.StackTrace);
  78. }
  79.  
  80. SourceActionEnabled = false;
  81. }
  82.  
  83. private static void UpdateTargetRunspaceState(object sender, PSEventArgs args)
  84. {
  85. if (!TargetActionEnabled)
  86. {
  87. return;
  88. }
  89.  
  90. List<PSModuleInfo> newOrChangedModules;
  91. List<PSVariable> newOrChangedVars;
  92.  
  93. lock (syncObj)
  94. {
  95. newOrChangedModules = new List<PSModuleInfo>(moduleToImport);
  96. newOrChangedVars = new List<PSVariable>(variablesToSet);
  97.  
  98. moduleToImport.Clear();
  99. variablesToSet.Clear();
  100. }
  101.  
  102. if (newOrChangedModules.Count > 0)
  103. {
  104. // Import the modules with -Force
  105. }
  106.  
  107. if (newOrChangedVars.Count > 0)
  108. {
  109. // Set or update the variables.
  110. }
  111.  
  112. TargetActionEnabled = false;
  113. }
  114.  
  115. public static PSEventSubscriber SubscribeOnIdleEvent(EngineIntrinsics engineIntrinsics, bool isSourceRunspace)
  116. {
  117. PSEventReceivedEventHandler handler = null;
  118. if (isSourceRunspace)
  119. {
  120. if (sourceEventSubscribed)
  121. {
  122. throw new InvalidOperationException("OnIdle even already subscribed in source Runspace.");
  123. }
  124.  
  125. // Save the engineIntrinsics from source Runspace for later use.
  126. handler = (PSEventReceivedEventHandler) CollectSourceRunspaceState;
  127. sourceEngineIntrinsics = engineIntrinsics;
  128. sourceEventSubscribed = true;
  129. }
  130. else
  131. {
  132. if (targetEventSubscribed)
  133. {
  134. throw new InvalidOperationException("OnIdle even already subscribed in target Runspace.");
  135. }
  136.  
  137. // Save the engineIntrinsics from target Runspace for later use.
  138. handler = (PSEventReceivedEventHandler) UpdateTargetRunspaceState;
  139. targetEngineIntrinsics = engineIntrinsics;
  140. targetEventSubscribed = true;
  141. }
  142.  
  143. return engineIntrinsics.Events.SubscribeEvent(
  144. source: null,
  145. eventName: null,
  146. sourceIdentifier: PSEngineEvent.OnIdle.ToString(),
  147. data: null,
  148. handlerDelegate: handler,
  149. supportEvent: true,
  150. forwardEvent: false);
  151. }
  152. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement