• Running Windows Batch
  • Windows Batch
  • Types of shells supported by GitLab Runner

    GitLab Runner implements shell script generators that allow executing builds on different systems.

    The shell scripts contain commands to execute all steps of the build:

    1. git clone
    2. Restore the build cache
    3. Build commands
    4. Update the build cache
    5. Generate and upload the build artifacts

    The shells don’t have any configuration options. The build steps are received from the commands defined in the script directive in .gitlab-ci.yml .

    The supported shells are:

    Shell Status Description
    bash Fully Supported Bash (Bourne Again Shell). All commands executed in Bash context (default for all Unix systems)
    sh Fully Supported Sh (Bourne shell). All commands executed in Sh context (fallback for bash for all Unix systems)
    powershell Fully Supported PowerShell script. All commands are executed in PowerShell Desktop context. In GitLab Runner 12.0-13.12, this is the default when registering a new runner.
    pwsh Fully Supported PowerShell script. All commands are executed in PowerShell Core context. In GitLab Runner 14.0 and later, this is the default when registering a new runner.
    cmd Deprecated Windows Batch script. All commands are executed in Batch context. Deprecated in favor of PowerShell Core. Default when no shell is specified. Learn how to gain access to the CMD shell when PowerShell is the default shell .

    If you want to select a particular shell to use other than the default, you must specify the shell in your config.toml file.

    Sh/Bash shells

    This is the default shell used on all Unix based systems. The bash script used in .gitlab-ci.yml is executed by piping the shell script to one of the following commands:

    Shell profile loading

    For certain executors, the runner passes the --login flag as shown above, which also loads the shell profile. Anything that you have in your .bashrc , .bash_logout , or any other dotfile , is executed in your job.

    If a job fails on the Prepare environment stage, it is likely that something in the shell profile is causing the failure. A common failure is when there is a .bash_logout that tries to clear the console.

    To troubleshoot this error, check /home/gitlab-runner/.bash_logout . For example, if the .bash_logout file has a script section like the following, comment it out and restart the pipeline:

    if [ "$SHLVL" = 1 ]; then
        [ -x /usr/bin/clear_console ] && /usr/bin/clear_console -q
    

    Executors that load shell profiles:

    • shell
    • parallels (The shell profile of the target virtual machine is loaded)
    • virtualbox (The shell profile of the target virtual machine is loaded)
    • ssh (The shell profile of the target machine is loaded)

    PowerShell

    PowerShell Desktop Edition is the default shell when a new runner is registered on Windows using GitLab Runner 12.0-13.12. In 14.0 and later, the default is PowerShell Core Edition.

    PowerShell doesn’t support executing the build in context of another user.

    The generated PowerShell script is executed by saving its content to a file and passing the filename to the following command:

    This is what an example PowerShell script looks like:

    $ErrorActionPreference = "Continue" # This will be set to 'Stop' when targetting PowerShell Core
    echo "Running on $([Environment]::MachineName)..."
      $CI="true"
      $env:CI=$CI
      $CI_COMMIT_SHA="db45ad9af9d7af5e61b829442fd893d96e31250c"
      $env:CI_COMMIT_SHA=$CI_COMMIT_SHA
      $CI_COMMIT_BEFORE_SHA="d63117656af6ff57d99e50cc270f854691f335ad"
      $env:CI_COMMIT_BEFORE_SHA=$CI_COMMIT_BEFORE_SHA
      $CI_COMMIT_REF_NAME="main"
      $env:CI_COMMIT_REF_NAME=$CI_COMMIT_REF_NAME
      $CI_JOB_ID="1"
      $env:CI_JOB_ID=$CI_JOB_ID
      $CI_REPOSITORY_URL="Z:\Gitlab\tests\test"
      $env:CI_REPOSITORY_URL=$CI_REPOSITORY_URL
      $CI_PROJECT_ID="1"
      $env:CI_PROJECT_ID=$CI_PROJECT_ID
      $CI_PROJECT_DIR="Z:\Gitlab\tests\test\builds\0\project-1"
      $env:CI_PROJECT_DIR=$CI_PROJECT_DIR
      $CI_SERVER="yes"
      $env:CI_SERVER=$CI_SERVER
      $CI_SERVER_NAME="GitLab CI"
      $env:CI_SERVER_NAME=$CI_SERVER_NAME
      $CI_SERVER_VERSION=""
      $env:CI_SERVER_VERSION=$CI_SERVER_VERSION
      $CI_SERVER_REVISION=""
      $env:CI_SERVER_REVISION=$CI_SERVER_REVISION
      $GITLAB_CI="true"
      $env:GITLAB_CI=$GITLAB_CI
      $GIT_SSL_CAINFO=""
      New-Item -ItemType directory -Force -Path "C:\GitLab-Runner\builds\0\project-1.tmp" | out-null
      $GIT_SSL_CAINFO | Out-File "C:\GitLab-Runner\builds\0\project-1.tmp\GIT_SSL_CAINFO"
      $GIT_SSL_CAINFO="C:\GitLab-Runner\builds\0\project-1.tmp\GIT_SSL_CAINFO"
      $env:GIT_SSL_CAINFO=$GIT_SSL_CAINFO
      $CI_SERVER_TLS_CA_FILE=""
      New-Item -ItemType directory -Force -Path "C:\GitLab-Runner\builds\0\project-1.tmp" | out-null
      $CI_SERVER_TLS_CA_FILE | Out-File "C:\GitLab-Runner\builds\0\project-1.tmp\CI_SERVER_TLS_CA_FILE"
      $CI_SERVER_TLS_CA_FILE="C:\GitLab-Runner\builds\0\project-1.tmp\CI_SERVER_TLS_CA_FILE"
      $env:CI_SERVER_TLS_CA_FILE=$CI_SERVER_TLS_CA_FILE
      echo "Cloning repository..."
      if( (Get-Command -Name Remove-Item2 -Module NTFSSecurity -ErrorAction SilentlyContinue) -and (Test-Path "C:\GitLab-Runner\builds\0\project-1" -PathType Container) ) {
        Remove-Item2 -Force -Recurse "C:\GitLab-Runner\builds\0\project-1"
      } elseif(Test-Path "C:\GitLab-Runner\builds\0\project-1") {
        Remove-Item -Force -Recurse "C:\GitLab-Runner\builds\0\project-1"
      & "git" "clone" "https://gitlab.com/group/project.git" "Z:\Gitlab\tests\test\builds\0\project-1"
      if(!$?) { Exit $LASTEXITCODE }
      cd "C:\GitLab-Runner\builds\0\project-1"
      if(!$?) { Exit $LASTEXITCODE }
      echo "Checking out db45ad9a as main..."
      & "git" "checkout" "db45ad9af9d7af5e61b829442fd893d96e31250c"
      if(!$?) { Exit $LASTEXITCODE }
      if(Test-Path "..\..\..\cache\project-1\pages\main\cache.tgz" -PathType Leaf) {
        echo "Restoring cache..."
        & "gitlab-runner-windows-amd64.exe" "extract" "--file" "..\..\..\cache\project-1\pages\main\cache.tgz"
        if(!$?) { Exit $LASTEXITCODE }
      } else {
        if(Test-Path "..\..\..\cache\project-1\pages\main\cache.tgz" -PathType Leaf) {
          echo "Restoring cache..."
          & "gitlab-runner-windows-amd64.exe" "extract" "--file" "..\..\..\cache\project-1\pages\main\cache.tgz"
          if(!$?) { Exit $LASTEXITCODE }
    if(!$?) { Exit $LASTEXITCODE }
      $CI="true"
      $env:CI=$CI
      $CI_COMMIT_SHA="db45ad9af9d7af5e61b829442fd893d96e31250c"
      $env:CI_COMMIT_SHA=$CI_COMMIT_SHA
      $CI_COMMIT_BEFORE_SHA="d63117656af6ff57d99e50cc270f854691f335ad"
      $env:CI_COMMIT_BEFORE_SHA=$CI_COMMIT_BEFORE_SHA
      $CI_COMMIT_REF_NAME="main"
      $env:CI_COMMIT_REF_NAME=$CI_COMMIT_REF_NAME
      $CI_JOB_ID="1"
      $env:CI_JOB_ID=$CI_JOB_ID
      $CI_REPOSITORY_URL="Z:\Gitlab\tests\test"
      $env:CI_REPOSITORY_URL=$CI_REPOSITORY_URL
      $CI_PROJECT_ID="1"
      $env:CI_PROJECT_ID=$CI_PROJECT_ID
      $CI_PROJECT_DIR="Z:\Gitlab\tests\test\builds\0\project-1"
      $env:CI_PROJECT_DIR=$CI_PROJECT_DIR
      $CI_SERVER="yes"
      $env:CI_SERVER=$CI_SERVER
      $CI_SERVER_NAME="GitLab CI"
      $env:CI_SERVER_NAME=$CI_SERVER_NAME
      $CI_SERVER_VERSION=""
      $env:CI_SERVER_VERSION=$CI_SERVER_VERSION
      $CI_SERVER_REVISION=""
      $env:CI_SERVER_REVISION=$CI_SERVER_REVISION
      $GITLAB_CI="true"
      $env:GITLAB_CI=$GITLAB_CI
      $GIT_SSL_CAINFO=""
      New-Item -ItemType directory -Force -Path "C:\GitLab-Runner\builds\0\project-1.tmp" | out-null
      $GIT_SSL_CAINFO | Out-File "C:\GitLab-Runner\builds\0\project-1.tmp\GIT_SSL_CAINFO"
      $GIT_SSL_CAINFO="C:\GitLab-Runner\builds\0\project-1.tmp\GIT_SSL_CAINFO"
      $env:GIT_SSL_CAINFO=$GIT_SSL_CAINFO
      $CI_SERVER_TLS_CA_FILE=""
      New-Item -ItemType directory -Force -Path "C:\GitLab-Runner\builds\0\project-1.tmp" | out-null
      $CI_SERVER_TLS_CA_FILE | Out-File "C:\GitLab-Runner\builds\0\project-1.tmp\CI_SERVER_TLS_CA_FILE"
      $CI_SERVER_TLS_CA_FILE="C:\GitLab-Runner\builds\0\project-1.tmp\CI_SERVER_TLS_CA_FILE"
      $env:CI_SERVER_TLS_CA_FILE=$CI_SERVER_TLS_CA_FILE
      cd "C:\GitLab-Runner\builds\0\project-1"
      if(!$?) { Exit $LASTEXITCODE }
      echo "`$ echo true"
      echo true
    if(!$?) { Exit $LASTEXITCODE }
      $CI="true"
      $env:CI=$CI
      $CI_COMMIT_SHA="db45ad9af9d7af5e61b829442fd893d96e31250c"
      $env:CI_COMMIT_SHA=$CI_COMMIT_SHA
      $CI_COMMIT_BEFORE_SHA="d63117656af6ff57d99e50cc270f854691f335ad"
      $env:CI_COMMIT_BEFORE_SHA=$CI_COMMIT_BEFORE_SHA
      $CI_COMMIT_REF_NAME="main"
      $env:CI_COMMIT_REF_NAME=$CI_COMMIT_REF_NAME
      $CI_JOB_ID="1"
      $env:CI_JOB_ID=$CI_JOB_ID
      $CI_REPOSITORY_URL="Z:\Gitlab\tests\test"
      $env:CI_REPOSITORY_URL=$CI_REPOSITORY_URL
      $CI_PROJECT_ID="1"
      $env:CI_PROJECT_ID=$CI_PROJECT_ID
      $CI_PROJECT_DIR="Z:\Gitlab\tests\test\builds\0\project-1"
      $env:CI_PROJECT_DIR=$CI_PROJECT_DIR
      $CI_SERVER="yes"
      $env:CI_SERVER=$CI_SERVER
      $CI_SERVER_NAME="GitLab CI"
      $env:CI_SERVER_NAME=$CI_SERVER_NAME
      $CI_SERVER_VERSION=""
      $env:CI_SERVER_VERSION=$CI_SERVER_VERSION
      $CI_SERVER_REVISION=""
      $env:CI_SERVER_REVISION=$CI_SERVER_REVISION
      $GITLAB_CI="true"
      $env:GITLAB_CI=$GITLAB_CI
      $GIT_SSL_CAINFO=""
      New-Item -ItemType directory -Force -Path "C:\GitLab-Runner\builds\0\project-1.tmp" | out-null
      $GIT_SSL_CAINFO | Out-File "C:\GitLab-Runner\builds\0\project-1.tmp\GIT_SSL_CAINFO"
      $GIT_SSL_CAINFO="C:\GitLab-Runner\builds\0\project-1.tmp\GIT_SSL_CAINFO"
      $env:GIT_SSL_CAINFO=$GIT_SSL_CAINFO
      $CI_SERVER_TLS_CA_FILE=""
      New-Item -ItemType directory -Force -Path "C:\GitLab-Runner\builds\0\project-1.tmp" | out-null
      $CI_SERVER_TLS_CA_FILE | Out-File "C:\GitLab-Runner\builds\0\project-1.tmp\CI_SERVER_TLS_CA_FILE"
      $CI_SERVER_TLS_CA_FILE="C:\GitLab-Runner\builds\0\project-1.tmp\CI_SERVER_TLS_CA_FILE"
      $env:CI_SERVER_TLS_CA_FILE=$CI_SERVER_TLS_CA_FILE
      cd "C:\GitLab-Runner\builds\0\project-1"
      if(!$?) { Exit $LASTEXITCODE }
      echo "Archiving cache..."
      & "gitlab-runner-windows-amd64.exe" "archive" "--file" "..\..\..\cache\project-1\pages\main\cache.tgz" "--path" "vendor"
      if(!$?) { Exit $LASTEXITCODE }
    if(!$?) { Exit $LASTEXITCODE }
    

    Running Windows Batch

    You can execute Batch scripts from PowerShell using Start-Process "cmd.exe" "/c C:\Path\file.bat" for old Batch scripts not ported to PowerShell.

    Windows Batch note
    In GitLab 11.11, we announced the deprecation of the Windows Batch executor, cmd shell, for the GitLab Runner in favor of PowerShell . The cmd shell remains included in future versions of GitLab Runner however, any new feature for Windows is to be tested and supported only for use with PowerShell. Only critical bugs and regressions to the cmd shell will be investigated and fixed.

    You can execute Batch scripts from PowerShell using Start-Process "cmd.exe" "/c C:\Path\file.bat" for old Batch scripts not ported to PowerShell.

    Windows Batch is the default shell used on Windows when shell is not specified.

    It doesn’t support executing the build in context of another user.

    The generated Batch script is executed by saving its content to file and passing the filename to the following command:

    cmd /Q /C generated-windows-batch.cmd
    

    This is what an example Batch script looks like:

    @echo off
    setlocal enableextensions
    setlocal enableDelayedExpansion
    set nl=^
    echo Running on %COMPUTERNAME%...
    call :prescript
    IF !errorlevel! NEQ 0 exit /b !errorlevel!
    call :buildscript
    IF !errorlevel! NEQ 0 exit /b !errorlevel!
    call :postscript
    IF !errorlevel! NEQ 0 exit /b !errorlevel!
    goto :EOF
    :prescript
    SET CI=true
    SET CI_COMMIT_SHA=db45ad9af9d7af5e61b829442fd893d96e31250c
    SET CI_COMMIT_BEFORE_SHA=d63117656af6ff57d99e50cc270f854691f335ad
    SET CI_COMMIT_REF_NAME=main
    SET CI_JOB_ID=1
    SET CI_REPOSITORY_URL=http://gitlab.example.com/group/project.git
    SET CI_PROJECT_ID=1
    SET CI_PROJECT_DIR=Z:\Gitlab\tests\test\builds\0\project-1
    SET CI_SERVER=yes
    SET CI_SERVER_NAME=GitLab CI
    SET CI_SERVER_VERSION=
    SET CI_SERVER_REVISION=
    SET GITLAB_CI=true
    md "C:\\GitLab-Runner\\builds\\0\\project-1.tmp" 2>NUL 1>NUL
    echo multiline!nl!tls!nl!chain > C:\GitLab-Runner\builds\0\project-1.tmp\GIT_SSL_CAINFO
    SET GIT_SSL_CAINFO=C:\GitLab-Runner\builds\0\project-1.tmp\GIT_SSL_CAINFO
    md "C:\\GitLab-Runner\\builds\\0\\project-1.tmp" 2>NUL 1>NUL
    echo multiline!nl!tls!nl!chain > C:\GitLab-Runner\builds\0\project-1.tmp\CI_SERVER_TLS_CA_FILE
    SET CI_SERVER_TLS_CA_FILE=C:\GitLab-Runner\builds\0\project-1.tmp\CI_SERVER_TLS_CA_FILE
    echo Cloning repository...
    rd /s /q "C:\GitLab-Runner\builds\0\project-1" 2>NUL 1>NUL
    "git" "clone" "http://gitlab.example.com/group/project.git" "Z:\Gitlab\tests\test\builds\0\project-1"
    IF !errorlevel! NEQ 0 exit /b !errorlevel!
    cd /D "C:\GitLab-Runner\builds\0\project-1"
    IF !errorlevel! NEQ 0 exit /b !errorlevel!
    echo Checking out db45ad9a as main...
    "git" "checkout" "db45ad9af9d7af5e61b829442fd893d96e31250c"
    IF !errorlevel! NEQ 0 exit /b !errorlevel!
    IF EXIST "..\..\..\cache\project-1\pages\main\cache.tgz" (
      echo Restoring cache...
      "gitlab-runner-windows-amd64.exe" "extract" "--file" "..\..\..\cache\project-1\pages\main\cache.tgz"
      IF !errorlevel! NEQ 0 exit /b !errorlevel!
    ) ELSE (
      IF EXIST "..\..\..\cache\project-1\pages\main\cache.tgz" (
        echo Restoring cache...
        "gitlab-runner-windows-amd64.exe" "extract" "--file" "..\..\..\cache\project-1\pages\main\cache.tgz"
        IF !errorlevel! NEQ 0 exit /b !errorlevel!
    goto :EOF
    :buildscript
    SET CI=true
    SET CI_COMMIT_SHA=db45ad9af9d7af5e61b829442fd893d96e31250c
    SET CI_COMMIT_BEFORE_SHA=d63117656af6ff57d99e50cc270f854691f335ad
    SET CI_COMMIT_REF_NAME=main
    SET CI_JOB_ID=1
    SET CI_REPOSITORY_URL=Z:\Gitlab\tests\test
    SET CI_PROJECT_ID=1
    SET CI_PROJECT_DIR=Z:\Gitlab\tests\test\builds\0\project-1
    SET CI_SERVER=yes
    SET CI_SERVER_NAME=GitLab CI
    SET CI_SERVER_VERSION=
    SET CI_SERVER_REVISION=
    SET GITLAB_CI=true
    md "C:\\GitLab-Runner\\builds\\0\\project-1.tmp" 2>NUL 1>NUL
    echo multiline!nl!tls!nl!chain > C:\GitLab-Runner\builds\0\project-1.tmp\GIT_SSL_CAINFO
    SET GIT_SSL_CAINFO=C:\GitLab-Runner\builds\0\project-1.tmp\GIT_SSL_CAINFO
    md "C:\\GitLab-Runner\\builds\\0\\project-1.tmp" 2>NUL 1>NUL
    echo multiline!nl!tls!nl!chain > C:\GitLab-Runner\builds\0\project-1.tmp\CI_SERVER_TLS_CA_FILE
    SET CI_SERVER_TLS_CA_FILE=C:\GitLab-Runner\builds\0\project-1.tmp\CI_SERVER_TLS_CA_FILE
    cd /D "C:\GitLab-Runner\builds\0\project-1"
    IF !errorlevel! NEQ 0 exit /b !errorlevel!
    echo $ echo true
    echo true
    goto :EOF
    :postscript
    SET CI=true
    SET CI_COMMIT_SHA=db45ad9af9d7af5e61b829442fd893d96e31250c
    SET CI_COMMIT_BEFORE_SHA=d63117656af6ff57d99e50cc270f854691f335ad
    SET CI_COMMIT_REF_NAME=main
    SET CI_JOB_ID=1
    SET CI_REPOSITORY_URL=Z:\Gitlab\tests\test
    SET CI_PROJECT_ID=1
    SET CI_PROJECT_DIR=Z:\Gitlab\tests\test\builds\0\project-1
    SET CI_SERVER=yes
    SET CI_SERVER_NAME=GitLab CI
    SET CI_SERVER_VERSION=
    SET CI_SERVER_REVISION=
    SET GITLAB_CI=true
    md "C:\\GitLab-Runner\\builds\\0\\project-1.tmp" 2>NUL 1>NUL
    echo multiline!nl!tls!nl!chain > C:\GitLab-Runner\builds\0\project-1.tmp\GIT_SSL_CAINFO
    SET GIT_SSL_CAINFO=C:\GitLab-Runner\builds\0\project-1.tmp\GIT_SSL_CAINFO
    md "C:\\GitLab-Runner\\builds\\0\\project-1.tmp" 2>NUL 1>NUL
    echo multiline!nl!tls!nl!chain > C:\GitLab-Runner\builds\0\project-1.tmp\CI_SERVER_TLS_CA_FILE
    SET CI_SERVER_TLS_CA_FILE=C:\GitLab-Runner\builds\0\project-1.tmp\CI_SERVER_TLS_CA_FILE
    cd /D "C:\GitLab-Runner\builds\0\project-1"
    IF !errorlevel! NEQ 0 exit /b !errorlevel!
    echo Archiving cache...
    "gitlab-runner-windows-amd64.exe" "archive" "--file" "..\..\..\cache\project-1\pages\main\cache.tgz" "--path" "vendor"
    IF !errorlevel! NEQ 0 exit /b !errorlevel!
    goto :EOF
    

    Access CMD shell when PowerShell is the default

    The project: Call CMD From Default PowerShell in GitLab CI demonstrates how to gain access to the CMD shell when PowerShell is the default shell on a runner.

    Video walkthrough of working PowerShell examples

    The Slicing and Dicing with PowerShell on GitLab CI video is a walkthrough of the PowerShell Pipelines on GitLab CI Guided Exploration project. It was tested on:

    The example can be copied to your own group or instance for testing. More details on what other GitLab CI patterns are demonstrated are available at the project page.

    Help & feedback

    Docs

    Edit this page to fix an error or add an improvement in a merge request.
    Create an issue to suggest an improvement to this page.

    Product

    Create an issue if there's something you don't like about this feature.
    Propose functionality by submitting a feature request.
    Join First Look to help shape new features.

    Feature availability and product trials

    View pricing to see all GitLab tiers and features, or to upgrade.
    Try GitLab for free with access to all features for 30 days.

    Get Help

    If you didn't find what you were looking for, search the docs .
    If you want help with something specific and could use community support, post on the GitLab forum .
    For problems setting up or using this feature (depending on your GitLab subscription).

    Request support