Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No way to get output or set variables from Execute-Powershell calls #26

Closed
jimbobmcgee opened this issue Jan 30, 2025 · 2 comments
Closed

Comments

@jimbobmcgee
Copy link

jimbobmcgee commented Jan 30, 2025

There does not appear to be a means to capture the output stream from Execute-Powershell, nor does it appear possible to obtain the value of a variable set inside the Powershell script back to the enclosing OtterScript.

It is possible to get a result back from $PSEval() but the options to both $PSEval and Execute-Powershell are not equivalent. For instance:

  1. Execute-Powershell uses a Text property which does not interpolate OtterScript variables at the script level (it extracts and dispatches them), which means it better handles the $variables that are specific to the Powershell script
  2. $PSEval() does interpolate OtterScript variables, which means all the variables in the Powershell script have to be backtick-escaped, whether they are specific to the Powershell script or defined in the OtterScript context
  3. $PSEval() does not like parentheses; many of these have to be escaped as well, and it is not always clear which ones
  4. $PSEval() does not like newlines; these can be within "swim" strings, but these still require escaping at least the variables
  5. $PSEval() is not (currently) particularly supportive of scripts with varying output (see PSEval can be called as $PSEval, @PSEval or %PSEval, but null/empty returns only make sense for $PSEval #25).

Correctly escaping all the parentheses and variables in any Powershell longer than a couple of lines is an exercise in torture.

Execute-Powershell is clearly the better choice for more complex scripts, but seems to lack the means to return anything back to the caller.

As such, could Execute-Powershell be at least augmented with an output parameter, to capture anything in the Powershell output stream back to target variable? (noting it would have to be aware of scalar or vector context)

Alternatively/additionally, it would be useful for Execute-Powershell to export variables back to the calling OtterScript context. Clobbering existing variables across the board might not be the right approach (so as not to break existing scripts), but perhaps Execute-Powershell could be given an optional input parameter which is a list of variable names to export, so the capure is opt-in?

(I assume this was the intent of including them in ExecutePowerShellJob+Result, and that Result is corerectly populated...)

# context aware output..
Execute-Powershell (
  Text: >>
    Write-Output "abc"
  >>, 
  OutputVariable => $foo
);

Execute-Powershell (
  Text: >>
    Write-Output "abc"
    Write-Output "def"
    Write-Output "ghi"
  >>, 
  OutputVariable => @bar
);

Execute-Powershell (
  Text: >>
    Write-Output @{a = 1; b = 2; c = 3} 
  >>, 
  OutputVariable => %baz
);

# or, with capture...
Execute-Powershell (
  Text: >>
    $a = 10 + 5
    $b = @($a, 10)
    $c = @{a = $a; b = $b}
  >>,
  CaptureVariables: @(a, b, c)
);
Log-Information $a;            # -> 15
Log-Information $ToJson(@b);   # -> ["15", "10"]
Log-Information $ToJson(%c);   # -> { "a": "15", "b": ["15", "10"] }

Expand for various crimes against humanity, trying to escape properly

set $foo = "hello 'world'";
set @bar = @();

# 'natural' approach, newlines, no escapes: (otter compile error: 'Expected ;')
{
    set @a = @PSEval(
        for ($i = 1; $i -le 5; $i++) {
            Write-Output ('{0} {1}' -f $foo,$i)
        }
    );
    Log-Information `@a: $ToJson(@a);
}

# flatten newlines, no escapes: (otter runtime error: 'cannot resolve variable $i')
set @a = @PSEval(for ($i = 1; $i -le 5; $i++) { Write-Output ('{0} {1}' -f $foo,$i) });

# flatten newlines, no escapes: (otter runtime error: 'invalid use of vector expression in scalar')
set $a = $PSEval(for ($i = 1; $i -le 5; $i++) { Write-Output ('{0} {1}' -f $foo,$i) });

# flatten newlines, escape parens: (otter runtime error: 'cannot resolve variable $i')
set @a = @PSEval(for `($i = 1; $i -le 5; $i++`) { Write-Output `('{0} {1}' -f $foo,$i`) });

# flatten newlines, escape Powershell sigils and parens: ($foo is interpolated, not captured; Powershell syntax error at '-f hello')
set @a = @PSEval(for `(`$i = 1; `$i -le 5; `$i++`) { Write-Output `('{0} {1}' -f $foo,`$i`) });

# flatten newlines, escape all sigils and parens: ($foo is captured; powershell runtime error: 'missing closing ")"')
set @a = @PSEval(for (`$i = 1; `$i -le 5; `$i++`) { Write-Output ('{0} {1}' -f `$foo,`$i`) });

# flatten newlines, escape all sigils and parens: ($foo is captured; powershell runtime error: 'missing closing ")"')
set @a = @PSEval(for `(`$i = 1; `$i -le 5; `$i++`) { Write-Output `('{0`} {1`}' -f `$foo,`$i`) });

# as a swim string; same as above: ('cannot resolve $i' when unescaped; 'missing closing ")"' when escaped)
set @a = @PSEval(>-|>
    for ($i = 1; $i -le 5; $i++) { 
        Write-Output ('{0} {1}' -f $foo,$i)
    }
>-|>);

# as a variable, leaded by swim string; escaping all sigils: (captures $foo, this is the first one that works)
set $ps = >-|>
    for (`$i = 1; `$i -le 5; `$i++) { 
        Write-Output ('{0} {1}' -f `$foo,`$i)
    }
>-|>;
set @a = @PSEval($ps);

# executes with the 'natural' syntactic approach; captures $foo but has no means to return output
Execute-Powershell(
    Text: >-|>
        for ($i = 1; $i -le 5; $i++) { 
            Write-Output ('{0} {1}' -f $foo,$i)
        }
    >-|>
);

# similarly 'natural'; captures $foo and $bar, but does not populate @bar
Execute-Powershell(
    Text: >-|>
        $bar = @()
        for ($i = 1; $i -le 5; $i++) { 
            $bar += ('{0} {1}' -f $foo,$i)
        }
    >-|>
);
@inedodean
Copy link

hi @jimbobmcgee ,

We don't monitor our GitHib repos for issues and we have no means of tracking/assigning progress to them internally so, I'm going to close out this issue and try to disable issue tracking.

Can you post this to our fourms instead, where we can track it internally?
https://forums.inedo.com/

We'll respond on there as well.

-- Dean

@apxltd apxltd closed this as completed Jan 30, 2025
@apxltd
Copy link
Member

apxltd commented Jan 30, 2025

i'll also try to remember to disable this later then, so you can at least copy/paste old message

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants