Let’s say I have two variables and a scriptblock that looks like this:
$var1 = 'test1'
$var2 = 'test2'
$ScriptBlock = { echo "$var1"; $var2 }
I want to rename $var1 and $var2 to $var1-new and $var2 to $var2-new. What’s the best way to do this? I want to be able to rename all variables in a scriptblock regardless of where they are. This is just a simple example. A scriptblock may actually be hundreds of lines long with dozens of variables all in different contexts so I’d appreciate a scalable solution.
I don’t want to just do a regex find/replace on all “$something” strings. I want put some intelligence behind it and pick out the variables in various contexts like by themselves and in double quotes for example.
I’ve been fooling around with the AST do this but I don’t understand where it’s getting it’s offset numbers from. Here’s what I have.
$AstVariables = $ScriptBlock.Ast.FindAll({ $args[0] -is [System.Management.Automation.Language.VariableExpressionAst] }, $true)
$BlockText = $ScriptBlock.Ast.Endblock.Extent.Text
$selectProps = @(
@{ n = 'Variable'; e = { $_.VariablePath.UserPath } }
@{ n = 'Start'; e = { $_.Extent.StartOffset - 16 } }
@{ n = 'End'; e = { $_.Extent.EndOffset - 16 } }
'Parent'
)
$VariableLocations = $AstVariables | Select-Object -Property $selectProps | Sort-Object 'Start' -Descending
$VariableLocations | foreach {
if ($_.Parent.CommandElements[0].StringConstantType -ne 'DoubleQuoted')
{
$NewName = '{0}:{1}' -f '$using', $_.Variable
} else {
$NewName = '$({0}:{1})' -f '$using', $_.Variable
}
$BlockText = $BlockText.Remove($_.Start, ($_.End - $_.Start)).Insert($_.Start, $NewName)
}
[scriptblock]::Create($BlockText)
This works…sometimes. For some reason, the StartOffset and EndOffset numbers are sometimes wrong to locate the starting and ending positions of the variables. I’m not quite sure why I’m having to subtract 16 from the number to make them close. Admittedly, this is a major hack. There’s got to be a better way to get the starting and ending places where all the variables are located in the scriptblock. That is the hardest part so far.
I’ve tried to use the Parser as well but ran into some problems when variables were inside double quotes.
Can anyone offer any assistance?