Octopus.Script exported 2025-10-14 by mcasperson belongs to ‘Octopus’ category.
This step checks to ensure that deployments to blue/green environments alternate. The output variable SequentialDeploy is set to True if two deployments are done to the same environment, and False if they are alternating.
A common scenario is to check for SequentialDeploy set to True and display a warning or the manual intervention step to confirm a deployment.
Parameters
When steps based on the template are included in a project’s deployment process, the parameters below can be set.
The Octopus API key
BlueGreen.Octopus.Api.Key =
Use the documentation at https://octopus.com/docs/octopus-rest-api/how-to-create-an-api-key to create an API key.
The name of the blue environment
BlueGreen.Environment.Blue.Name =
This is the name of the environment in Octopus that represents the blue deployment stack. It will be something like Production - Blue.
The name of the green environment
BlueGreen.Environment.Green.Name =
This is the name of the environment in Octopus that represents the green deployment stack. It will be something like Production - Green.
Script body
Steps based on this template will execute the following PowerShell script.
# We assume that deployments to the production environments alternate between green and blue.
# For example, if the last production deployment was to blue the next one should be to the green environment.
# This check is used to provide a warning if a production environment is deployed to twice in a row.
$octopusUrl = ""
if ([string]::IsNullOrWhitespace("#{Octopus.Web.ServerUri}"))
{
$octopusUrl = "#{Octopus.Web.BaseUrl}"
}
else
{
$octopusUrl = "#{Octopus.Web.ServerUri}"
}
if (-not "#{BlueGreen.Octopus.Api.Key}".StartsWith("API-")) {
Write-Host "The BlueGreen.Octopus.Api.Key variable has not been defined. We can not validate the deployment environment."
Write-Highlight "See the [Octopus documentation](https://octopus.com/docs/octopus-rest-api/how-to-create-an-api-key) for details on creating API keys."
Write-Highlight "Once you have an API key, add it to the $($OctopusParameters['Octopus.Step.Name']) step to enable the ability to check for deployments to blue/green environments in this space."
exit 0
}
if ([string]::IsNullOrWhiteSpace("#{BlueGreen.Environment.Blue.Name}")) {
Write-Host "The BlueGreen.Environment.Blue.Name variable has not been defined. We can not validate the deployment environment."
exit 0
}
if ([string]::IsNullOrWhiteSpace("#{BlueGreen.Environment.Green.Name}")) {
Write-Host "The BlueGreen.Environment.Green.Name variable has not been defined. We can not validate the deployment environment."
exit 0
}
$header = @{ "X-Octopus-ApiKey" = "#{BlueGreen.Octopus.Api.Key}" }
# Get environment ID
$blueEnvironmentName = "#{BlueGreen.Environment.Blue.Name}"
$blueEnvironments = Invoke-RestMethod -Uri "$octopusURL/api/#{Octopus.Space.Id}/environments?partialName=$([uri]::EscapeDataString($blueEnvironmentName))&skip=0&take=100" -Headers $header
$blueEnvironment = $blueEnvironments.Items | Where-Object { $_.Name -eq $blueEnvironmentName } | Select-Object -First 1
if ($null -eq $blueEnvironment) {
Write-Host "Could not find an environment called $blueEnvironmentName. We can not validate the deployment environment."
exit 0
}
$greenEnvironmentName = "#{BlueGreen.Environment.Green.Name}"
$greenEnvironments = Invoke-RestMethod -Uri "$octopusURL/api/#{Octopus.Space.Id}/environments?partialName=$([uri]::EscapeDataString($greenEnvironmentName))&skip=0&take=100" -Headers $header
$greenEnvironment = $greenEnvironments.Items | Where-Object { $_.Name -eq $greenEnvironmentName } | Select-Object -First 1
if ($null -eq $greenEnvironment) {
Write-Host "Could not find an environment called $greenEnvironment. We can not validate the deployment environment."
exit 0
}
# Get deployments for the environment and project, excluding the current deployment
$blueDeploymentsUri = "$octopusUrl/api/#{Octopus.Space.Id}/deployments?environments=$($blueEnvironment.Id)&projects=#{Octopus.Project.Id}&take=2"
# Scope to the current tenant if this is a tenant deployment
if ("#{Octopus.Deployment.Tenant.Id}" -ne "") {
$blueDeploymentsUri += "&tenants=#{Octopus.Deployment.Tenant.Id}"
}
$blueLatestDeployment = Invoke-RestMethod -Uri $blueDeploymentsUri -Headers $header | Select-Object -ExpandProperty Items | Where-Object { $_.Id -ne "#{Octopus.Deployment.Id}" }
$greenDeploymentsUri = "$octopusUrl/api/#{Octopus.Space.Id}/deployments?environments=$($greenEnvironment.Id)&projects=#{Octopus.Project.Id}&take=2"
# Scope to the current tenant if this is a tenant deployment
if ("#{Octopus.Deployment.Tenant.Id}" -ne "") {
$greenDeploymentsUri += "&tenants=#{Octopus.Deployment.Tenant.Id}"
}
$greenLatestDeployment = Invoke-RestMethod -Uri $greenDeploymentsUri -Headers $header | Select-Object -ExpandProperty Items | Where-Object { $_.Id -ne "#{Octopus.Deployment.Id}" }
# This is the first deployment to any environment. It doesn't matter which one we go to first.
if ($greenLatestDeployment.Length -eq 0 -and $blueLatestDeployment.Length -eq 0) {
Write-Host "Neither environment has had a deployment, so we are OK to continue"
Set-OctopusVariable -name "SequentialDeploy" -value "False"
exit 0
}
if ("#{Octopus.Environment.Name}" -eq $blueEnvironmentName) {
if ($blueLatestDeployment.Length -eq 0)
{
Write-Host "We're deploying to blue and there are no blue deployments, so we're OK to continue"
Set-OctopusVariable -name "SequentialDeploy" -value "False"
exit 0
}
# We know we have deployed to blue at least once, but if we have never deployed to green
# then we should not continue.
if ($greenLatestDeployment.Length -eq 0)
{
Write-Host "We're deploying to blue but there are no green deployments, so we should not continue"
Set-OctopusVariable -name "SequentialDeploy" -value "True"
exit 0
}
}
if ("#{Octopus.Environment.Name}" -eq $greenEnvironmentName) {
if ($greenLatestDeployment.Length -eq 0)
{
Write-Host "We're deploying to green and there are no green deployments, so we're OK to continue"
Set-OctopusVariable -name "SequentialDeploy" -value "False"
exit 0
}
# We know we have deployed to green at least once, but if we have never deployed to blue
# then we should not continue.
if ($blueLatestDeployment.Length -eq 0)
{
Write-Host "We're deploying to green but there are no blue deployments, so we should not continue"
Set-OctopusVariable -name "SequentialDeploy" -value "True"
exit 0
}
}
# At this point both blue and green have done at least one deployment. We need to check
# which environment had the last deployment.
$blueLastDeploy = [DateTimeOffset]::Parse($blueLatestDeployment[0].Created)
$greenLastDeploy = [DateTimeOffset]::Parse($greenLatestDeployment[0].Created)
Write-Host "Blue Last Deploy: $blueLastDeploy"
Write-Host "Green Last Deploy: $greenLastDeploy"
# We now check to see if the current environment has had the last deployment. If so,
# we have deployed to this environment twice in a row and we should block the deployment.
if ("#{Octopus.Environment.Name}" -eq $blueEnvironmentName -and $blueLastDeploy -gt $greenLastDeploy) {
Write-Host "The last deployment was to the blue environment, so we should not deploy to it again."
Set-OctopusVariable -name "SequentialDeploy" -value "True"
exit 0
}
if ("#{Octopus.Environment.Name}" -eq $greenEnvironmentName -and $greenLastDeploy -gt $blueLastDeploy) {
Write-Host "The last deployment was to the green environment, so we should not deploy to it again."
Set-OctopusVariable -name "SequentialDeploy" -value "True"
exit 0
}
Write-Host "We're OK to continue with the deployment."
Set-OctopusVariable -name "SequentialDeploy" -value "False"
Write-Highlight "Check the ##{Octopus.Action[#{Octopus.Step.Name}].Output.SequentialDeploy} output variable to determine if the deployment should proceed."
Provided under the Apache License version 2.0.
To use this template in Octopus Deploy, copy the JSON below and paste it into the Library → Step templates → Import dialog.
{
"Id": "72db001f-ae7f-4a0f-b952-5f80e2fc4cd2",
"Name": "Octopus - Check Blue Green Deployment",
"Description": "This step checks to ensure that deployments to blue/green environments alternate. The output variable `SequentialDeploy` is set to `True` if two deployments are done to the same environment, and `False` if they are alternating.\n\nA common scenario is to check for `SequentialDeploy` set to `True` and display a warning or the manual intervention step to confirm a deployment.",
"Version": 3,
"ExportedAt": "2025-10-14T06:35:25.515Z",
"ActionType": "Octopus.Script",
"Author": "mcasperson",
"Packages": [],
"Parameters": [
{
"Id": "825689d8-f465-4887-a8fc-b03821c82910",
"Name": "BlueGreen.Octopus.Api.Key",
"Label": "The Octopus API key",
"HelpText": "Use the documentation at https://octopus.com/docs/octopus-rest-api/how-to-create-an-api-key to create an API key.",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "Sensitive"
}
},
{
"Id": "b2535aeb-ea47-413b-a387-f2bae47137bd",
"Name": "BlueGreen.Environment.Blue.Name",
"Label": "The name of the blue environment",
"HelpText": "This is the name of the environment in Octopus that represents the blue deployment stack. It will be something like `Production - Blue`.",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "7049503a-b6a1-4ba4-b190-55b2f4508d85",
"Name": "BlueGreen.Environment.Green.Name",
"Label": "The name of the green environment",
"HelpText": "This is the name of the environment in Octopus that represents the green deployment stack. It will be something like `Production - Green`.",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
}
],
"Properties": {
"Octopus.Action.Script.ScriptBody": "# We assume that deployments to the production environments alternate between green and blue.\n# For example, if the last production deployment was to blue the next one should be to the green environment.\n# This check is used to provide a warning if a production environment is deployed to twice in a row.\n\n$octopusUrl = \"\"\n\nif ([string]::IsNullOrWhitespace(\"#{Octopus.Web.ServerUri}\"))\n{\n $octopusUrl = \"#{Octopus.Web.BaseUrl}\"\n}\nelse\n{\n $octopusUrl = \"#{Octopus.Web.ServerUri}\"\n}\n\nif (-not \"#{BlueGreen.Octopus.Api.Key}\".StartsWith(\"API-\")) {\n Write-Host \"The BlueGreen.Octopus.Api.Key variable has not been defined. We can not validate the deployment environment.\"\n Write-Highlight \"See the [Octopus documentation](https://octopus.com/docs/octopus-rest-api/how-to-create-an-api-key) for details on creating API keys.\"\n Write-Highlight \"Once you have an API key, add it to the $($OctopusParameters['Octopus.Step.Name']) step to enable the ability to check for deployments to blue/green environments in this space.\"\n exit 0\n}\n\nif ([string]::IsNullOrWhiteSpace(\"#{BlueGreen.Environment.Blue.Name}\")) {\n Write-Host \"The BlueGreen.Environment.Blue.Name variable has not been defined. We can not validate the deployment environment.\"\n exit 0\n}\n\nif ([string]::IsNullOrWhiteSpace(\"#{BlueGreen.Environment.Green.Name}\")) {\n Write-Host \"The BlueGreen.Environment.Green.Name variable has not been defined. We can not validate the deployment environment.\"\n exit 0\n}\n\n$header = @{ \"X-Octopus-ApiKey\" = \"#{BlueGreen.Octopus.Api.Key}\" }\n\n# Get environment ID\n$blueEnvironmentName = \"#{BlueGreen.Environment.Blue.Name}\"\n$blueEnvironments = Invoke-RestMethod -Uri \"$octopusURL/api/#{Octopus.Space.Id}/environments?partialName=$([uri]::EscapeDataString($blueEnvironmentName))&skip=0&take=100\" -Headers $header\n$blueEnvironment = $blueEnvironments.Items | Where-Object { $_.Name -eq $blueEnvironmentName } | Select-Object -First 1\n\nif ($null -eq $blueEnvironment) {\n Write-Host \"Could not find an environment called $blueEnvironmentName. We can not validate the deployment environment.\"\n exit 0\n}\n\n$greenEnvironmentName = \"#{BlueGreen.Environment.Green.Name}\"\n$greenEnvironments = Invoke-RestMethod -Uri \"$octopusURL/api/#{Octopus.Space.Id}/environments?partialName=$([uri]::EscapeDataString($greenEnvironmentName))&skip=0&take=100\" -Headers $header\n$greenEnvironment = $greenEnvironments.Items | Where-Object { $_.Name -eq $greenEnvironmentName } | Select-Object -First 1\n\nif ($null -eq $greenEnvironment) {\n Write-Host \"Could not find an environment called $greenEnvironment. We can not validate the deployment environment.\"\n exit 0\n}\n\n# Get deployments for the environment and project, excluding the current deployment\n$blueDeploymentsUri = \"$octopusUrl/api/#{Octopus.Space.Id}/deployments?environments=$($blueEnvironment.Id)&projects=#{Octopus.Project.Id}&take=2\"\n\n# Scope to the current tenant if this is a tenant deployment\nif (\"#{Octopus.Deployment.Tenant.Id}\" -ne \"\") {\n $blueDeploymentsUri += \"&tenants=#{Octopus.Deployment.Tenant.Id}\"\n}\n\n$blueLatestDeployment = Invoke-RestMethod -Uri $blueDeploymentsUri -Headers $header | Select-Object -ExpandProperty Items | Where-Object { $_.Id -ne \"#{Octopus.Deployment.Id}\" }\n\n$greenDeploymentsUri = \"$octopusUrl/api/#{Octopus.Space.Id}/deployments?environments=$($greenEnvironment.Id)&projects=#{Octopus.Project.Id}&take=2\"\n\n# Scope to the current tenant if this is a tenant deployment\nif (\"#{Octopus.Deployment.Tenant.Id}\" -ne \"\") {\n $greenDeploymentsUri += \"&tenants=#{Octopus.Deployment.Tenant.Id}\"\n}\n\n$greenLatestDeployment = Invoke-RestMethod -Uri $greenDeploymentsUri -Headers $header | Select-Object -ExpandProperty Items | Where-Object { $_.Id -ne \"#{Octopus.Deployment.Id}\" }\n\n# This is the first deployment to any environment. It doesn't matter which one we go to first.\nif ($greenLatestDeployment.Length -eq 0 -and $blueLatestDeployment.Length -eq 0) {\n Write-Host \"Neither environment has had a deployment, so we are OK to continue\"\n Set-OctopusVariable -name \"SequentialDeploy\" -value \"False\"\n exit 0\n}\n\nif (\"#{Octopus.Environment.Name}\" -eq $blueEnvironmentName) {\n if ($blueLatestDeployment.Length -eq 0)\n {\n Write-Host \"We're deploying to blue and there are no blue deployments, so we're OK to continue\"\n Set-OctopusVariable -name \"SequentialDeploy\" -value \"False\"\n exit 0\n }\n\n # We know we have deployed to blue at least once, but if we have never deployed to green\n # then we should not continue.\n if ($greenLatestDeployment.Length -eq 0)\n {\n Write-Host \"We're deploying to blue but there are no green deployments, so we should not continue\"\n Set-OctopusVariable -name \"SequentialDeploy\" -value \"True\"\n exit 0\n }\n}\n\nif (\"#{Octopus.Environment.Name}\" -eq $greenEnvironmentName) {\n if ($greenLatestDeployment.Length -eq 0)\n {\n Write-Host \"We're deploying to green and there are no green deployments, so we're OK to continue\"\n Set-OctopusVariable -name \"SequentialDeploy\" -value \"False\"\n exit 0\n }\n\n # We know we have deployed to green at least once, but if we have never deployed to blue\n # then we should not continue.\n if ($blueLatestDeployment.Length -eq 0)\n {\n Write-Host \"We're deploying to green but there are no blue deployments, so we should not continue\"\n Set-OctopusVariable -name \"SequentialDeploy\" -value \"True\"\n exit 0\n }\n}\n\n# At this point both blue and green have done at least one deployment. We need to check\n# which environment had the last deployment.\n$blueLastDeploy = [DateTimeOffset]::Parse($blueLatestDeployment[0].Created)\n$greenLastDeploy = [DateTimeOffset]::Parse($greenLatestDeployment[0].Created)\n\nWrite-Host \"Blue Last Deploy: $blueLastDeploy\"\nWrite-Host \"Green Last Deploy: $greenLastDeploy\"\n\n# We now check to see if the current environment has had the last deployment. If so,\n# we have deployed to this environment twice in a row and we should block the deployment.\nif (\"#{Octopus.Environment.Name}\" -eq $blueEnvironmentName -and $blueLastDeploy -gt $greenLastDeploy) {\n Write-Host \"The last deployment was to the blue environment, so we should not deploy to it again.\"\n Set-OctopusVariable -name \"SequentialDeploy\" -value \"True\"\n exit 0\n}\n\nif (\"#{Octopus.Environment.Name}\" -eq $greenEnvironmentName -and $greenLastDeploy -gt $blueLastDeploy) {\n Write-Host \"The last deployment was to the green environment, so we should not deploy to it again.\"\n Set-OctopusVariable -name \"SequentialDeploy\" -value \"True\"\n exit 0\n}\n\nWrite-Host \"We're OK to continue with the deployment.\"\nSet-OctopusVariable -name \"SequentialDeploy\" -value \"False\"\n\nWrite-Highlight \"Check the ##{Octopus.Action[#{Octopus.Step.Name}].Output.SequentialDeploy} output variable to determine if the deployment should proceed.\"",
"Octopus.Action.Script.ScriptSource": "Inline",
"Octopus.Action.Script.Syntax": "PowerShell",
"OctopusUseBundledTooling": "False"
},
"Category": "Octopus",
"HistoryUrl": "https://github.com/OctopusDeploy/Library/commits/master/step-templates/octopus-blue-green-check.json",
"Website": "/step-templates/72db001f-ae7f-4a0f-b952-5f80e2fc4cd2",
"Logo": "iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAC1QTFRFT6Tl////L5Pg8vj9Y67omsvwPJrisdfzfbzs5fL7y+T32Ov5isLucLXqvt31CJPHWwAABMJJREFUeNrs3deW4jAMAFDF3U75/89dlp0ZhiU4blJEjvQ8hYubLJsA00UCBCIQgQhEIAIRiEAEIhCBCEQgAhGIQAQiEIEIhD8kJm+t+QprfdKfB9HbYpx6CWfspj8HMi+gMgHL/AmQA8W3JTKH+ALFvzCeL0RbpyoCPE9IJeNOSQwh5Z3qd6yRGWQ2qi2cZQWxqj1WzQYSjeoJmJlAklOd4VlArOqPhQEkqBERToeMcfRJBkC0Uep8CfBpjz4JsHJ0zF3dkEWNje0kiB/sUC6eApndaIiCMyAa1PiwJ0AWhRGJHJJQHG2dC7h1rNbO1QOxSA7lNCkkKrQIpJCAB1GREILYIC1NAiwbpKFJgGWDNExcwGstfExcZBCHC6nOglshHtmhViLIig1RNBCN7qjtW8C0Z1UvJcC1Z9XmwMBzzvobmgAyEzgq91dtEEsBsQSQQAFZCSBAATEEEApHZbrVBIkkEIUPSVeB+KtALA0kXQUSrwKZBCIQBnk8Y4i5CsReBeKvkqLM+BCSDWJlrZFvGk9SRTHshkgjZCGAaArIxm3H3grhVzFlW2msfl1ca79UJ1bofYvsDHHlNdTZnlh5MghuPd5NdBDUNZHyCkfktIh03XzALGRPlBDPac7qgWjHZzWcmF5zmmkhidMQ6boKiDXcDTUEaylZqCGJ0Vjvu/fLJtHqhSANEvqb2OYqkOUqEHuVMbJcZdZCGiPhKhC4yjqiIjEE7XThMp8fAWII3mY3kUIQD+AMKQTzPiBhgQ63HlT/KSvgtoi0dq5mCPah1UIE0eh3sT0NhOByvKeAkFzi8PgQomumFhsyOxpIzZN4gLOj5plVwNpR0b2AuePWKBEHQu24pSsJA+LVCeHHQxZ1SiyDIdqok8IOhSSnTottHEQTdyt4ettAj4KkzA4dMikk2Dht2S5ptm1vswnPDxn0YyDZ5oDM3iToo2T5voWaYe+Q+vdjH80QyAzZhCgcDtLMI1Tmtz9w++XHgziHQHJJu/OZ3bs9Xn8gQ72NcP3dKqEfkp10F51xhoIi2I91R+LurXV/5q7pH+wx061CzO16oSQleMyr8fXvwMA0Pro8432DPD/ySx8XrHfSuDAM8n6UhnjQabaiXf5Bq/lREHvEeNtn1rJ08+C/uXkQZHeguxAPC3UvtcJYUogLzZX5hhZZvS6onG5lxXtzWGaygwb79vT/IXhdlNibwlKYOR6T8xjI7W8n+xV7T+GH4tMzWwR+lZhRkJYSsC0thpmCYqyngOz3rN2FLBZ2wZflBCggUHF0Vnp88JKienzIXLSEZCZqU7IKr/gQW9yx3pzV7Y9kvWZWTRRIqDmTtRUnU7b2lLcTYmoqHqnmiO1poER0SPkAeZMAZxaJx0Y3TCdAclsIqDz03ALcyxfTCZBsthoGXWmigGyVhWPLFJJfuuKQWycoEFdXbH4dJJoJxNR1eD/kshz6yn48cF8yW8sFoitflB1w6Q8n+/15Za7oA17/pYNmYgP5fmWm8L1NOHPWgK8kuFew1/JXtOA0yJCv7ah7X8ObUuT5kObU30+fDZm8+zqP+HTIpK0xQ796b5Kv2hSIQAQiEIEIRCACEYhABCIQgQhEIAIRiEAEIpBf8UeAAQAEjtYmlDTcCgAAAABJRU5ErkJggg==",
"$Meta": {
"Type": "ActionTemplate"
}
}
Page updated on Tuesday, October 14, 2025