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

Time:10-13

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

CodePudding user response:

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

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.
. .\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.

CodePudding user response:

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
  • Related