Skip to content

Commit 4e66976

Browse files
author
Friedrich Weinmann
committed
Adding initialization logic
1 parent dd58092 commit 4e66976

7 files changed

Lines changed: 111 additions & 5 deletions

File tree

PSFramework/internal/scripts/environment.ps1

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,7 @@ if (($PSVersionTable.PSVersion.Major -ge 6) -and ($PSVersionTable.OS -notlike "*
8787

8888
if (-not ([PSFramework.Message.LogHost]::LoggingPath)) { [PSFramework.Message.LogHost]::LoggingPath = $script:path_Logging }
8989

90-
[PSFramework.PSFCore.PSFCoreHost]::ModuleRoot = $script:ModuleRoot
90+
[PSFramework.PSFCore.PSFCoreHost]::ModuleRoot = $script:ModuleRoot
91+
# Run the library initialization logic
92+
# Needed before the configuration system loads
93+
[PSFramework.PSFCore.PSFCoreHost]::Initialize()

PSFramework/internal/scripts/removalEvent.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ $PSF_OnRemoveScript = {
44
if ([runspace]::DefaultRunspace.Id -eq 1)
55
{
66
Get-PSFRunspace | Stop-PSFRunspace
7+
[PSFramework.PSFCore.PSFCoreHost]::Uninitialize()
78
}
89

910
# Properly disconnect all remote sessions still held open

PSFramework/internal/tepp/scripts/input.ps1

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,17 @@
1919
if ($pipelineAst.PipelineElements[$inputIndex].CommandElements)
2020
{
2121
# Resolve command and fail if it breaks
22-
$command = Get-Command $pipelineAst.PipelineElements[$inputIndex].CommandElements[0].Value -ErrorAction Ignore
22+
$commandString = $pipelineAst.PipelineElements[$inputIndex].CommandElements[0].Value
23+
if ($commandString -eq "?") { $commandString = (Get-Alias -Name "?").ResolvedCommand.Name }
24+
$command = Get-Command $commandString -ErrorAction Ignore
2325
if ($command -is [System.Management.Automation.AliasInfo]) { $command = $command.ResolvedCommand }
2426
if (-not $command) { break }
2527

2628
switch ($command.Name)
2729
{
2830
'Where-Object' { $inputIndex = $inputIndex - 1; continue main }
2931
'Tee-Object' { $inputIndex = $inputIndex - 1; continue main }
32+
'Sort-Object' { $inputIndex = $inputIndex - 1; continue main }
3033
#region Select-Object
3134
'Select-Object'
3235
{

library/PSFramework/PSFCore/PSFCoreHost.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,33 @@ public static string ModuleRoot
2929
}
3030
}
3131
private static string _ModuleRoot;
32+
33+
/// <summary>
34+
/// Initializes the PSFramework library.
35+
/// Required for some components to work correctly.
36+
/// </summary>
37+
public static void Initialize()
38+
{
39+
if (_Initialized)
40+
return;
41+
_Initialized = true;
42+
43+
// Initialization logic goes here
44+
}
45+
private static bool _Initialized = false;
46+
47+
/// <summary>
48+
/// Reverses the initialization of the PSFramework library.
49+
/// Should be called when destroying the main runspace
50+
/// </summary>
51+
public static void Uninitialize()
52+
{
53+
if (!_Initialized)
54+
return;
55+
56+
// De-Initiialization logic goes here
57+
58+
_Initialized = false;
59+
}
3260
}
3361
}

library/PSFramework/Runspace/RunspaceBoundValue.cs

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System;
1+
using PSFramework.Utility;
2+
using System;
23
using System.Collections.Generic;
34
using System.Linq;
45
using System.Management.Automation.Runspaces;
@@ -10,7 +11,7 @@ namespace PSFramework.Runspace
1011
/// <summary>
1112
/// Wrapper class that offers the tools to make Values runspace specific
1213
/// </summary>
13-
public class RunspaceBoundValue
14+
public class RunspaceBoundValue : IDisposable
1415
{
1516
/// <summary>
1617
/// Whether the defautl value should be offered when asking from a runspace without custom settings
@@ -49,9 +50,63 @@ public object Value
4950
}
5051
}
5152

53+
/// <summary>
54+
/// Removes all value entries whose corresponding Runspace has been destroyed
55+
/// </summary>
5256
public void PurgeExpired()
5357
{
54-
System.Management.Automation.Runspaces.Runspace.GetRunspaces(null);
58+
// Store IDs first, so parallel access is not an issue and a new value gets accidentally discarded
59+
Guid[] IDs = Values.Keys.ToArray();
60+
ICollection<System.Management.Automation.Runspaces.Runspace> runspaces = UtilityHost.GetRunspaces();
61+
ICollection<Guid> runspaceIDs = (ICollection<Guid>)runspaces.Select(o => o.InstanceId);
62+
63+
foreach (Guid ID in IDs)
64+
if (!runspaceIDs.Contains(ID))
65+
Values.Remove(ID);
66+
}
67+
68+
/// <summary>
69+
/// Destruction logic, eliminating all data stored in the object.
70+
/// Since handles to this object are automatically stored and maintained, it is impossible to otherwise guarantee releasing the object's data for the GC.
71+
/// </summary>
72+
public void Dispose()
73+
{
74+
Values = new Dictionary<Guid, object>();
75+
DefaultValue = null;
76+
RunspaceHost._RunspaceBoundValues.Remove(this);
77+
}
78+
79+
/// <summary>
80+
/// Create an empty runspace bound value object
81+
/// </summary>
82+
public RunspaceBoundValue()
83+
: this(null, true)
84+
{
85+
86+
}
87+
88+
/// <summary>
89+
/// Create a runspace bound value object with its initial value
90+
/// </summary>
91+
/// <param name="Value">The object to set as the initial value</param>
92+
public RunspaceBoundValue(object Value)
93+
: this(Value, true)
94+
{
95+
96+
}
97+
98+
/// <summary>
99+
/// Create a runspace bound value object with its initial value
100+
/// </summary>
101+
/// <param name="Value">The object to set as the initial value</param>
102+
/// <param name="OfferDefaultValue">Whether the initial / default value should be offered when accessed from runspaces that do not have a runspace-local value</param>
103+
public RunspaceBoundValue(object Value, bool OfferDefaultValue)
104+
{
105+
this.Value = Value;
106+
this.OfferDefaultValue = OfferDefaultValue;
107+
108+
// Add to central list of runspacebound values
109+
RunspaceHost._RunspaceBoundValues.Add(this);
55110
}
56111
}
57112
}

library/PSFramework/Runspace/RunspaceHost.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,10 @@ public static class RunspaceHost
1616
/// The dictionary containing the definitive list of unique Runspace
1717
/// </summary>
1818
public static Dictionary<string, RunspaceContainer> Runspaces = new Dictionary<string, RunspaceContainer>();
19+
20+
/// <summary>
21+
/// List of all runspace bound values in use
22+
/// </summary>
23+
internal static List<RunspaceBoundValue> _RunspaceBoundValues = new List<RunspaceBoundValue>();
1924
}
2025
}

library/PSFramework/Utility/UtilityHost.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,17 @@ public static object GetExecutionContextFromTLS()
235235
return method.Invoke(null, BindingFlags.NonPublic | BindingFlags.Static, null, null, System.Globalization.CultureInfo.CurrentCulture);
236236
}
237237

238+
/// <summary>
239+
/// Returns the list of runspaces available in the process
240+
/// </summary>
241+
/// <returns>The lists of currently known runspaces</returns>
242+
public static ICollection<System.Management.Automation.Runspaces.Runspace> GetRunspaces()
243+
{
244+
Type runspaceType = typeof(System.Management.Automation.Runspaces.Runspace);
245+
MethodInfo method = runspaceType.GetMethod("get_RunspaceList", BindingFlags.Static | BindingFlags.NonPublic);
246+
return (ICollection < System.Management.Automation.Runspaces.Runspace > )method.Invoke(null, null);
247+
}
248+
238249
/// <summary>
239250
/// Removes an alias from the global list of aliases
240251
/// </summary>

0 commit comments

Comments
 (0)