azure-devopsazure-pipelinesazure-pipelines-yamlservicenow

Azure YAML Pipeline ServiceNow Connector Can't Access Variable Values


I have an Azure YAML Pipeline that is setting variables in a step to use in later steps. For example, setting a timestamp to a variable and passing later into the ServiceNow Change Management connector for the "planned start date" field. The problem is, the planned start date field does not seem to accept any syntax for the pipeline's variables. The pipeline fails no matter what I try. The ServiceNow Change Management connector exists in an environment check in the pipeline's step.

Here's my example YAML:

trigger:
  branches:
    include:
    - development
  paths:
    include:
    - /migrations

stages:
- stage: SetVariablesStage
  jobs:
  - job: SetVariableJob
    steps:
    - powershell: |
        $dateTimeFormat = "yyyy-MM-dd HH:mm:ss"
        $scheduledDateTimeFormat = "yyyy-MM-dd HH:mm"
        $plannedStartDateTime = (Get-Date).AddMinutes(-60).ToString($dateTimeFormat)
        $plannedEndDateTime = (Get-Date).ToString($dateTimeFormat)
        $scheduledStartDateTime = (Get-Date).AddMinutes(-60).ToString($scheduledDateTimeFormat)
        $scheduledEndDateTime = (Get-Date).ToString($scheduledDateTimeFormat)
        Write-Host "##vso[task.setvariable variable=plannedStartDateTime;isOutput=true]$plannedStartDateTime"
        Write-Host "##vso[task.setvariable variable=plannedEndDateTime;isOutput=true]$plannedEndDateTime"
        Write-Host "##vso[task.setvariable variable=scheduledStartDateTime;isOutput=true]$scheduledStartDateTime"
        Write-Host "##vso[task.setvariable variable=scheduledEndDateTime;isOutput=true]$scheduledEndDateTime"
        echo "plannedStartDateTime: $plannedStartDateTime"
        echo "plannedEndDateTime: $plannedEndDateTime"
        echo "scheduledStartDateTime: $scheduledStartDateTime"
        echo "scheduledEndDateTime: $scheduledEndDateTime"
      displayName: 'Set Custom Variables'
      name: SetVariableStep
    pool:
      vmImage: ubuntu-latest
- stage: 'dev_stage'
  dependsOn: SetVariablesStage
  variables:
    - group: TestPipeline-Variables_Dev
    - name: env
      value: "dev"
  jobs:      
  - deployment: DeployToDevelopment
    variables:
      plannedStartDateTime: $[ stageDependencies.SetVariablesStage.SetVariableJob.outputs['SetVariableStep.plannedStartDateTime'] ]
      plannedEndDateTime: $[ stageDependencies.SetVariablesStage.SetVariableJob.outputs['SetVariableStep.plannedEndDateTime'] ]
      scheduledStartDateTime: $[ stageDependencies.SetVariablesStage.SetVariableJob.outputs['SetVariableStep.scheduledStartDateTime'] ]
      scheduledEndDateTime: $[ stageDependencies.SetVariablesStage.SetVariableJob.outputs['SetVariableStep.scheduledEndDateTime'] ]
    displayName: 'Deploying to Development'
    pool:
      vmImage: 'ubuntu-latest'
    environment: 
      name: 'Development'
    strategy:
      runOnce:
        deploy:
          steps:          
          - checkout: self
          - task: UsePythonVersion@0
            displayName: 'Use Python 3.8.x'
            inputs:
              versionSpec: '3.8.x'
          - task: Bash@3
            inputs:
              targetType: 'inline'
              script: |
                <redacted: Deployment script>

  - job: update_ServiceNow
    dependsOn: DeployToDevelopment
    variables:
      plannedStartDateTime: $[ stageDependencies.SetVariablesStage.SetVariableJob.outputs['SetVariableStep.plannedStartDateTime'] ]
      plannedEndDateTime: $[ stageDependencies.SetVariablesStage.SetVariableJob.outputs['SetVariableStep.plannedEndDateTime'] ]
      scheduledStartDateTime: $[ stageDependencies.SetVariablesStage.SetVariableJob.outputs['SetVariableStep.scheduledStartDateTime'] ]
      scheduledEndDateTime: $[ stageDependencies.SetVariablesStage.SetVariableJob.outputs['SetVariableStep.scheduledEndDateTime'] ]
    steps:
    - task: UpdateServiceNowChangeRequest@2
      inputs:
        ServiceNowConnection: 'ServiceNow_Sandbox'
        NewStatus: '6'
        otherParameters: '{  "u_work_notes": "$(Build.BuildNumber) $(plannedStartDateTime) $(plannedEndDateTime)", "u_scheduled_start": "$(scheduledStartDateTime)", "u_scheduled_end": "$(scheduledEndDateTime)"  }'
pool: server

Example ServiceNow connection configuration:

ServiceNow Configuration

For the Control Options: Linked Variable Group, I have it connected to the correct Variable group.

When I run the pipeline, the environment check fails. It is related to the Planned Start Date field because if I hard code a value the pipeline works. If I remove the value it works, but later fails due to a business rule in our ServiceNow on the field.

How do I use a variable in the field so I don't have to hard code it? The last step in the pipeline that updates servicenow works correctly. I am able to set the "otherParameters" correctly with the pipeline variables. Just not in the Environment Check ServiceNow connector.


Solution

  • The problem is, the planned start date field does not seem to accept any syntax for the pipeline's variables.

    The ServiceNow Change Management in environment approval cannot directly invoke the variables which created in previous stage/job.

    You can try to output the variable value to validate. For example, output in Approvals:

    enter image description here

    To use the variable value, as an alternative, you can put the target value to variable group, and link to this group in ServiceNow Change Management, then you can use the variable inside.

    enter image description here

    enter image description here

    I don't have servicenow account, so i checked with rest api approval as an example.

    I updated the variable group variable value in powershell task. Make sure the {project} build service(org) account has administrator role on the Variable group security so that it can update the variable value.

    enter image description here

    stages:
    - stage: SetVariablesStage
      jobs:
      - job: SetVariableJob
        steps:
        - powershell: |
            $dateTimeFormat = "yyyy-MM-dd HH:mm:ss"
            $scheduledDateTimeFormat = "yyyy-MM-dd HH:mm"
            $plannedStartDateTime = (Get-Date).AddMinutes(-60).ToString($dateTimeFormat)
            $plannedEndDateTime = (Get-Date).ToString($dateTimeFormat)
            $scheduledStartDateTime = (Get-Date).AddMinutes(-60).ToString($scheduledDateTimeFormat)
            $scheduledEndDateTime = (Get-Date).ToString($scheduledDateTimeFormat)
            Write-Host "##vso[task.setvariable variable=plannedStartDateTime;isOutput=true]$plannedStartDateTime"
            Write-Host "##vso[task.setvariable variable=plannedEndDateTime;isOutput=true]$plannedEndDateTime"
            Write-Host "##vso[task.setvariable variable=scheduledStartDateTime;isOutput=true]$scheduledStartDateTime"
            Write-Host "##vso[task.setvariable variable=scheduledEndDateTime;isOutput=true]$scheduledEndDateTime"
            echo "plannedStartDateTime: $plannedStartDateTime"
            echo "plannedEndDateTime: $plannedEndDateTime"
            echo "scheduledStartDateTime: $scheduledStartDateTime"
            echo "scheduledEndDateTime: $scheduledEndDateTime"
          displayName: 'Set Custom Variables'
          name: SetVariableStep
      
        - powershell: |
            $url = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/distributedtask/variablegroups/27?api-version=5.0-preview.1"
            Write-Host $url
            $json = '{"id":27,"type":"Vsts","name":"TestPipeline-Variables_Dev","variables":{"plannedStartDateTimeVG":{"isSecret":false,"value":"$(SetVariableStep.plannedStartDateTime)"}, "plannedEndDateTimeVG":{"isSecret":false,"value":"$(SetVariableStep.plannedEndDateTime)"}}}'
            $pipeline = Invoke-RestMethod -Uri $url -Method Put -Body $json -ContentType "application/json" -Headers @{
                Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
            }
            Write-Host "New Variable Value:" $pipeline.variables.plannedStartDateTimeVG.value
            Write-Host "New Variable Value:" $pipeline.variables.plannedEndDateTimeVG.value
          env:
            SYSTEM_ACCESSTOKEN: $(system.accesstoken)
        pool:
          vmImage: ubuntu-latest
    
    - stage: 'dev_stage'
      dependsOn: SetVariablesStage
      variables:
        - group: TestPipeline-Variables_Dev
        - name: env
          value: "dev"
      jobs:      
      - deployment: DeployToDevelopment
        variables:
          plannedStartDateTime: $[ stageDependencies.SetVariablesStage.SetVariableJob.outputs['SetVariableStep.plannedStartDateTime'] ]
          plannedEndDateTime: $[ stageDependencies.SetVariablesStage.SetVariableJob.outputs['SetVariableStep.plannedEndDateTime'] ]
          scheduledStartDateTime: $[ stageDependencies.SetVariablesStage.SetVariableJob.outputs['SetVariableStep.scheduledStartDateTime'] ]
          scheduledEndDateTime: $[ stageDependencies.SetVariablesStage.SetVariableJob.outputs['SetVariableStep.scheduledEndDateTime'] ]
        displayName: 'Deploying to Development'
        pool:
          vmImage: 'ubuntu-latest'
        environment: 
          name: 'Development'
        strategy:
          runOnce:
            deploy:
              steps:          
              - checkout: self
              - task: UsePythonVersion@0
                displayName: 'Use Python 3.8.x'
                inputs:
                  versionSpec: '3.8.x'
              - task: Bash@3
                inputs:
                  targetType: 'inline'
                  script: |
                    echo 1 $(plannedStartDateTime)
                    echo 2 $(plannedEndDateTime)
                    echo 3 $(scheduledStartDateTime)
                    echo 4 $(scheduledEndDateTime)
    

    I simply invoked the variable from Variable group in the url:

    enter image description here

    Confirm the variable is correctly get in rest api url when pipeline started. enter image description here