Way to invoke a scriptblock with named parameters from C#
See original GitHub issueSummary of the new feature/enhancement
Say I have a scriptblock like this:
{
param(
$a,
$b
)
"a: $a"
"b: $b"
}
And I want to invoke it from C#:
var sb = ScriptBlock.Create("...");
var parameters = new Hashtable
{
{ "a", "A" },
{ "b", "B" },
};
sb.Invoke(?);
InvokeCommand.InvokeScript(sb, ?);
using (var pwsh = PowerShell.Create())
{
pwsh.<?>.AddParameters(parameters).Invoke();
}
Is there a way to do this currently in PowerShell, and if not can we have one?
The best way I’ve found to do this so far is to use reflection to create a FunctionInfo
object around the scriptblock for invocation:
var sb = ScriptBlock.Create("param($a, $b) \"a: $a\",\"b: $b\"");
var runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
PropertyInfo runspaceExecutionContextProperty = typeof(Runspace).GetProperty("ExecutionContext", BindingFlags.Instance | BindingFlags.NonPublic);
Type ecType = runspaceExecutionContextProperty.PropertyType;
ConstructorInfo funcInfoCtor = typeof(FunctionInfo).GetConstructor(
BindingFlags.NonPublic | BindingFlags.Instance,
binder: null,
new[] { typeof(string), typeof(ScriptBlock), ecType },
modifiers: null);
object executionContext = runspaceExecutionContextProperty.GetValue(runspace);
var sbFuncInfo = (FunctionInfo)funcInfoCtor.Invoke(new object[] { string.Empty, sb, executionContext });
using (var pwsh = PowerShell.Create())
{
pwsh.AddCommand(sbFuncInfo).AddParameters(new Dictionary<string, object>{ {"a", "A"}, {"b", "B"} });
foreach (PSObject result in pwsh.Invoke())
{
Console.WriteLine(result);
}
}
But this is very involved, messy, requires overhead and isn’t public/officially supported.
Proposed technical implementation details (optional)
Some considerations:
- While the
PowerShell
API is a good place for this, it doesn’t currently have good support for scriptblocks (something which could be improved) - Other APIs do support scriptblocks well, such as
CommandInvocationIntrinsics.InvokeScript
andScriptBlock.Invoke[WithContext]
and it would be nice to extend those to enable named parameter passing since they allow simpler control of the execution context than thePowerShell
API
Issue Analytics
- State:
- Created 3 years ago
- Reactions:2
- Comments:12 (5 by maintainers)
Top Results From Across the Web
PowerShell Pass Named parameters to ArgumentList
Use a script block to run the file, instead of the using -FilePath. Invoke-Command -ComputerName server -ScriptBlock {& " ...
Read more >about Script Blocks - PowerShell
Like functions, a script block can include parameters. Use the Param keyword to assign named parameters, as shown in the following syntax:.
Read more >Invoke-Command (Microsoft.PowerShell.Core)
Invoke -Command uses the ScriptBlock parameter that defines two variables, $param1 and $param2 . Get-ChildItem uses the named parameters, Name and Include with ......
Read more >Passing named parameter when using invoke command
Passing named parameter when using invoke command ... $servers = Get-Content ('servers.txt') $path = 'c:\temp' foreach ($server in $servers) ...
Read more >How to pass arguments in Invoke-Command in PowerShell
To pass the argument in the Invoke-command, you need to use -ArgumentList parameter. For example, we need to get the notepad process ...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
I believe
AddParameters()
does that.My primary reason is not wanting to rebuild a scriptblock. In my scenario, I’m taking in a user-provided scriptblock in a cmdlet and I want to execute it providing a set of parameters to choose from. I’d like that scriptblock to keep all of its context and metadata and not have the overhead of stringifying it just for PowerShell to construct a new one. That way, if something goes wrong in the execution, the error message makes sense to users.
It may not matter in every use case, but it’s worth noting that the
Invoke*
methods have a lot of limitations (like end block only, very limited$MyInvocation
, no error stream) and aren’t very performant.