sigkillit
sigkillit

Reputation: 23

Read value of variable in .ps1 and update the same variable in another .ps1

I'm trying to find an efficient way to read the value of a string variable in a PowerShell .ps1 file and then update the same variable/value in another .ps1 file. In my specific case, I would update a variable for the version # on script one and then I would want to run a script to update it on multiple other .ps1 files. For example:

1_script.ps1 - Script I want to read variable from

$global:scriptVersion = "v1.1"

2_script.ps1 - script I would want to update variable on (Should update to v1.1)

$global:scriptVersion = "v1.0"

I would want to update 2_script.ps1 to set the variable to "v1.1" as read from 1_script.ps1. My current method is using get-content with a regex to find a line starting with my variable, then doing a bunch of replaces to get the portion of the string I want. This does work, but it seems like there is probably a better way I am missing or didn't get working correctly in my tests.

My Modified Regex Solution Based on Answer by @mklement0 : I slightly modified @mklement0 's solution because dot-sourcing the first script was causing it to run

$file1 = ".\1_script.ps1"
$file2 = ".\2_script.ps1"

$fileversion = (Get-Content $file1 | Where-Object {$_ -match '(?m)(?<=^\s*\$global:scriptVersion\s*=\s*")[^"]+'}).Split("=")[1].Trim().Replace('"','')
(Get-Content -Raw $file2) -replace '(?m)(?<=^\s*\$global:scriptVersion\s*=\s*")[^"]+',$fileversion | Set-Content $file2 -NoNewLine

Upvotes: 2

Views: 432

Answers (2)

mklement0
mklement0

Reputation: 437663

Generally, the most robust way to parse PowerShell code is to use the language parser. However, reconstructing source code, with modifications after parsing, may situationally be hampered by the parser not reporting the details of intra-line whitespace - see this answer for an example and a discussion.[1]

Pragmatically speaking, using a regex-based -replace solution is probably good enough in your simple case (note that the value to update is assumed to be enclosed in "..." - but matching could be made more flexible to support '...' quoting too):

# Dot-source the first script in order to obtain the new value.
# Note: This invariably executes *all* top-level code in the script.
. .\1_script.ps1 

# Outputs to the display.
# Append 
#   | Set-Content -Encoding utf8 2_script.ps1
# to save back to the input file.
(Get-Content -Raw 2_script.ps1) -replace '(?m)(?<=^\s*\$global:scriptVersion\s*=\s*")[^"]+', $global:scriptVersion

For an explanation of the regex and the ability to experiment with it, see this regex101.com page.


[1] Syntactic elements are reported in terms of line and column position, and columns are character-based, meaning that spaces and tabs are treated the same, so that a difference of, say, 3 character positions can represent 3 spaces, 3 tabs, or any mix of it - the parser won't tell you. However, if your approach allows keeping the source code as a whole while only removing and splicing in certain elements, that won't be a problem, as shown in iRon's helpful answer.

Upvotes: 2

iRon
iRon

Reputation: 23663

To compliment the helpful answer from @mklement0. In case your do go for the PowerShell abstract syntax tree (AST) class, you might use the Extent.StartOffset/Extent.EndOffset properties to reconstruct your script:

Using NameSpace System.Management.Automation.Language

$global:scriptVersion = 'v1.1' # . .\Script1.ps1
$Script2 = { # = Get-Content -Raw .\Script2.ps1
[CmdletBinding()]param()
begin {
    $global:scriptVersion = "v1.0"
}
process {
    $_
}
end {}
}.ToString()

$Ast = [Parser]::ParseInput($Script2, [ref]$null, [ref]$null)
$Extent = $Ast.Find(
    {
        $args[0] -is [AssignmentStatementAst] -and
        $args[0].Left.VariablePath.UserPath -eq 'global:scriptVersion' -and
        $args[0].Operator -eq 'Equals'
    }, $true
).Right.Extent
-Join (
    $Script2.SubString(0, $Extent.StartOffset),
    $global:scriptVersion,
    $Script2.SubString($Extent.EndOffset)
) # |Set-Content .\Script2.ps1

Upvotes: 3

Related Questions