Reputation: 3246
I am attempting to write a cmdlet based PowerShell module for an application we have. After the initial connection cmdlet, I want to store values somewhere while the user has their current PowerShell window open. One of the values is an auth key that I create from the user's credentials and then is required for future calls, without providing credentials for every action.
I thought it might be easy to get and set these in a custom object from C#, but I am struggling to get it to apply to the current runspace. I will admit, that I am pretty new to C# too.
Here is an example of my most successful attempt in a minimal form i.e. this will evaluate as true, however, it's not the same runspace. If I call $item in PowerShell, it obviously doesn't know what I am going on about.
using System.Management.Automation.Runspaces;
namespace Test
{
public class VariableTest
{
public bool CreateVariable()
{
var runSpace = RunspaceFactory.CreateRunspace();
runSpace.Open();
runSpace.SessionStateProxy.SetVariable("item", "FooBar");
var a = runSpace.SessionStateProxy.PSVariable.GetValue("item");
if (a.ToString() == "FooBar")
{
return true;
}
else
{
return false;
}
}
}
}
If I was writing this module in PowerShell, I'd probably just save them in a global variable. Can anyone help with getting and setting these values so I can call item in the PowerShell console? Or is this terribly wrong and something exists to already account for persistent module wide variables within C# that I have missed.
Upvotes: 3
Views: 2165
Reputation: 3246
Many thanks to Mathias above for his guidance on this. Here is a minimal example for anyone else who comes looking for this.
Connect cmdlet
using System.Management.Automation;
namespace Test
{
[Cmdlet(VerbsCommunications.Connect, "TestSystem")]
public class VariableTest : PSCmdlet
{
private string _item;
public string Item
{
get { return _item; }
set { _item = value; }
}
protected override void BeginProcessing()
{
base.BeginProcessing();
}
protected override void ProcessRecord()
{
Item = "FooBar";
}
protected override void EndProcessing()
{
SessionState.PSVariable.Set(new PSVariable(nameof(Item), Item, ScopedItemOptions.Private));
}
}
}
Other cmdlet
using System.Management.Automation;
namespace Test
{
[Cmdlet(VerbsCommunications.Read, "TestVariable")]
public class ReadVariable : PSCmdlet
{
protected override void BeginProcessing()
{
base.BeginProcessing();
}
protected override void ProcessRecord()
{
var test = SessionState.PSVariable.Get("Item");
WriteObject(test.Value.ToString());
}
}
}
Result
PS C:\> Connect-TestSystem
PS C:\> Read-TestVariable
FooBar
Upvotes: 1
Reputation: 174505
Assuming your Connect-*
cmdlet inherits PSCmdlet
, you can access variables through this.SessionState.PSVariable
:
[Cmdlet("Connect", "SomeSystem")]
public class ConnectCmd : PSCmdlet
{
protected override void EndProcessing()
{
SessionState.PSVariable.Set(new PSVariable("varName", valueGoesHere, ScopedItemOptions.Private));
}
}
Now, any cmdlet running in the same runspace can retrieve and read the variable:
[Cmdlet("Get", "Stuff")]
public class GetCmd : PSCmdlet
{
protected override void EndProcessing()
{
WriteObject(SessionState.PSVariable.Get("varName").Value);
}
}
Please note that the Private
option is not a visibility or scope modifier, but rather ensures that no one can overwrite the variable value.
Upvotes: 6