Replies: 3 comments 16 replies
-
|
I think the big challenges we'd need to overcome here are:
We would also require users to use the On the pros side:
|
Beta Was this translation helpful? Give feedback.
-
|
On the AST rewriting front, my thought is basically that we could attempt something like this: [Cmdlet(VerbsCommon.Get, "ConcatStrings")]
public class GetConcatStringsCommand : PSCmdlet
{
[Parameter]
public ScriptBlock Script { get; set; }
protected override void EndProcessing()
{
var visitor = new StringGatheringVisitor();
Script.Ast.Visit(visitor);
WriteObject(visitor.GetRewrittenStrings(), enumerateCollection: true);
}
private class StringGatheringVisitor : AstVisitor2
{
private List<string> _strings;
public StringGatheringVisitor()
{
_strings = new List<string>();
}
public IEnumerable<string> GetRewrittenStrings()
{
return _strings;
}
public override AstVisitAction VisitExpandableStringExpression(ExpandableStringExpressionAst expandableStringExpressionAst)
{
var sb = new StringBuilder(expandableStringExpressionAst.Value.Length).Append("concat ");
int currIndex = 0;
foreach (ExpressionAst expression in expandableStringExpressionAst.NestedExpressions)
{
int nextIndex = expression.Extent.StartOffset - expandableStringExpressionAst.Extent.StartOffset;
if (currIndex < nextIndex)
{
sb.Append("'").Append(expandableStringExpressionAst.Value.Substring(currIndex, nextIndex - currIndex - 1).Replace("'", "''")).Append("' ");
}
sb.Append(expression.Extent.Text).Append(' ');
currIndex = expression.Extent.EndOffset - expandableStringExpressionAst.Extent.StartOffset - 1;
}
if (currIndex < expandableStringExpressionAst.Value.Length - 1)
{
sb.Append("'").Append(expandableStringExpressionAst.Value.Substring(currIndex).Replace("'", "''")).Append("'");
}
_strings.Add(sb.ToString());
return AstVisitAction.Continue;
}
}
}> Get-ConcatStrings -Script {
"ssh $adminUsername@$((reference $publicIPAddressName).dnsSettings.fqdn)"
}
concat 'ssh ' $adminUsername '@' $((reference $publicIPAddressName).dnsSettings.fqdn)
> Get-ConcatStrings -Script { "hello${there}friends${of}the${woods}" }
concat 'hello' ${there} 'friends' ${of} 'the' ${woods} |
Beta Was this translation helpful? Give feedback.
-
|
On the dirty arm provider trick, this seems to do what is expected: # represents list of psarm ref objects
$psarm = @{
adminUsername = "[parameters('x')]"
}
function arm([string]$expr) {
# is psarm reference?
if ($psarm[$expr]) {
return $psarm[$expr] # emit expression
}
@"
[concat($(($expr.split()|% { if (([regex]"`^\[.+\]`$").IsMatch($_)) {
@"
$_
"@
} else {
@"
'$_'
"@
}}) -join ","))]
"@
}
$hostname = "hostname"
arm("ssh $(arm('adminUsername')) $hostname")returns |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Taken from discussion at https://twitter.com/alexandair/status/1378100061725466624
Taking @alexandair 's question in hand:
In short: How can we improve PSArm to allow interpolation of ARM references to keep the clarity of bicep, while allowing the improved expressiveness of powershell?
My suggestion is to use a special powershell arm resolver provider, modeled something like this:
Problem statement
Regular string interpolation won't work, because as @rjmholt demonstrates:
So, we can't use direct string interpolation - but what if we use powershell's provider model for our benefit?
Suggested Solution
Let's take advantage of the fact that
"ssh $adminUsername"is equivalent to"ssh ${variable:adminUsername}", which is itself equivalent to"ssh $(get-content variable:\adminUsername)"If we prefix PSArm objects with our own recursive "resolver" (hello graphql!) like so:
$arm:"ssh $arm:adminUsername"then we can apply the same logic:$arm:adminUsernamegets resolved to$(get-content arm:adminUsername)which resolves to[parameters('x')]$arm:"ssh [parameters('x')]"gets resolved to$(get-content arm:"ssh [parameters('x')]")which resolves to[concat("ssh", [parameters('x'])]This approach allows regular string interpolation too, example:
$arm:"ssh $arm:adminUsername $hostname"will interpolate$hostnameas a regular string taken from the "default" variable provider.Of course, the devil is in the details but I think the idea seems sound enough, IMHO.
Beta Was this translation helpful? Give feedback.
All reactions