Search code examples
powershellbatch-filejenkinsvariable-expansion

How to use special characters in a powerShellScript


So I am trying to use the below script do dynamically put different values in a properties file But powershell will not let me use special characters such as !

@echo off
setlocal enabledelayedexpansion

rem Set the properties file path
set "PROPERTIES_FILE=src\main\resources\config.properties"

rem Replace placeholders with Jenkins parameters in the properties file
powershell -Command "(Get-Content '%PROPERTIES_FILE%') | ForEach-Object { $_ -replace 'USERNAME=(.*)', 'USERNAME=%Username%' } | Set-Content '%PROPERTIES_FILE%'"
powershell -Command "(Get-Content '%PROPERTIES_FILE%') | ForEach-Object { $_ -replace 'PASSWORD=(.*)', ('PASSWORD=' + [regex]::escape('%Password%')) } | Set-Content '%PROPERTIES_FILE%'"


rem Optionally, print the updated file contents for verification
type "%PROPERTIES_FILE%"

rem Execute your Maven command
mvn clean test -Dtest=ScriptTest

I am trying to use Jenkins parameters to update a config.properties file.


Solution

  • Remove enabledelayedexpansion from your setlocal statement.

    • In other words: Replace line setlocal enabledelayedexpansion with just setlocal

    enabledelayedexpansion is what "eats" the ! characters - even those present in the values of statically referenced variables, such as %Password%.

    enabledelayedexpansion is only needed if you no need dynamic variable expansion, by enclosing variable references in !...!, e.g. !Password!, as distinct from the static, macro-like expansion that regular %...% variable references perform.

    While the enabledelayedexpansion feature is sometimes necessary, e.g. for building up a variable's value iteratively in a for /f statement, it is problematic for interpreting any ! as being part of a dynamic variable reference in literal use and in %...% expansions, and quietly removing it if it isn't - unless explicit escaping is employed.

    The following batch-file content demonstrates this problem:

    @echo off & setlocal enableDelayedExpansion
    
    :: This "!" will be "eaten"
    echo [hi!]
    
    echo --
    
    :: In literal use, you can *escape* "!", using "^"
    :: Note that - awkwardly - whether you need *one or two* "^" depends
    :: on whether the argument is inside "..." or not.
    echo [hi^^!]
    echo "[hi^!]"
    
    echo --
    
    :: In %...% variable references, stand-alone "!" are also "eaten",
    :: but via !...! they are preserved.
    
    :: Due to `enabledelayedexpansion`, this assigns verbatim "hi!"
    set "FOO=hi^!"
    
    echo [%FOO%]
    echo [!FOO!]
    

    The above outputs the following, proving that stand-alone ! is "eaten" (quietly removed) in both (unescaped) literal use and in %...% variable expansions:

    [hi]
    --
    [hi!]
    "[hi!]"
    --
    [hi]
    [hi!]
    

    Note:

    • Variable references - both static and dynamic - permit a substitution (substring replacement) technique: e.g,
      set FOO=BAR_NONE, followed by echo %FOO:_=-% or echo !FOO:_=-! (with enabledelayedexpansion in effect) result in BAR-NONE.

    • In principle, you can leverage this in %...% variable references too in order to inject the necessary escaping before dynamic interpretation due to enabledelayedexpansion kicks in - e.g., echo [%FOO:!=^^!%] or echo "[%FOO:!=^!%]" - but, just like with escaping the literal use of !, needing to choose the number of ^ instances for escaping based on whether the reference is inside "..." or not is awkward - and, fundamentally, choosing dynamic expansion via !...! avoids that problem.