Home > Mobile >  Dynamically create functions from hashtable with parameters in PowerShell
Dynamically create functions from hashtable with parameters in PowerShell

Time:08-14

Question

Hi, I'd like to dynamically create functions from a hashtable in Powershell. But the created functions are supposed to be able to receive parameters.

The Code I have so far:

$functions = @{
    "wu" = "winget upgrade --include-unknown";
    "wui" = "winget upgrade -i -e";
    "wi" = "winget install -i";
    "wii" = "winget install -i -e";
    "ws" = "winget search"
}

foreach($funcName in $functions.PSBase.Keys){
    New-Item function:\ -Name $funcName -Value $([scriptblock]::Create($functions[$funcName])) | Out-Null
}

The problem is, that whatever I type behind the function is not considered a parameter: enter image description here

Can you help me out?

CodePudding user response:

Here is a possible solution:

$functions = @{
    ws = { winget search $args }
    # ... and so on
}

foreach($funcName in $functions.PSBase.Keys){
    New-Item function:\ -Name $funcName -Value $functions.$funcName | Out-Null
}
  • Define script blocks {…} directly in the hashtable, so you don't need to convert anything for the New-Item arguments.
  • Use the automatic variable $args to forward arguments of the script block to the command. Note that for native commands, the $args array is unrolled automatically. For PowerShell commands you'd have to use splatting (@args).

CodePudding user response:

Append @args to your CLI calls, so that PowerShell passes all arguments passed to the function itself through:

foreach($funcName in $functions.PSBase.Keys){
  $null = New-Item function:$funcName -Value "$($functions[$funcName]) @args"
}

Note:

  • @arg is the splatted form of the automatic $args variable. Given that you're calling external programs, $args would be sufficient in this case (either form results in the (stringified) array elements being passed as individual arguments), but if you were to call PowerShell commands, @args is required in order to pass named arguments through properly.

  • As shown above, you can pass the function body as a string to New-Item - it'll be converted to a script block automatically.

  • The above assumes that all pass-through arguments go at the end of each of the CLI command lines that make up your functions. If you need more fine-grained control, use the technique shown in zett42's helpful answer, which allows you to control for each CLI call where @args / $args goes or alternatively allows you to declare parameters explicitly with a param(...) block.

  • Related