puppetlabs/bolt

Ability to write task in Pwsh 7+

Closed this issue · 3 comments

Use Case

The ability to use Pwsh 7 for Bolt Tasks.

Describe the Solution You Would Like

input_type="pwsh" maybe?

Describe Alternatives You've Considered

Using a plan or powershell to call pwsh.

You should be able to configure this in the interpreters config for .ps1 files https://www.puppet.com/docs/bolt/latest/bolt_transports_reference.html#interpreters

@donoghuc I had no idea about this. Thank you!

Is it expected that if a task input_method is powershell that you cannot define interpreters? If I set this to stdin it actually runs in pwsh.exe instead of powershell.exe.

Reproduction:

bolt-project.yaml:

---
name: bolt_pwsh_task
modules: []

inventory:

config:
  local:
    interpreters:
      ".ps1": "C:\\Program Files\\PowerShell\\7\\pwsh.exe"

working but no named parameters tasks/init.json:

{
    "input_method": "stdin",
    "parameters": {
        "name": {
            "description": "Name of user to run command",
            "type": "String"
        }
    }
}

always powershell.exe but working named params tasks/init.json:

{
    "input_method": "powershell",
    "parameters": {
        "name": {
            "description": "Name of user to run command",
            "type": "String"
        }
    }
}

tasks/init.ps1:

#!/usr/bin/env pwsh
[CmdletBinding()]
param (
    [Parameter()]
    [string]
    $name
)

Write-Host "PSEdition = $($PSEdition)"
$PSVersionTable
Write-Host "Name = $($Name)"

Appears to be intentional to not allow overriding

command = if powershell_file?(task_path) && stdin.nil?
run_ps_task(task_path, arguments, input_method)
else
if (interpreter = select_interpreter(task_path, target.options['interpreters']))
# interpreter can be a String or Array here. Cast it to an array.
interpreter_array = Array(interpreter)
# Make path the first part of the array - this should be the binary
path = interpreter_array.shift
# Anything else in interpreters should get prepended to
# the command. If interpreters was a string this will
# just be [task_path]
args = interpreter_array + [task_path]
else
path, args = *process_from_extension(task_path)
end
execute_process(path, args, stdin)
end

def run_ps_task(task_path, arguments, input_method)
# NOTE: cannot redirect STDIN to a .ps1 script inside of PowerShell
# must create new powershell.exe process like other interpreters
# fortunately, using PS with stdin input_method should never happen
if input_method == 'powershell'
Snippets.ps_task(task_path, arguments)
else
Snippets.try_catch(task_path)
end
end

I'm closing because I found much more success using Plans + Script Task. I think it's a bit weird powershell.exe is forced on windows, for non-windows management pwsh is great.