As a convention-oriented deployment tool, Octopus can perform a number of actions automatically, such as managing configuration files, creating IIS websites and application pools, and installing Windows Services. Sometimes however you’ll need to do more than the built-in conventions support – and that’s where custom scripts come in.
- Scripts in Packages
- Scripts in package steps
- Standalone scripts
- Azure PowerShell scripts
- Passing parameters to scripts
- Error handling
- Output variables
- Collecting artifacts
- Security and permissions
- Testing scripts
- Working directories
- Scripts that block deployments
Scripts in Packages
In your package, you can add any of the following script files in any of the scripting languages supported by Octopus where
<ext> is the appropriate extension for your scripting language of choice:
After extracting your package, Calamari will detect these scripts and invoke them. Which file you use depends on when you need your custom activity to run – see the section on what order are conventions run in for details. Your scripts can do anything your scripting language supports, as well as setting output variables and collecting artifacts. These scripts must be located in the root of your package.
As mentioned above, you can create a file named
DeployFailed.<ext>, which will be invoked if the package deployment fails. Our blog post about this feature describes how DeployFailed.<ext> works.
Scripts in package steps
Rather than embed scripts in packages, you can also define scripts within the package step definition in Octopus. This is a feature that can be enabled on package steps:
When enabled, you can define your PreDeploy/Deploy/PostDeploy scripts within the Octopus user interface:
Octopus also allows you to add standalone script steps to your deployment process. You can use standalone scripts to execute scripts on the Octopus Server or on deployment targets, where the script can be defined inline or as part of a package. Standalone scripts are so useful we've dedicated an entire page to them: Standalone scripts.
Azure PowerShell scripts
You can manage your Azure subscription using custom PowerShell scripts and the Azure Resource Management (RM) or Service Management (SM) API - more information.
For information about adding a step to the deployment process, see the add step section.
Octopus allows you to define variables to parameterize your deployments. These variables, along with some predefined variables, will be available from within your scripts.
Let's consider an example where we have defined a project variable called
Variables in PowerShell scripts
In PowerShell we have pre-defined some script-scoped variables for you as a convenience. Consider the same example as before, a variable named "MyApp.ConnectionString" will be available as both:
In the first form the variable name appears just as they appear in the Octopus web portal, while in the second example special characters have been removed. The first form is the most flexible, but in some cases the second form may be more convenient.
Passing parameters to scripts
Octopus can pass parameters to your custom script files for any of the supported scripting languages. This means you can use existing scripts, or write and test your own parameterized scripts that have no knowledge of Octopus, passing Octopus Variables directly to your scripts as parameters. The Octopus scripting API is still available within the context of your script, meaning you can use a mixture of parameters and other Octopus variables and functions.
Consider this example PowerShell script:
You can parameterize this script making it easier to test outside of Octopus:
When you call external scripts (sourced from a file inside a package) you can pass parameters to your script. This means you can write "vanilla" scripts that are unaware of Octopus, and test them in your local development environment.
You can define your parameters in the Script Parameters field using the format expected by your scripting execution environment (see below for examples).
Passing parameters to PowerShell scripts
You can pass parameters to PowerShell scripts as if you were calling the script yourself from PowerShell, using positional or named parameters.
Passing parameters to C# scripts
You can pass parameters to C# scripts as described here for the ScriptCS engine. ScriptCS only supports positional parameters.
Passing parameters to Bash scripts
You can pass parameters to Bash scripts as described in Bash manual.
Passing parameters to F# scripts
You can pass parameters to FSharp scripts as described in MSDN.
When your scripts emit messages Octopus will display the messages in the Task Logs at the most appropriate level for the message. For example:
Try these out for yourself using the Script Console!
Calamari examines the exit code of the script engine to determine whether the script failed. If the exit code is zero, Calamari assumes the script ran successfully. If the exit code is non-zero, then Calamari assumes the script failed.
Syntax errors and unhandled exceptions will result in a non-zero exit code from the script engine, which will fail the deployment
Error handling in PowerShell scripts
For PowerShell scripts Calamari also sets the
$ErrorActionPreference to Stop before invoking your script. This means that if a command fails, the rest of the script won't be executed. For example:
The third line will not be executed. To change this behavior, set
$ErrorActionPreference to Continue at the top of your script.
At the end of the script, Calamari also checks
$LastExitCode to see if the last Windows-based program that you invoked exited successfully. Note that some Windows programs use non-zero exit codes even when they run successfully - for example, Robocopy returns the number of files copied. This can mean that Calamari assumes your script failed even if it actually ran successfully. Best practice is to call
Exit 0 yourself if your script ran successfully.
Note that you'll need to check
$LastExitCode yourself if you run multiple Windows programs. For example, with this script, Calamari would correctly see that ping returned an exit code of 1 (the host couldn't be contacted) and will assume the script failed:
But if your script looks like this, Calamari will only examine the exit code from the last line (which is successful), so it will assume the script was successful.
The best practice here is to always check the exit code when invoking programs:
Your scripts can emit variables that are available in subsequent deployment steps. This means you can factor your deployment into smaller, more well-defined steps that leverage the result of prior steps. It is an extremely powerful feature and you should refer to the documentation on output variables for more information.
Does your deployment produce a log file, configuration files, binaries, or test results you want to publish and keep as part of your deployment? Your scripts can instruct the Octopus server to collect files as deployment artifacts. Refer to the documentation on artifacts for more information.
This example comes from our VSTS Extension which builds a VSIX package as part of the deployment process, which is then published as an artifact for convenience.
Security and permissions
Keep in mind that scripts are executed in the context of the account that the Tentacle Windows Service (which invokes Calamari) or SSH session runs as.
You may find that your script runs differently under Calamari than it does when run from PowerShell directly.
The easiest way to test your scripts under Calamari is to use the Script Console. Alternatively you can invoke
Calamari.exe run-script via the command line to test a script.
Octopus Scripts are executed by Calamari, the command-line tool invoked by the Octopus Server or Tentacle during a deployment, within a the context of a working directory. This location is C:\Octopus\Work\ by default. If you're executing a script contained within a package, the package contents will be uncompressed and copied to this directory but the working directory is the directory containing the script within it.
Scripts that block deployments
Sometimes a script launches a service or application that runs continuously. In this case the script does not complete until the application is terminated. When the script is run in an Octopus deployment, the deployment will continue executing until the script exits. In most cases this is undesirable. In order to avoid this behaviour the service or application should be launched in a separate process or session, allowing the deployment to continue executing immediately. For example: