5

Has anyone run into a problem when using PowerShell in a Jenkins Pipeline, where when you try to pull in an environmental variable (e.g., $env:CHANGE_ID), it evaluates to something like this?

org.jenkinsci.plugins.workflow.cps.EnvActionImpl@1b69f5bb:VARIABLE_NAME

It looks like someone else was running into the same problem in this question, but I'm not sure that it was answered there (they show how to print all environment variables, but not how to get a specific one when toString is not implemented): Retrieve all properties of env in Jenkinsfile

My Jenkins pipeline file:

pipeline {
  agent {
    node {
      label 'jenkins_managed_windows'
    }
  }

  stages {
    stage('SonarQube Analysis') {
      steps {
        powershell "dotnet sonarscanner begin /k:project-key /d:sonar.branch.name=$env:BRANCH_NAME"
      }
    }

    stage('Build') {
      steps {
        powershell 'dotnet build'
      }
    }

    stage('SonarQube End') {
      steps {
        powershell 'dotnet sonarscanner end'
      }
    }
  }
}

The step with the environment variable gets run as:

dotnet sonarscanner begin /k:project-key /d:sonar.branch.name=org.jenkinsci.plugins.workflow.cps.EnvActionImpl@54ee3a8:BRANCH_NAME
Interestingly, if I use single quoting:
powershell 'dotnet sonarscanner begin /k:project-key /d:sonar.branch.name=$env:BRANCH_NAME'
It doesn't even evaluate the environment variable at all, and just gets run as:
dotnet sonarscanner begin /k:project-key /d:sonar.branch.name=$env:BRANCH_NAME
olucafont6
  • 53
  • 7
  • Single-quoted strings are not evaluated. – Benjamin Hubbard Sep 03 '19 at 21:33
  • Try `powershell "dotnet sonarscanner begin /k:project-key /d:sonar.branch.name=$($env:BRANCH_NAME)"` – Benjamin Hubbard Sep 03 '19 at 21:34
  • This gave me: `WorkflowScript: 11: illegal string body character after dollar sign; solution: either escape a literal dollar sign "\$5" or bracket the value expression "${5}" @ line 11, column 3.` I then tried: `powershell "dotnet sonarscanner begin /k:project-key /d:sonar.branch.name=${env:BRANCH_NAME}"`, which ended up working. Thanks! – olucafont6 Sep 03 '19 at 22:23

2 Answers2

5

The syntax forms $env:BRANCH_NAME and the equivalent ${env:BRANCH_NAME} are PowerShell constructs, which means that in order to pass them through to PowerShell in an interpolating Groovy string ("..."), you must \-escape the $ character to prevent Groovy from interpreting the construct up front:

powershell "dotnet sonarscanner begin ... /d:sonar.branch.name=\$env:BRANCH_NAME"

That said, given that your command contains no Groovy variables that need to be interpolated (it's safe and more robust to let PowerShell reference environment variables), you can simply use a literal Groovy string, '...', where $ chars. destined for PowerShell need no escaping:

powershell 'dotnet sonarscanner begin ... /d:sonar.branch.name=$env:BRANCH_NAME'

As for what you tried:

"... $env:BRANCH_NAME" in an interpolating Groovy string causes Groovy to interpolate variable env (since it is preceded by $), and treat :BRANCH_NAME as a literal.

Since env refers to the object that contains all environment variables, what you're seeing is the (unhelpful) stringification of that object, which is the class name (org.jenkinsci.plugins.workflow.cps.EnvActionImpl) followed by an instance-specific hash code (@54ee3a8).

Using ${env.BRANCH_NAME} would have worked - given that the value of environment variable BRANCH_NAME can be accessed as a property of the env object - but note that this means that Groovy interpolates the value up front and that PowerShell then only sees the resulting value.

In simple cases (environment-variable values without whitespace or special characters), "${env.BRANCH_NAME}" (up-front interpolation by Groovy) and "\${env:BRANCH_NAME}" (later interpretation by PowerShell) are interchangeable, but only the latter approach works robustly with all values.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 1
    Oh, nevermind. The output of the Jenkins Pipeline was just showing the command as `dotnet sonarscanner begin /k:project-key /d:sonar.branch.name=$env:BRANCH_NAME`, since Groovy wasn't interpolating the command. When it was actually run in PowerShell though it was using the actual environment variables though. – olucafont6 Sep 04 '19 at 21:29
0

Turns out specifying the environment variable this way works:

powershell "dotnet sonarscanner begin /k:project-key /d:sonar.branch.name=${env:BRANCH_NAME}"

You can also use a period instead of a colon (${env.BRANCH_NAME}).

olucafont6
  • 53
  • 7
  • 1
    Inside `"..."`, you should `\ `-escape the `$` - `\${env:BRANCH_NAME}` - which prevents Groovy from potentially interpreting the construct. By contrast, using `${env.BRANCH_NAME}` (note the `.`) causes Groovy to replace the construct with the _value_ of environment variable `BRANCH_NAME` _before_ PowerShell sees the resulting string. In simple cases the two approaches are interchangeable, but the latter approach can break if your command if the variable value contains whitespace or special characters. – mklement0 Sep 04 '19 at 03:49