From bcdb333b586d22dd5ab1b81407db6e91ddcbfce3 Mon Sep 17 00:00:00 2001 From: Bec Callow Date: Thu, 22 Jan 2026 12:10:38 +1000 Subject: [PATCH 1/6] Fix CLI examples --- .../cli/octopus-tenant-variables-update.mdx | 18 ++++++++++++++++-- .../cli/octopus-tenant-variables.mdx | 7 +++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables-update.mdx b/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables-update.mdx index a100b06bb7..bcd54acc5f 100644 --- a/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables-update.mdx +++ b/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables-update.mdx @@ -1,7 +1,7 @@ --- layout: src/layouts/Default.astro pubDate: 2023-01-01 -modDate: 2025-05-07 +modDate: 2026-01-20 title: octopus tenant variables update description: Update the value of a tenant variable navOrder: 145 @@ -36,9 +36,23 @@ Global Flags: ``` +# Interactive mode - prompts for all required values $ octopus tenant variables update + +# Update a project variable for a specific environment (single environment scope) $ octopus tenant variables update --tenant "Bobs Fish Shack" --name "site-name" --value "Bob's Fish Shack" --project "Awesome Web Site" --environment "Test" -$ octopus tenant variables update --tenant "Sally's Tackle Truck" --name dbPassword --value "12345" --library-variable-set "Shared Variables" + +# Update a project variable for multiple environments (multiple environment scopes) +$ octopus tenant variables update --tenant "Bobs Fish Shack" --name "database-server" --value "prod-db-01" --project "Awesome Web Site" --environment "Staging" --environment "Production" + +# Update a project variable for all environments (unscoped - omit --environment flag) +$ octopus tenant variables update --tenant "Bobs Fish Shack" --name "app-name" --value "Bobs App" --project "Awesome Web Site" + +# Update a common variable from a library variable set +$ octopus tenant variables update --tenant "Sally's Tackle Truck" --name "dbPassword" --value "12345" --library-variable-set "Shared Variables" + +# Update a common variable with environment scoping +$ octopus tenant variables update --tenant "Sally's Tackle Truck" --name "api-key" --value "prod-key-123" --library-variable-set "API Config" --environment "Production" ``` diff --git a/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables.mdx b/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables.mdx index 8436c54d78..3308e5d915 100644 --- a/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables.mdx +++ b/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables.mdx @@ -1,7 +1,7 @@ --- layout: src/layouts/Default.astro pubDate: 2023-01-01 -modDate: 2025-05-07 +modDate: 2026-01-20 title: octopus tenant variables description: Manage tenant variables navOrder: 143 @@ -38,9 +38,12 @@ Use "octopus tenant variables [command] --help" for more information about a com ``` $ octopus tenant variables list "Bobs Wood Shop" -$ octopus tenant variables update --tenant "Bobs Fish Shack" --name "site-name" --value "Bob's Fish Shack" --project "Awesome Web Site" --environment "Test" +# Update a project variable for a specific environment (single environment scope) +$ octopus tenant variables update --tenant "Bobs Fish Shack" --name "site-name" --value "Bob's Fish Shack" --project "Awesome Web Site" --environment "Test" +# Update a common variable from a library variable set for specific environments +$ octopus tenant variables update --tenant "Bobs Fish Shack" --name "company-logo" --value "bobs-logo.png" --library-variable-set "Shared Assets" --environment "Production" ``` ## Learn more From cde8fa52172d9cb2fdd0bb8b4db8a6730bdac659 Mon Sep 17 00:00:00 2001 From: Bec Callow Date: Thu, 22 Jan 2026 12:12:09 +1000 Subject: [PATCH 2/6] Replace outdated example scripts for project tenant variables --- .../tenants/update-tenant-variable.mdx | 27 +- ...tenant-project-variable-scripts.include.md | 550 ++++++++++++++++++ .../update-tenant-variable-scripts.include.md | 374 ------------ 3 files changed, 570 insertions(+), 381 deletions(-) create mode 100644 src/shared-content/scripts/update-tenant-project-variable-scripts.include.md delete mode 100644 src/shared-content/scripts/update-tenant-variable-scripts.include.md diff --git a/src/pages/docs/octopus-rest-api/examples/tenants/update-tenant-variable.mdx b/src/pages/docs/octopus-rest-api/examples/tenants/update-tenant-variable.mdx index ad56bd4d27..5c2aa79d8f 100644 --- a/src/pages/docs/octopus-rest-api/examples/tenants/update-tenant-variable.mdx +++ b/src/pages/docs/octopus-rest-api/examples/tenants/update-tenant-variable.mdx @@ -1,15 +1,16 @@ --- layout: src/layouts/Default.astro pubDate: 2023-01-01 -modDate: 2023-01-01 +modDate: 2026-01-20 title: Update tenant variables -description: An example script that updates tenant variables for a specific project template with a single value across each connected environment in Octopus using the REST API and Octopus.Client. +description: Example scripts that update tenant variables for both project variables and common (library) variables in Octopus using the REST API and Octopus.Client. --- -import UpdateTenantVariableScripts from 'src/shared-content/scripts/update-tenant-variable-scripts.include.md'; +import UpdateTenantProjectVariableScripts from 'src/shared-content/scripts/update-tenant-project-variable-scripts.include.md'; +import UpdateTenantCommonVariableScripts from 'src/shared-content/scripts/update-tenant-common-variable-scripts.include.md'; -This script demonstrates how to programmatically update tenant variables with a single value across each connected environment in Octopus. +These scripts demonstrate how to programmatically update tenant variables. -## Usage +## Update project tenant variables Provide values for: @@ -21,6 +22,18 @@ Provide values for: - The new variable value - Choose whether the new variable value is bound to an Octopus variable value e.g. `#{MyVariable}` -## Script + - +## Update common tenant variables + +Provide values for: + +- Octopus URL +- Octopus API Key +- Name of the space to use +- Name of the tenant +- Name of the Library template +- The new variable value +- Choose whether the new variable value is bound to an Octopus variable value e.g. `#{MyVariable}` + + diff --git a/src/shared-content/scripts/update-tenant-project-variable-scripts.include.md b/src/shared-content/scripts/update-tenant-project-variable-scripts.include.md new file mode 100644 index 0000000000..45963f54ab --- /dev/null +++ b/src/shared-content/scripts/update-tenant-project-variable-scripts.include.md @@ -0,0 +1,550 @@ +
+PowerShell (REST API) + +```powershell +$ErrorActionPreference = "Stop"; + +# Define working variables +$octopusURL = "https://your-octopus-url" +$octopusAPIKey = "API-YOUR-KEY" +$header = @{ "X-Octopus-ApiKey" = $octopusAPIKey } + +$spaceName = "Default" # Name of the space +$tenantName = "TenantName" # The tenant name +$projectVariableTemplateName = "ProjectTemplateName" # Choose the template name +$newValue = "NewValue" # Choose a new variable value, assumes same per environment +$NewValueIsBoundToOctopusVariable=$False # Choose $True if the $newValue is an Octopus variable e.g. #{SomeValue} + +# Get space +$space = (Invoke-RestMethod -Method Get -Uri "$octopusURL/api/spaces/all" -Headers $header) | Where-Object {$_.Name -eq $spaceName} + +# Get Tenant +$tenantsSearch = (Invoke-RestMethod -Method Get -Uri "$octopusURL/api/$($space.Id)/tenants?name=$tenantName" -Headers $header) +$tenant = $tenantsSearch.Items | Select-Object -First 1 + +# Get Project Tenant Variables (including missing variables) +$projectVariablesUri = "$octopusURL/api/$($space.Id)/tenants/$($tenant.Id)/projectvariables?includeMissingVariables=true" +$projectVariables = (Invoke-RestMethod -Method Get -Uri $projectVariablesUri -Headers $header) + +# Build update payload +$updatePayload = @{ + Variables = @() +} + +# Loop through project variables +foreach ($variable in $projectVariables.Variables) { + if ($variable.Template.Name -eq $projectVariableTemplateName) { + Write-Host "Found project variable template: $projectVariableTemplateName (Template ID: $($variable.Template.Id), Project ID: $($variable.ProjectId))" + + # Create new variable entry + $variableEntry = @{ + ProjectId = $variable.ProjectId + TemplateId = $variable.Template.Id + Scope = @{ + EnvironmentIds = $variable.Scope.EnvironmentIds + } + } + + # Handle sensitive values + if($variable.Template.DisplaySettings["Octopus.ControlType"] -eq "Sensitive") { + if($NewValueIsBoundToOctopusVariable -eq $True) { + $variableEntry.Value = $newValue + } else { + $variableEntry.Value = @{ + HasValue = $true + NewValue = $newValue + } + } + Write-Host "Updated sensitive variable for environments: $($variable.Scope.EnvironmentIds -join ', ')" + } else { + $variableEntry.Value = $newValue + Write-Host "Updated variable value to '$newValue' for environments: $($variable.Scope.EnvironmentIds -join ', ')" + } + + $updatePayload.Variables += $variableEntry + } else { + # Keep existing variables unchanged + $updatePayload.Variables += @{ + Id = $variable.Id + ProjectId = $variable.ProjectId + TemplateId = $variable.TemplateId + Value = $variable.Value + Scope = $variable.Scope + } + } +} + +# Handle variables that need to be created +if ($projectVariables.MissingVariables) { + foreach ($missingVariable in $projectVariables.MissingVariables) { + if ($missingVariable.Template.Name -eq $projectVariableTemplateName) { + Write-Host "Found missing project variable template: $projectVariableTemplateName (Template ID: $($missingVariable.Template.Id), Project ID: $($missingVariable.ProjectId))" + + # Create new variable entry for missing variable + $variableEntry = @{ + ProjectId = $missingVariable.ProjectId + TemplateId = $missingVariable.Template.Id + Scope = @{ + EnvironmentIds = $missingVariable.Scope.EnvironmentIds + } + } + + # Handle sensitive values + if($missingVariable.Template.DisplaySettings["Octopus.ControlType"] -eq "Sensitive") { + if($NewValueIsBoundToOctopusVariable -eq $True) { + $variableEntry.Value = $newValue + } else { + $variableEntry.Value = @{ + HasValue = $true + NewValue = $newValue + } + } + Write-Host "Created sensitive variable for missing template" + } else { + $variableEntry.Value = $newValue + Write-Host "Created variable value '$newValue' for missing template" + } + + $updatePayload.Variables += $variableEntry + } + } +} + +# Update project variables +Invoke-RestMethod -Method Put -Uri "$octopusURL/api/$($space.Id)/tenants/$($tenant.Id)/projectvariables" -Headers $header -Body ($updatePayload | ConvertTo-Json -Depth 10) +Write-Host "Successfully updated project tenant variables" +``` + +
+
+PowerShell (Octopus.Client) + +```powershell +# You can get this dll from your Octopus Server/Tentacle installation directory or from +# https://www.nuget.org/packages/Octopus.Client/ +Add-Type -Path 'Octopus.Client.dll' + +# Octopus variables +$octopusURL = "https://your-octopus-url" +$octopusAPIKey = "API-YOUR-KEY" + +$spaceName = "Default" # Name of the Space +$tenantName = "TenantName" # The tenant name +$projectVariableTemplateName = "ProjectTemplateName" # Choose the template Name +$newValue = "NewValue" # Choose a new variable value +$NewValueIsBoundToOctopusVariable=$False # Choose $True if the $newValue is an Octopus variable e.g. #{SomeValue} + +$endpoint = New-Object Octopus.Client.OctopusServerEndpoint $octopusURL, $octopusAPIKey +$repository = New-Object Octopus.Client.OctopusRepository $endpoint +$client = New-Object Octopus.Client.OctopusClient $endpoint + +try +{ + # Get space + $space = $repository.Spaces.FindByName($spaceName) + $spaceRepository = $client.ForSpace($space) + + # Get Tenant + $tenant = $spaceRepository.Tenants.FindByName($tenantName) + + # Get Project Tenant Variables (including missing variables) + $projectVariablesRequest = New-Object Octopus.Client.Model.TenantVariables.GetProjectVariablesByTenantIdRequest($tenant.Id, $space.Id) + $projectVariablesRequest.IncludeMissingVariables = $true + $projectVariables = $spaceRepository.TenantVariables.Get($projectVariablesRequest) + + # Build update payload + $variablesToModify = @() + + # Loop through project variables + foreach ($variable in $projectVariables.Variables) { + if ($variable.Template.Name -eq $projectVariableTemplateName) { + Write-Host "Found project variable template: $projectVariableTemplateName (Template ID: $($variable.Template.Id), Project ID: $($variable.ProjectId))" + + # Handle sensitive values + if($variable.Template.DisplaySettings["Octopus.ControlType"] -eq "Sensitive") { + if($NewValueIsBoundToOctopusVariable -eq $True) { + $newPropertyValue = New-Object Octopus.Client.Model.PropertyValueResource($newValue, $false) + } else { + $newPropertyValue = New-Object Octopus.Client.Model.PropertyValueResource + $newPropertyValue.SensitiveValue = @{ + HasValue = $true + NewValue = $newValue + } + $newPropertyValue.IsSensitive = $true + } + Write-Host "Updated sensitive variable for environments: $($variable.Scope.EnvironmentIds -join ', ')" + } else { + $newPropertyValue = New-Object Octopus.Client.Model.PropertyValueResource($newValue, $false) + Write-Host "Updated variable value to '$newValue' for environments: $($variable.Scope.EnvironmentIds -join ', ')" + } + + # Create new payload entry + $variablePayload = New-Object Octopus.Client.Model.TenantVariables.TenantProjectVariablePayload( + $variable.ProjectId, + $variable.TemplateId, + $newPropertyValue, + $variable.Scope + ) + + $variablesToModify += $variablePayload + } else { + # Keep existing variables unchanged + $variablePayload = New-Object Octopus.Client.Model.TenantVariables.TenantProjectVariablePayload( + $variable.ProjectId, + $variable.TemplateId, + $variable.Value, + $variable.Scope + ) + $variablePayload.Id = $variable.Id + + $variablesToModify += $variablePayload + } + } + + # Handle variables that need to be created + if ($projectVariables.MissingVariables) { + foreach ($missingVariable in $projectVariables.MissingVariables) { + if ($missingVariable.Template.Name -eq $projectVariableTemplateName) { + Write-Host "Found missing project variable template: $projectVariableTemplateName (Template ID: $($missingVariable.Template.Id), Project ID: $($missingVariable.ProjectId))" + + # Handle sensitive values + if($missingVariable.Template.DisplaySettings["Octopus.ControlType"] -eq "Sensitive") { + if($NewValueIsBoundToOctopusVariable -eq $True) { + $newPropertyValue = New-Object Octopus.Client.Model.PropertyValueResource($newValue, $false) + } else { + $newPropertyValue = New-Object Octopus.Client.Model.PropertyValueResource + $newPropertyValue.SensitiveValue = @{ + HasValue = $true + NewValue = $newValue + } + $newPropertyValue.IsSensitive = $true + } + Write-Host "Created sensitive variable for missing template" + } else { + $newPropertyValue = New-Object Octopus.Client.Model.PropertyValueResource($newValue, $false) + Write-Host "Created variable value '$newValue' for missing template" + } + + # Create new payload entry for missing variable + $variablePayload = New-Object Octopus.Client.Model.TenantVariables.TenantProjectVariablePayload( + $missingVariable.ProjectId, + $missingVariable.TemplateId, + $newPropertyValue, + $missingVariable.Scope + ) + + $variablesToModify += $variablePayload + } + } + } + + # Update project variables + $modifyProjectCommand = New-Object Octopus.Client.Model.TenantVariables.ModifyProjectVariablesByTenantIdCommand($tenant.Id, $space.Id, $variablesToModify) + $spaceRepository.TenantVariables.Modify($modifyProjectCommand) | Out-Null + Write-Host "Successfully updated project tenant variables" +} +catch +{ + Write-Host $_.Exception.Message +} +``` + +
+
+C# + +```csharp +// If using .net Core, be sure to add the NuGet package of System.Security.Permissions +#r "nuget: Octopus.Client" + +using Octopus.Client; +using Octopus.Client.Model; +using Octopus.Client.Model.TenantVariables; + +var octopusURL = "https://your-octopus-url"; +var octopusAPIKey = "API-YOUR-KEY"; +var spaceName = "Default"; +var tenantName = "TenantName"; +var projectVariableTemplateName = "ProjectTemplateName"; +var variableNewValue = "NewValue"; +var valueBoundToOctoVariable = false; + +// Create repository object +var endpoint = new OctopusServerEndpoint(octopusURL, octopusAPIKey); +var repository = new OctopusRepository(endpoint); +var client = new OctopusClient(endpoint); + +try +{ + // Get space + var space = repository.Spaces.FindByName(spaceName); + var repositoryForSpace = client.ForSpace(space); + + // Get Tenant + var tenant = repositoryForSpace.Tenants.FindByName(tenantName); + + // Get Project Tenant Variables (including missing variables) + var projectVariablesRequest = new GetProjectVariablesByTenantIdRequest(tenant.Id, space.Id) + { + IncludeMissingVariables = true + }; + + var projectVariables = repositoryForSpace.TenantVariables.Get(projectVariablesRequest); + + // Build update payload + var variablesToModify = new List(); + + // Loop through project variables + foreach (var variable in projectVariables.Variables) + { + if (variable.Template.Name == projectVariableTemplateName) + { + Console.WriteLine($"Found project variable template: {projectVariableTemplateName} (Template ID: {variable.Template.Id}, Project ID: {variable.ProjectId})"); + + PropertyValueResource newPropertyValue; + + // Handle sensitive values + if (variable.Template.DisplaySettings.ContainsKey("Octopus.ControlType") && + variable.Template.DisplaySettings["Octopus.ControlType"] == "Sensitive") + { + if (NewValueIsBoundToOctopusVariable) + { + newPropertyValue = new PropertyValueResource(newValue, false); + } + else + { + newPropertyValue = new PropertyValueResource(newValue, true); + } + Console.WriteLine($"Updated sensitive variable for environments: {string.Join(", ", variable.Scope.EnvironmentIds)}"); + } + else + { + newPropertyValue = new PropertyValueResource(newValue, false); + Console.WriteLine($"Updated variable value to '{newValue}' for environments: {string.Join(", ", variable.Scope.EnvironmentIds)}"); + } + + // Create new payload entry + var variablePayload = new TenantProjectVariablePayload( + variable.ProjectId, + variable.TemplateId, + newPropertyValue, + variable.Scope + ); + + variablesToModify.Add(variablePayload); + } + else + { + // Keep existing variables unchanged + var variablePayload = new TenantProjectVariablePayload( + variable.ProjectId, + variable.TemplateId, + variable.Value, + variable.Scope + ) + { + Id = variable.Id + }; + + variablesToModify.Add(variablePayload); + } + } + + // Handle variables that need to be created + if (projectVariables.MissingVariables != null) + { + foreach (var missingVariable in projectVariables.MissingVariables) + { + if (missingVariable.Template.Name == projectVariableTemplateName) + { + Console.WriteLine($"Found missing project variable template: {projectVariableTemplateName} (Template ID: {missingVariable.Template.Id}, Project ID: {missingVariable.ProjectId})"); + + PropertyValueResource newPropertyValue; + + // Handle sensitive values + if (missingVariable.Template.DisplaySettings.ContainsKey("Octopus.ControlType") && + missingVariable.Template.DisplaySettings["Octopus.ControlType"] == "Sensitive") + { + if (NewValueIsBoundToOctopusVariable) + { + newPropertyValue = new PropertyValueResource(newValue, false); + } + else + { + // For sensitive variables, use the isSensitive parameter + newPropertyValue = new PropertyValueResource(newValue, true); + } + Console.WriteLine("Created sensitive variable for missing template"); + } + else + { + newPropertyValue = new PropertyValueResource(newValue, false); + Console.WriteLine($"Created variable value '{newValue}' for missing template"); + } + + // Create new payload entry for missing variable + var variablePayload = new TenantProjectVariablePayload( + missingVariable.ProjectId, + missingVariable.TemplateId, + newPropertyValue, + missingVariable.Scope + ); + + variablesToModify.Add(variablePayload); + } + } + } + + // Update project variables + var modifyProjectCommand = new ModifyProjectVariablesByTenantIdCommand(tenant.Id, space.Id, variablesToModify.ToArray()); + repositoryForSpace.TenantVariables.Modify(modifyProjectCommand); + Console.WriteLine("Successfully updated project tenant variables"); +} +catch (Exception ex) +{ + Console.WriteLine(ex.Message); + return; +} +``` + +
+
+Python3 + +```python +import json +import requests + +def get_octopus_resource(uri, headers, skip_count = 0): + items = [] + skip_querystring = "" + + if '?' in uri: + skip_querystring = '&skip=' + else: + skip_querystring = '?skip=' + + response = requests.get((uri + skip_querystring + str(skip_count)), headers=headers) + response.raise_for_status() + + # Get results of API call + results = json.loads(response.content.decode('utf-8')) + + # Store results + if 'Items' in results.keys(): + items += results['Items'] + + # Check to see if there are more results + if (len(results['Items']) > 0) and (len(results['Items']) == results['ItemsPerPage']): + skip_count += results['ItemsPerPage'] + items += get_octopus_resource(uri, headers, skip_count) + + else: + return results + + return items + +octopus_server_uri = 'https://your-octopus-url' +octopus_api_key = 'API-YOUR-KEY' +headers = {'X-Octopus-ApiKey': octopus_api_key} +space_name = "Default" +tenant_name = "MyTenant" +project_variable_template_name = "ProjectTemplateName" +new_value = "MyValue" +new_value_bound_to_octopus_variable = False + +# Get space +uri = f'{octopus_server_uri}/api/spaces' +spaces = get_octopus_resource(uri, headers) +space = next((x for x in spaces if x['Name'] == space_name), None) + +# Get Tenant +uri = '{0}/api/{1}/tenants'.format(octopus_server_uri, space['Id']) +tenants = get_octopus_resource(uri, headers) +tenant = next((t for t in tenants if t['Name'] == tenant_name), None) + +# Get Project Tenant Variables (including missing variables) +uri = '{0}/api/{1}/tenants/{2}/projectvariables?includeMissingVariables=true'.format(octopus_server_uri, space['Id'], tenant['Id']) +project_variables = requests.get(uri, headers=headers).json() + +update_payload = { + 'Variables': [] +} + +# Loop through project variables +for variable in project_variables['Variables']: + if variable['Template']['Name'] == project_variable_template_name: + print(f"Found project variable template: {project_variable_template_name} (Template ID: {variable['Template']['Id']}, Project ID: {variable['ProjectId']})") + + # Create new variable entry + variable_entry = { + 'ProjectId': variable['ProjectId'], + 'TemplateId': variable['Template']['Id'], + 'Scope': { + 'EnvironmentIds': variable['Scope']['EnvironmentIds'] + } + } + + # Handle sensitive values + if variable['Template']['DisplaySettings'].get('Octopus.ControlType') == 'Sensitive': + if new_value_is_bound_to_octopus_variable: + variable_entry['Value'] = new_value + else: + variable_entry['Value'] = { + 'HasValue': True, + 'NewValue': new_value + } + print(f"Updated sensitive variable for environments: {', '.join(variable['Scope']['EnvironmentIds'])}") + else: + variable_entry['Value'] = new_value + print(f"Updated variable value to '{new_value}' for environments: {', '.join(variable['Scope']['EnvironmentIds'])}") + + update_payload['Variables'].append(variable_entry) + else: + # Keep existing variables unchanged + update_payload['Variables'].append({ + 'Id': variable['Id'], + 'ProjectId': variable['ProjectId'], + 'TemplateId': variable['TemplateId'], + 'Value': variable['Value'], + 'Scope': variable['Scope'] + }) + +# Handle variables that need to be created +if 'MissingVariables' in project_variables and project_variables['MissingVariables']: + for missing_variable in project_variables['MissingVariables']: + if missing_variable['Template']['Name'] == project_variable_template_name: + print(f"Found missing project variable template: {project_variable_template_name} (Template ID: {missing_variable['Template']['Id']}, Project ID: {missing_variable['ProjectId']})") + + # Create new variable entry for missing variable + variable_entry = { + 'ProjectId': missing_variable['ProjectId'], + 'TemplateId': missing_variable['Template']['Id'], + 'Scope': { + 'EnvironmentIds': missing_variable['Scope']['EnvironmentIds'] + } + } + + # Handle sensitive values + if missing_variable['Template']['DisplaySettings'].get('Octopus.ControlType') == 'Sensitive': + if new_value_is_bound_to_octopus_variable: + variable_entry['Value'] = new_value + else: + variable_entry['Value'] = { + 'HasValue': True, + 'NewValue': new_value + } + print("Created sensitive variable for missing template") + else: + variable_entry['Value'] = new_value + print(f"Created variable value '{new_value}' for missing template") + + update_payload['Variables'].append(variable_entry) + +# Update project variables +response = requests.put(f'{octopus_server_uri}/api/{space["Id"]}/tenants/{tenant["Id"]}/projectvariables', headers=headers, json=update_payload) +response.raise_for_status() +print("Successfully updated project tenant variables") +``` + +
\ No newline at end of file diff --git a/src/shared-content/scripts/update-tenant-variable-scripts.include.md b/src/shared-content/scripts/update-tenant-variable-scripts.include.md deleted file mode 100644 index 594e9f16aa..0000000000 --- a/src/shared-content/scripts/update-tenant-variable-scripts.include.md +++ /dev/null @@ -1,374 +0,0 @@ -
-PowerShell (REST API) - -```powershell -$ErrorActionPreference = "Stop"; - -# Define working variables -$octopusURL = "https://your-octopus-url" -$octopusAPIKey = "API-YOUR-KEY" -$header = @{ "X-Octopus-ApiKey" = $octopusAPIKey } - -$spaceName = "Default" # Name of the Space -$tenantName = "TenantName" # The tenant name -$variableTemplateName = "ProjectTemplateName" # Choose the template Name -$newValue = "NewValue" # Choose a new variable value, assumes same per environment -$NewValueIsBoundToOctopusVariable=$False # Choose $True if the $newValue is an Octopus variable e.g. #{SomeValue} - -# Get space -$space = (Invoke-RestMethod -Method Get -Uri "$octopusURL/api/spaces/all" -Headers $header) | Where-Object {$_.Name -eq $spaceName} - -# Get Tenant -$tenantsSearch = (Invoke-RestMethod -Method Get -Uri "$octopusURL/api/$($space.Id)/tenants?name=$tenantName" -Headers $header) -$tenant = $tenantsSearch.Items | Select-Object -First 1 - -# Get Tenant Variables -$variables = (Invoke-RestMethod -Method Get -Uri "$octopusURL/api/$($space.Id)/tenants/$($tenant.Id)/variables" -Headers $header) - -# Get project templates -$projects = $variables.ProjectVariables | Get-Member | Where-Object {$_.MemberType -eq "NoteProperty"} | Select-Object -ExpandProperty "Name" - -# Loop through each project template -foreach ($projectKey in $projects) -{ - # Get connected project - $project = $variables.ProjectVariables.$projectKey - $projectName = $project.ProjectName - Write-Host "Working on Project: $projectName ($projectKey)" - - # Get Project template ID - $variableTemplate = ($project.Templates | Where-Object Name -eq $variableTemplateName | Select-Object -First 1) - - - if($null -ne $variableTemplate) { - - $variableTemplateId = $variableTemplate.Id - $variableTemplateIsSensitiveControlType = $variableTemplate.DisplaySettings["Octopus.ControlType"] -eq "Sensitive" - - Write-Host "Found templateId for Template: $variableTemplateName = $variableTemplateId" - $projectConnectedEnvironments = $project.Variables | Get-Member | Where-Object {$_.MemberType -eq "NoteProperty"} | Select-Object -ExpandProperty "Name" - - # Loop through each of the connected environments variables - foreach($envKey in $projectConnectedEnvironments) { - # Check for Environment project template entry, and add if not present - if($null -eq $project.Variables.$envKey.$variableTemplateId) { - $project.Variables.$envKey | Add-Member -MemberType NoteProperty -Name $variableTemplateId -Value $newValue - } - - # Check sensitive control types differently - if($variableTemplateIsSensitiveControlType -eq $True) { - # If $newValue denotes an octopus variable e.g. #{SomeVar}, treat it as if it were text - if($NewValueIsBoundToOctopusVariable -eq $True) { - Write-Host "Adding in new text value (treating as octopus variable) in Environment '$envKey' for $variableTemplateName" - $project.Variables.$envKey.$variableTemplateId = $newValue - } - else { - $newSensitiveValue = [PsCustomObject]@{ - HasValue = $True - NewValue = $newValue - } - Write-Host "Adding in new sensitive value = '********' in Environment '$envKey' for $variableTemplateName" - $project.Variables.$envKey.$variableTemplateId = $newSensitiveValue - } - } - else { - Write-Host "Adding in new value = $newValue in Environment '$envKey' for $variableTemplateName" - $project.Variables.$envKey.$variableTemplateId = $newValue - } - } - } - else { - Write-Host "Couldn't find project template: $variableTemplateName for project $projectName" - } -} -# Update the variables with the new value -Invoke-RestMethod -Method Put -Uri "$octopusURL/api/$($space.Id)/tenants/$($tenant.Id)/variables" -Headers $header -Body ($variables | ConvertTo-Json -Depth 10) -``` - -
-
-PowerShell (Octopus.Client) - -```powershell -# You can get this dll from your Octopus Server/Tentacle installation directory or from -# https://www.nuget.org/packages/Octopus.Client/ -Add-Type -Path 'Octopus.Client.dll' - -# Octopus variables -$octopusURL = "https://your-octopus-url" -$octopusAPIKey = "API-YOUR-KEY" - -$spaceName = "Default" # Name of the Space -$tenantName = "TenantName" # The tenant name -$variableTemplateName = "ProjectTemplateName" # Choose the template Name -$newValue = "NewValue" # Choose a new variable value, assumes same per environment -$NewValueIsBoundToOctopusVariable=$False # Choose $True if the $newValue is an Octopus variable e.g. #{SomeValue} - -$endpoint = New-Object Octopus.Client.OctopusServerEndpoint $octopusURL, $octopusAPIKey -$repository = New-Object Octopus.Client.OctopusRepository $endpoint -$client = New-Object Octopus.Client.OctopusClient $endpoint - -try -{ - # Get space - $space = $repository.Spaces.FindByName($spaceName) - $spaceRepository = $client.ForSpace($space) - - # Get Tenant - $tenant = $spaceRepository.Tenants.FindByName($tenantName) - - # Get Tenant Variables - $variables = $spaceRepository.Tenants.GetVariables($tenant) - - # Loop through each Project Template - foreach($projectKey in $variables.ProjectVariables.Keys) - { - # Get connected project - $project = $variables.ProjectVariables[$projectKey] - $projectName = $project.ProjectName - Write-Host "Working on Project: $projectName ($projectKey)" - - # Get Project template ID - $variableTemplate = ($project.Templates | Where-Object Name -eq $variableTemplateName | Select-Object -First 1) - $variableTemplateId = $variableTemplate.Id - $variableTemplateIsSensitiveControlType = $variableTemplate.DisplaySettings["Octopus.ControlType"] -eq "Sensitive" - - if($null -ne $variableTemplateId) { - - Write-Host "Found templateId for Template: $variableTemplateName = $variableTemplateId" - - # Loop through each of the connected environments variables - foreach($envKey in $project.Variables.Keys) { - - # Set null value in case not set - $project.Variables[$envKey][$variableTemplateId] = $null - - # Check sensitive control types differently - if($variableTemplateIsSensitiveControlType -eq $True) { - - # If $newValue denotes an octopus variable e.g. #{SomeVar}, treat it as if it were text - if($NewValueIsBoundToOctopusVariable -eq $True) { - Write-Host "Adding in new text value (treating as octopus variable) in Environment '$envKey' for $variableTemplateName" - $project.Variables[$envKey][$variableTemplateId] = New-Object Octopus.Client.Model.PropertyValueResource $newValue - } - else { - Write-Host "Adding in new sensitive value = '********' in Environment '$envKey' for $variableTemplateName" - $sensitiveValue = New-Object Octopus.Client.Model.SensitiveValue - $sensitiveValue.HasValue = $True - $sensitiveValue.NewValue = $newValue - $project.Variables[$envKey][$variableTemplateId] = $sensitiveValue - } - } - else { - Write-Host "Adding in new value = $newValue in Environment '$envKey' for $variableTemplateName" - $project.Variables[$envKey][$variableTemplateId] = New-Object Octopus.Client.Model.PropertyValueResource $newValue - } - } - } - else { - Write-Host "Couldn't find project template: $variableTemplateName for project $projectName" - } - } - - # Update the variables with the new value - $spaceRepository.Tenants.ModifyVariables($tenant, $variables) | Out-Null -} -catch -{ - Write-Host $_.Exception.Message -} -``` - -
-
-C# - -```csharp -// If using .net Core, be sure to add the NuGet package of System.Security.Permissions -#r "nuget: Octopus.Client" - -using Octopus.Client; -using Octopus.Client.Model; - -var octopusURL = "https://your-octopus-url"; -var octopusAPIKey = "API-YOUR-KEY"; -var spaceName = "Default"; -var tenantName = "TenantName"; -var projectVariableTemplateName = "TemplateName"; -var variableNewValue = "NewValue"; -var valueBoundToOctoVariable = true; - -// Create repository object -var endpoint = new OctopusServerEndpoint(octopusURL, octopusAPIKey); -var repository = new OctopusRepository(endpoint); -var client = new OctopusClient(endpoint); - -try -{ - // Get space - var space = repository.Spaces.FindByName(spaceName); - var repositoryForSpace = client.ForSpace(space); - - // Get tenant - var tenant = repositoryForSpace.Tenants.FindByName(tenantName); - - // Get tenant variables - var variables = repositoryForSpace.Tenants.GetVariables(tenant); - - // Loop through tenant variables - foreach (var projectKey in variables.ProjectVariables.Keys) - { - var project = variables.ProjectVariables[projectKey]; - var projectName = project.ProjectName; - Console.WriteLine("Working on Project: {0} ({1})", projectName, projectKey); - - // Get project template ID. - var variableTemplateResource = project.Templates.FirstOrDefault(t => t.Name == projectVariableTemplateName); - - if (variableTemplateResource != null) - { - var variableTemplateId = variableTemplateResource.Id; - var variableTemplateIsSensitiveControlType = (variableTemplateResource.DisplaySettings.FirstOrDefault(ds => ds.Key == "Octopus.ControlType")).Value == "Sensitive"; - Console.WriteLine("Found templateid for template: {0} of {1}", projectVariableTemplateName, variableTemplateId); - - // Loop through each of the connected environments - foreach (var envKey in project.Variables.Keys) - { - // Set null value in case not set - project.Variables[envKey][variableTemplateId] = null; - - if (variableTemplateIsSensitiveControlType == true) - { - if (valueBoundToOctoVariable == true) - { - Console.WriteLine("Adding in new text value (treating as octopus variable) in Environment '{0}' for {1}", envKey, projectVariableTemplateName); - project.Variables[envKey][variableTemplateId] = new PropertyValueResource(variableNewValue); - } - else - { - Console.WriteLine("Adding in new sensitive value = '********' in Environment '{0}' for {1}", envKey, projectVariableTemplateName); - var sensitiveValue = new SensitiveValue { HasValue = true, NewValue = variableNewValue }; - project.Variables[envKey][variableTemplateId] = new PropertyValueResource(sensitiveValue); - } - } - else - { - //Write-Host "Adding in new value = $newValue in Environment '$envKey' for $variableTemplateName" - Console.WriteLine("Adding in new value = '{0}' in Environment '{1}' for {2}", variableNewValue, envKey, projectVariableTemplateName); - project.Variables[envKey][variableTemplateId] = new PropertyValueResource(variableNewValue); - } - } - } - else - { - Console.WriteLine("Couldn't find project template: {0} for project {1}", projectVariableTemplateName, projectName); - } - } - - // Update the variables with the new value - repositoryForSpace.Tenants.ModifyVariables(tenant, variables); -} -catch (Exception ex) -{ - Console.WriteLine(ex.Message); - return; -} -``` - -
-
-Python3 - -```python -import json -import requests -from requests.api import get, head - -def get_octopus_resource(uri, headers, skip_count = 0): - items = [] - skip_querystring = "" - - if '?' in uri: - skip_querystring = '&skip=' - else: - skip_querystring = '?skip=' - - response = requests.get((uri + skip_querystring + str(skip_count)), headers=headers) - response.raise_for_status() - - # Get results of API call - results = json.loads(response.content.decode('utf-8')) - - # Store results - if 'Items' in results.keys(): - items += results['Items'] - - # Check to see if there are more results - if (len(results['Items']) > 0) and (len(results['Items']) == results['ItemsPerPage']): - skip_count += results['ItemsPerPage'] - items += get_octopus_resource(uri, headers, skip_count) - - else: - return results - - - # return results - return items - -octopus_server_uri = 'https://your-octopus-url' -octopus_api_key = 'API-YOUR-KEY' -headers = {'X-Octopus-ApiKey': octopus_api_key} -space_name = "Default" -tenant_name = "MyTenant" -variable_template_name = "Tenant.Site.HostName" -new_value = "MyValue" -new_value_bound_to_octopus_variable = False - -# Get space -uri = '{0}/api/spaces'.format(octopus_server_uri) -spaces = get_octopus_resource(uri, headers) -space = next((x for x in spaces if x['Name'] == space_name), None) - -# Get tenants -uri = '{0}/api/{1}/tenants'.format(octopus_server_uri, space['Id']) -tenants = get_octopus_resource(uri, headers) -tenant = next((t for t in tenants if t['Name'] == tenant_name), None) - -# Get tenant variables -uri = '{0}/api/{1}/tenants/{2}/variables'.format(octopus_server_uri, space['Id'], tenant['Id']) -tenant_variables = get_octopus_resource(uri, headers) -variable_template = None - -# Loop through connected projects -for projectKey in tenant_variables['ProjectVariables']: - templates = tenant_variables['ProjectVariables'][projectKey]['Templates'] - - # Loop through the project templates - for template in templates: - is_sensitive = (template['DisplaySettings']['Octopus.ControlType'] == 'Sensitive') - if template['Name'] == variable_template_name: - variable_template = template - break - - if variable_template != None: - # Loop through connected environments - environment_variables = tenant_variables['ProjectVariables'][projectKey]['Variables'] - - for environment_variable in environment_variables: - variables = tenant_variables['ProjectVariables'][projectKey]['Variables'][environment_variable] - if is_sensitive: - new_sensitive_variable = { - 'HasValue': True, - 'NewValue': new_value_bound_to_octopus_variable - } - variables[variable_template['Id']] = new_sensitive_variable - else: - variables[variable_template['Id']] = new_value - -# Update the tenants variables -uri = '{0}/api/{1}/tenants/{2}/variables'.format(octopus_server_uri, space['Id'], tenant['Id']) -response = requests.put(uri, headers=headers, json=tenant_variables) -response.raise_for_status() -``` - -
\ No newline at end of file From ece50b27d41c097a9f118d3ad1811fd1b30a09df Mon Sep 17 00:00:00 2001 From: Bec Callow Date: Thu, 22 Jan 2026 14:34:28 +1000 Subject: [PATCH 3/6] Add common tenant variable scripts --- ...-tenant-common-variable-scripts.include.md | 539 ++++++++++++++++++ 1 file changed, 539 insertions(+) create mode 100644 src/shared-content/scripts/update-tenant-common-variable-scripts.include.md diff --git a/src/shared-content/scripts/update-tenant-common-variable-scripts.include.md b/src/shared-content/scripts/update-tenant-common-variable-scripts.include.md new file mode 100644 index 0000000000..74b717ef0a --- /dev/null +++ b/src/shared-content/scripts/update-tenant-common-variable-scripts.include.md @@ -0,0 +1,539 @@ +
+PowerShell (REST API) + +```powershell +$ErrorActionPreference = "Stop"; + +# Define working variables +$octopusURL = "https://your-octopus-url" +$octopusAPIKey = "API-YOUR-KEY" +$header = @{ "X-Octopus-ApiKey" = $octopusAPIKey } + +$spaceName = "Default" # Name of the space +$tenantName = "TenantName" # The tenant name +$commonVariableTemplateName = "CommonTemplateName" # Choose the template name +$newValue = "NewValue" # Choose a new variable value, assumes same per environment +$NewValueIsBoundToOctopusVariable=$False # Choose $True if the $newValue is an Octopus variable e.g. #{SomeValue} + +# Get space +$space = (Invoke-RestMethod -Method Get -Uri "$octopusURL/api/spaces/all" -Headers $header) | Where-Object {$_.Name -eq $spaceName} + +# Get Tenant +$tenantsSearch = (Invoke-RestMethod -Method Get -Uri "$octopusURL/api/$($space.Id)/tenants?name=$tenantName" -Headers $header) +$tenant = $tenantsSearch.Items | Select-Object -First 1 + +# Get Common Tenant Variables (including missing variables) +$commonVariablesUri = "$octopusURL/api/$($space.Id)/tenants/$($tenant.Id)/commonvariables?includeMissingVariables=true" +$commonVariables = (Invoke-RestMethod -Method Get -Uri $commonVariablesUri -Headers $header) + +# Build update payload +$updatePayload = @{ + Variables = @() +} + +# Loop through common variables +foreach ($variable in $commonVariables.Variables) { + if ($variable.Template.Name -eq $commonVariableTemplateName) { + Write-Host "Found common variable template: $commonVariableTemplateName (Template ID: $($variable.Template.Id), Library Variable Set ID: $($variable.LibraryVariableSetId))" + + # Create new variable entry + $variableEntry = @{ + LibraryVariableSetId = $variable.LibraryVariableSetId + TemplateId = $variable.Template.Id + Scope = @{ + EnvironmentIds = $variable.Scope.EnvironmentIds + } + } + + # Handle sensitive values + if($variable.Template.DisplaySettings["Octopus.ControlType"] -eq "Sensitive") { + if($NewValueIsBoundToOctopusVariable -eq $True) { + $variableEntry.Value = $newValue + } else { + $variableEntry.Value = @{ + HasValue = $true + NewValue = $newValue + } + } + Write-Host "Updated sensitive variable for environments: $($variable.Scope.EnvironmentIds -join ', ')" + } else { + $variableEntry.Value = $newValue + Write-Host "Updated variable value to '$newValue' for environments: $($variable.Scope.EnvironmentIds -join ', ')" + } + + $updatePayload.Variables += $variableEntry + } else { + # Keep existing variables unchanged + $updatePayload.Variables += @{ + Id = $variable.Id + LibraryVariableSetId = $variable.LibraryVariableSetId + TemplateId = $variable.TemplateId + Value = $variable.Value + Scope = $variable.Scope + } + } +} + +# Handle variables that need to be created +if ($commonVariables.MissingVariables) { + foreach ($missingVariable in $commonVariables.MissingVariables) { + if ($missingVariable.Template.Name -eq $commonVariableTemplateName) { + Write-Host "Found missing common variable template: $commonVariableTemplateName (Template ID: $($missingVariable.Template.Id), Library Variable Set ID: $($missingVariable.LibraryVariableSetId))" + + # Create new variable entry for missing variable + $variableEntry = @{ + LibraryVariableSetId = $missingVariable.LibraryVariableSetId + TemplateId = $missingVariable.Template.Id + Scope = @{ + EnvironmentIds = $missingVariable.Scope.EnvironmentIds + } + } + + # Handle sensitive values + if($missingVariable.Template.DisplaySettings["Octopus.ControlType"] -eq "Sensitive") { + if($NewValueIsBoundToOctopusVariable -eq $True) { + $variableEntry.Value = $newValue + } else { + $variableEntry.Value = @{ + HasValue = $true + NewValue = $newValue + } + } + Write-Host "Created sensitive variable for missing template" + } else { + $variableEntry.Value = $newValue + Write-Host "Created variable value '$newValue' for missing template" + } + + $updatePayload.Variables += $variableEntry + } + } +} + +# Update common variables +Invoke-RestMethod -Method Put -Uri "$octopusURL/api/$($space.Id)/tenants/$($tenant.Id)/commonvariables" -Headers $header -Body ($updatePayload | ConvertTo-Json -Depth 10) +Write-Host "Successfully updated common tenant variables" +``` + +
+
+PowerShell (Octopus.Client) + +```powershell +# You can get this dll from your Octopus Server/Tentacle installation directory or from +# https://www.nuget.org/packages/Octopus.Client/ +Add-Type -Path 'Octopus.Client.dll' + +# Octopus variables +$octopusURL = "https://your-octopus-url" +$octopusAPIKey = "API-YOUR-KEY" + +$spaceName = "Default" # Name of the Space +$tenantName = "TenantName" # The tenant name +$commonVariableTemplateName = "CommonTemplateName" # Choose the template Name +$newValue = "NewValue" # Choose a new variable value +$NewValueIsBoundToOctopusVariable=$False # Choose $True if the $newValue is an Octopus variable e.g. #{SomeValue} + +$endpoint = New-Object Octopus.Client.OctopusServerEndpoint $octopusURL, $octopusAPIKey +$repository = New-Object Octopus.Client.OctopusRepository $endpoint +$client = New-Object Octopus.Client.OctopusClient $endpoint + +try +{ + # Get space + $space = $repository.Spaces.FindByName($spaceName) + $spaceRepository = $client.ForSpace($space) + + # Get Tenant + $tenant = $spaceRepository.Tenants.FindByName($tenantName) + + # Get Common Tenant Variables (including missing variables) + $commonVariablesRequest = New-Object Octopus.Client.Model.TenantVariables.GetCommonVariablesByTenantIdRequest($tenant.Id, $space.Id) + $commonVariablesRequest.IncludeMissingVariables = $true + $commonVariables = $spaceRepository.TenantVariables.Get($commonVariablesRequest) + + # Build update payload + $variablesToModify = @() + + # Loop through common variables + foreach ($variable in $commonVariables.Variables) { + if ($variable.Template.Name -eq $commonVariableTemplateName) { + Write-Host "Found common variable template: $commonVariableTemplateName (Template ID: $($variable.Template.Id), Library Variable Set ID: $($variable.LibraryVariableSetId))" + + # Handle sensitive values + if($variable.Template.DisplaySettings["Octopus.ControlType"] -eq "Sensitive") { + if($NewValueIsBoundToOctopusVariable -eq $True) { + $newPropertyValue = New-Object Octopus.Client.Model.PropertyValueResource($newValue, $false) + } else { + $newPropertyValue = New-Object Octopus.Client.Model.PropertyValueResource($newValue, $true) + } + Write-Host "Updated sensitive variable for environments: $($variable.Scope.EnvironmentIds -join ', ')" + } else { + $newPropertyValue = New-Object Octopus.Client.Model.PropertyValueResource($newValue, $false) + Write-Host "Updated variable value to '$newValue' for environments: $($variable.Scope.EnvironmentIds -join ', ')" + } + + # Create new payload entry + $variablePayload = New-Object Octopus.Client.Model.TenantVariables.TenantCommonVariablePayload( + $variable.LibraryVariableSetId, + $variable.TemplateId, + $newPropertyValue, + $variable.Scope + ) + + $variablesToModify += $variablePayload + } else { + # Keep existing variables unchanged + $variablePayload = New-Object Octopus.Client.Model.TenantVariables.TenantCommonVariablePayload( + $variable.LibraryVariableSetId, + $variable.TemplateId, + $variable.Value, + $variable.Scope + ) + $variablePayload.Id = $variable.Id + + $variablesToModify += $variablePayload + } + } + + # Handle variables that need to be created + if ($commonVariables.MissingVariables) { + foreach ($missingVariable in $commonVariables.MissingVariables) { + if ($missingVariable.Template.Name -eq $commonVariableTemplateName) { + Write-Host "Found missing common variable template: $commonVariableTemplateName (Template ID: $($missingVariable.Template.Id), Library Variable Set ID: $($missingVariable.LibraryVariableSetId))" + + # Handle sensitive values + if($missingVariable.Template.DisplaySettings["Octopus.ControlType"] -eq "Sensitive") { + if($NewValueIsBoundToOctopusVariable -eq $True) { + $newPropertyValue = New-Object Octopus.Client.Model.PropertyValueResource($newValue, $false) + } else { + $newPropertyValue = New-Object Octopus.Client.Model.PropertyValueResource($newValue, $true) + } + Write-Host "Created sensitive variable for missing template" + } else { + $newPropertyValue = New-Object Octopus.Client.Model.PropertyValueResource($newValue, $false) + Write-Host "Created variable value '$newValue' for missing template" + } + + # Create new payload entry for missing variable + $variablePayload = New-Object Octopus.Client.Model.TenantVariables.TenantCommonVariablePayload( + $missingVariable.LibraryVariableSetId, + $missingVariable.TemplateId, + $newPropertyValue, + $missingVariable.Scope + ) + + $variablesToModify += $variablePayload + } + } + } + + # Update common variables + $modifyCommonCommand = New-Object Octopus.Client.Model.TenantVariables.ModifyCommonVariablesByTenantIdCommand($tenant.Id, $space.Id, $variablesToModify) + $spaceRepository.TenantVariables.Modify($modifyCommonCommand) | Out-Null + Write-Host "Successfully updated common tenant variables" +} +catch +{ + Write-Host $_.Exception.Message +} +``` + +
+
+C# + +```csharp +// If using .net Core, be sure to add the NuGet package of System.Security.Permissions +#r "nuget: Octopus.Client" + +using Octopus.Client; +using Octopus.Client.Model; +using Octopus.Client.Model.TenantVariables; + +var octopusURL = "https://your-octopus-url"; +var octopusAPIKey = "API-YOUR-KEY"; +var spaceName = "Default"; +var tenantName = "TenantName"; +var commonVariableTemplateName = "CommonTemplateName"; +var variableNewValue = "NewValue"; +var valueBoundToOctoVariable = false; + +// Create repository object +var endpoint = new OctopusServerEndpoint(octopusURL, octopusAPIKey); +var repository = new OctopusRepository(endpoint); +var client = new OctopusClient(endpoint); + +try +{ + // Get space + var space = repository.Spaces.FindByName(spaceName); + var repositoryForSpace = client.ForSpace(space); + + // Get Tenant + var tenant = repositoryForSpace.Tenants.FindByName(tenantName); + + // Get Common Tenant Variables (including missing variables) + var commonVariablesRequest = new GetCommonVariablesByTenantIdRequest(tenant.Id, space.Id) + { + IncludeMissingVariables = true + }; + + var commonVariables = repositoryForSpace.TenantVariables.Get(commonVariablesRequest); + + // Build update payload + var variablesToModify = new List(); + + // Loop through common variables + foreach (var variable in commonVariables.Variables) + { + if (variable.Template.Name == commonVariableTemplateName) + { + Console.WriteLine($"Found common variable template: {commonVariableTemplateName} (Template ID: {variable.Template.Id}, Library Variable Set ID: {variable.LibraryVariableSetId})"); + + PropertyValueResource newPropertyValue; + + // Handle sensitive values + if (variable.Template.DisplaySettings.ContainsKey("Octopus.ControlType") && + variable.Template.DisplaySettings["Octopus.ControlType"] == "Sensitive") + { + if (valueBoundToOctoVariable) + { + newPropertyValue = new PropertyValueResource(variableNewValue, false); + } + else + { + newPropertyValue = new PropertyValueResource(variableNewValue, true); + } + Console.WriteLine($"Updated sensitive variable for environments: {string.Join(", ", variable.Scope.EnvironmentIds)}"); + } + else + { + newPropertyValue = new PropertyValueResource(variableNewValue, false); + Console.WriteLine($"Updated variable value to '{variableNewValue}' for environments: {string.Join(", ", variable.Scope.EnvironmentIds)}"); + } + + // Create new payload entry + var variablePayload = new TenantCommonVariablePayload( + variable.LibraryVariableSetId, + variable.TemplateId, + newPropertyValue, + variable.Scope + ); + + variablesToModify.Add(variablePayload); + } + else + { + // Keep existing variables unchanged + var variablePayload = new TenantCommonVariablePayload( + variable.LibraryVariableSetId, + variable.TemplateId, + variable.Value, + variable.Scope + ) + { + Id = variable.Id + }; + + variablesToModify.Add(variablePayload); + } + } + + // Handle variables that need to be created + if (commonVariables.MissingVariables != null) + { + foreach (var missingVariable in commonVariables.MissingVariables) + { + if (missingVariable.Template.Name == commonVariableTemplateName) + { + Console.WriteLine($"Found missing common variable template: {commonVariableTemplateName} (Template ID: {missingVariable.Template.Id}, Library Variable Set ID: {missingVariable.LibraryVariableSetId})"); + + PropertyValueResource newPropertyValue; + + // Handle sensitive values + if (missingVariable.Template.DisplaySettings.ContainsKey("Octopus.ControlType") && + missingVariable.Template.DisplaySettings["Octopus.ControlType"] == "Sensitive") + { + if (valueBoundToOctoVariable) + { + newPropertyValue = new PropertyValueResource(variableNewValue, false); + } + else + { + newPropertyValue = new PropertyValueResource(variableNewValue, true); + } + Console.WriteLine("Created sensitive variable for missing template"); + } + else + { + newPropertyValue = new PropertyValueResource(variableNewValue, false); + Console.WriteLine($"Created variable value '{variableNewValue}' for missing template"); + } + + // Create new payload entry for missing variable + var variablePayload = new TenantCommonVariablePayload( + missingVariable.LibraryVariableSetId, + missingVariable.TemplateId, + newPropertyValue, + missingVariable.Scope + ); + + variablesToModify.Add(variablePayload); + } + } + } + + // Update common variables + var modifyCommonCommand = new ModifyCommonVariablesByTenantIdCommand(tenant.Id, space.Id, variablesToModify.ToArray()); + repositoryForSpace.TenantVariables.Modify(modifyCommonCommand); + Console.WriteLine("Successfully updated common tenant variables"); +} +catch (Exception ex) +{ + Console.WriteLine(ex.Message); + return; +} +``` + +
+
+Python3 + +```python +import json +import requests + +def get_octopus_resource(uri, headers, skip_count = 0): + items = [] + skip_querystring = "" + + if '?' in uri: + skip_querystring = '&skip=' + else: + skip_querystring = '?skip=' + + response = requests.get((uri + skip_querystring + str(skip_count)), headers=headers) + response.raise_for_status() + + # Get results of API call + results = json.loads(response.content.decode('utf-8')) + + # Store results + if 'Items' in results.keys(): + items += results['Items'] + + # Check to see if there are more results + if (len(results['Items']) > 0) and (len(results['Items']) == results['ItemsPerPage']): + skip_count += results['ItemsPerPage'] + items += get_octopus_resource(uri, headers, skip_count) + + else: + return results + + return items + +octopus_server_uri = 'https://your-octopus-url' +octopus_api_key = 'API-YOUR-KEY' +headers = {'X-Octopus-ApiKey': octopus_api_key} +space_name = "Default" +tenant_name = "MyTenant" +common_variable_template_name = "CommonTemplateName" +new_value = "MyValue" +new_value_bound_to_octopus_variable = False + +# Get space +uri = f'{octopus_server_uri}/api/spaces' +spaces = get_octopus_resource(uri, headers) +space = next((x for x in spaces if x['Name'] == space_name), None) + +# Get Tenant +uri = '{0}/api/{1}/tenants'.format(octopus_server_uri, space['Id']) +tenants = get_octopus_resource(uri, headers) +tenant = next((t for t in tenants if t['Name'] == tenant_name), None) + +# Get Common Tenant Variables (including missing variables) +uri = '{0}/api/{1}/tenants/{2}/commonvariables?includeMissingVariables=true'.format(octopus_server_uri, space['Id'], tenant['Id']) +common_variables = requests.get(uri, headers=headers).json() + +update_payload = { + 'Variables': [] +} + +# Loop through common variables +for variable in common_variables['Variables']: + if variable['Template']['Name'] == common_variable_template_name: + print(f"Found common variable template: {common_variable_template_name} (Template ID: {variable['Template']['Id']}, Library Variable Set ID: {variable['LibraryVariableSetId']})") + + # Create new variable entry + variable_entry = { + 'LibraryVariableSetId': variable['LibraryVariableSetId'], + 'TemplateId': variable['Template']['Id'], + 'Scope': { + 'EnvironmentIds': variable['Scope']['EnvironmentIds'] + } + } + + # Handle sensitive values + if variable['Template']['DisplaySettings'].get('Octopus.ControlType') == 'Sensitive': + if new_value_bound_to_octopus_variable: + variable_entry['Value'] = new_value + else: + variable_entry['Value'] = { + 'HasValue': True, + 'NewValue': new_value + } + print(f"Updated sensitive variable for environments: {', '.join(variable['Scope']['EnvironmentIds'])}") + else: + variable_entry['Value'] = new_value + print(f"Updated variable value to '{new_value}' for environments: {', '.join(variable['Scope']['EnvironmentIds'])}") + + update_payload['Variables'].append(variable_entry) + else: + # Keep existing variables unchanged + update_payload['Variables'].append({ + 'Id': variable['Id'], + 'LibraryVariableSetId': variable['LibraryVariableSetId'], + 'TemplateId': variable['TemplateId'], + 'Value': variable['Value'], + 'Scope': variable['Scope'] + }) + +# Handle variables that need to be created +if 'MissingVariables' in common_variables and common_variables['MissingVariables']: + for missing_variable in common_variables['MissingVariables']: + if missing_variable['Template']['Name'] == common_variable_template_name: + print(f"Found missing common variable template: {common_variable_template_name} (Template ID: {missing_variable['Template']['Id']}, Library Variable Set ID: {missing_variable['LibraryVariableSetId']})") + + # Create new variable entry for missing variable + variable_entry = { + 'LibraryVariableSetId': missing_variable['LibraryVariableSetId'], + 'TemplateId': missing_variable['Template']['Id'], + 'Scope': { + 'EnvironmentIds': missing_variable['Scope']['EnvironmentIds'] + } + } + + # Handle sensitive values + if missing_variable['Template']['DisplaySettings'].get('Octopus.ControlType') == 'Sensitive': + if new_value_bound_to_octopus_variable: + variable_entry['Value'] = new_value + else: + variable_entry['Value'] = { + 'HasValue': True, + 'NewValue': new_value + } + print("Created sensitive variable for missing template") + else: + variable_entry['Value'] = new_value + print(f"Created variable value '{new_value}' for missing template") + + update_payload['Variables'].append(variable_entry) + +# Update common variables +response = requests.put(f'{octopus_server_uri}/api/{space["Id"]}/tenants/{tenant["Id"]}/commonvariables', headers=headers, json=update_payload) +response.raise_for_status() +print("Successfully updated common tenant variables") +``` + +
\ No newline at end of file From fa5dfe133951b36396a206de4c8e61f5b2fb7c0f Mon Sep 17 00:00:00 2001 From: Bec Callow Date: Thu, 22 Jan 2026 14:55:37 +1000 Subject: [PATCH 4/6] Fix lint --- .../octopus-rest-api/cli/octopus-tenant-variables-update.mdx | 4 ++-- .../docs/octopus-rest-api/cli/octopus-tenant-variables.mdx | 4 ++-- .../scripts/update-tenant-common-variable-scripts.include.md | 2 +- .../scripts/update-tenant-project-variable-scripts.include.md | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables-update.mdx b/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables-update.mdx index bcd54acc5f..2c145dbc74 100644 --- a/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables-update.mdx +++ b/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables-update.mdx @@ -10,7 +10,7 @@ import SamplesInstance from 'src/shared-content/samples/samples-instance.include Update the value of a tenant variable in Octopus Deploy -``` +```text Usage: octopus tenant variables update [flags] @@ -35,7 +35,7 @@ Global Flags: -``` +```bash # Interactive mode - prompts for all required values $ octopus tenant variables update diff --git a/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables.mdx b/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables.mdx index 3308e5d915..3272ff87b2 100644 --- a/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables.mdx +++ b/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables.mdx @@ -10,7 +10,7 @@ import SamplesInstance from 'src/shared-content/samples/samples-instance.include Manage tenant variables in Octopus Deploy -``` +```text Usage: octopus tenant variables [command] @@ -36,7 +36,7 @@ Use "octopus tenant variables [command] --help" for more information about a com -``` +```bash $ octopus tenant variables list "Bobs Wood Shop" # Update a project variable for a specific environment (single environment scope) diff --git a/src/shared-content/scripts/update-tenant-common-variable-scripts.include.md b/src/shared-content/scripts/update-tenant-common-variable-scripts.include.md index 74b717ef0a..e7fb1eab97 100644 --- a/src/shared-content/scripts/update-tenant-common-variable-scripts.include.md +++ b/src/shared-content/scripts/update-tenant-common-variable-scripts.include.md @@ -536,4 +536,4 @@ response.raise_for_status() print("Successfully updated common tenant variables") ``` - \ No newline at end of file + diff --git a/src/shared-content/scripts/update-tenant-project-variable-scripts.include.md b/src/shared-content/scripts/update-tenant-project-variable-scripts.include.md index 45963f54ab..2185028c92 100644 --- a/src/shared-content/scripts/update-tenant-project-variable-scripts.include.md +++ b/src/shared-content/scripts/update-tenant-project-variable-scripts.include.md @@ -547,4 +547,4 @@ response.raise_for_status() print("Successfully updated project tenant variables") ``` - \ No newline at end of file + From e6af84022553a41c76ec59f13a9a627c42a0224c Mon Sep 17 00:00:00 2001 From: Bec Callow Date: Thu, 22 Jan 2026 16:03:32 +1000 Subject: [PATCH 5/6] Use consistent naming --- ...-tenant-common-variable-scripts.include.md | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/shared-content/scripts/update-tenant-common-variable-scripts.include.md b/src/shared-content/scripts/update-tenant-common-variable-scripts.include.md index e7fb1eab97..b0e46409bb 100644 --- a/src/shared-content/scripts/update-tenant-common-variable-scripts.include.md +++ b/src/shared-content/scripts/update-tenant-common-variable-scripts.include.md @@ -256,8 +256,8 @@ var octopusAPIKey = "API-YOUR-KEY"; var spaceName = "Default"; var tenantName = "TenantName"; var commonVariableTemplateName = "CommonTemplateName"; -var variableNewValue = "NewValue"; -var valueBoundToOctoVariable = false; +var newValue = "NewValue"; +var newValueIsBoundToOctopusVariable = false; // Create repository object var endpoint = new OctopusServerEndpoint(octopusURL, octopusAPIKey); @@ -297,20 +297,20 @@ try if (variable.Template.DisplaySettings.ContainsKey("Octopus.ControlType") && variable.Template.DisplaySettings["Octopus.ControlType"] == "Sensitive") { - if (valueBoundToOctoVariable) + if (newValueIsBoundToOctopusVariable) { - newPropertyValue = new PropertyValueResource(variableNewValue, false); + newPropertyValue = new PropertyValueResource(newValue, false); } else { - newPropertyValue = new PropertyValueResource(variableNewValue, true); + newPropertyValue = new PropertyValueResource(newValue, true); } Console.WriteLine($"Updated sensitive variable for environments: {string.Join(", ", variable.Scope.EnvironmentIds)}"); } else { - newPropertyValue = new PropertyValueResource(variableNewValue, false); - Console.WriteLine($"Updated variable value to '{variableNewValue}' for environments: {string.Join(", ", variable.Scope.EnvironmentIds)}"); + newPropertyValue = new PropertyValueResource(newValue, false); + Console.WriteLine($"Updated variable value to '{newValue}' for environments: {string.Join(", ", variable.Scope.EnvironmentIds)}"); } // Create new payload entry @@ -355,20 +355,20 @@ try if (missingVariable.Template.DisplaySettings.ContainsKey("Octopus.ControlType") && missingVariable.Template.DisplaySettings["Octopus.ControlType"] == "Sensitive") { - if (valueBoundToOctoVariable) + if (newValueIsBoundToOctopusVariable) { - newPropertyValue = new PropertyValueResource(variableNewValue, false); + newPropertyValue = new PropertyValueResource(newValue, false); } else { - newPropertyValue = new PropertyValueResource(variableNewValue, true); + newPropertyValue = new PropertyValueResource(newValue, true); } Console.WriteLine("Created sensitive variable for missing template"); } else { - newPropertyValue = new PropertyValueResource(variableNewValue, false); - Console.WriteLine($"Created variable value '{variableNewValue}' for missing template"); + newPropertyValue = new PropertyValueResource(newValue, false); + Console.WriteLine($"Created variable value '{newValue}' for missing template"); } // Create new payload entry for missing variable From 2f25b5d9e4adb1b3d8d278c0621875cac0012c8f Mon Sep 17 00:00:00 2001 From: Bec Callow Date: Thu, 22 Jan 2026 16:05:10 +1000 Subject: [PATCH 6/6] Fix lint --- .../octopus-rest-api/cli/octopus-tenant-variables-update.mdx | 2 +- .../docs/octopus-rest-api/cli/octopus-tenant-variables.mdx | 2 +- .../scripts/update-tenant-project-variable-scripts.include.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables-update.mdx b/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables-update.mdx index 2c145dbc74..ef3b476e65 100644 --- a/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables-update.mdx +++ b/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables-update.mdx @@ -60,4 +60,4 @@ $ octopus tenant variables update --tenant "Sally's Tackle Truck" --name "api-ke ## Learn more - [Octopus CLI](/docs/octopus-rest-api/cli) -- [Creating API keys](/docs/octopus-rest-api/how-to-create-an-api-key) \ No newline at end of file +- [Creating API keys](/docs/octopus-rest-api/how-to-create-an-api-key) diff --git a/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables.mdx b/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables.mdx index 3272ff87b2..00205afa2d 100644 --- a/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables.mdx +++ b/src/pages/docs/octopus-rest-api/cli/octopus-tenant-variables.mdx @@ -49,4 +49,4 @@ $ octopus tenant variables update --tenant "Bobs Fish Shack" --name "company-log ## Learn more - [Octopus CLI](/docs/octopus-rest-api/cli) -- [Creating API keys](/docs/octopus-rest-api/how-to-create-an-api-key) \ No newline at end of file +- [Creating API keys](/docs/octopus-rest-api/how-to-create-an-api-key) diff --git a/src/shared-content/scripts/update-tenant-project-variable-scripts.include.md b/src/shared-content/scripts/update-tenant-project-variable-scripts.include.md index 2185028c92..d021cb6ce5 100644 --- a/src/shared-content/scripts/update-tenant-project-variable-scripts.include.md +++ b/src/shared-content/scripts/update-tenant-project-variable-scripts.include.md @@ -252,7 +252,7 @@ catch
C# - + ```csharp // If using .net Core, be sure to add the NuGet package of System.Security.Permissions #r "nuget: Octopus.Client"