Remove Variable with env scope

Hi

I’m using your script to remove variables, I would like to be able to remove variables filtered by environment. Is this possible? This is what I’ve added but the script stopped removing variables so just need to see where I’ve gone wrong.

TIA

Function Get-OctopusProject {
    # Define parameters
    param(
        $OctopusServerUrl,
        $ApiKey,
        $ProjectName,
        $SpaceId
    )
    # Call API to get all projects, then filter on name
    $octopusProject = Invoke-RestMethod -Method "get" -Uri "$OctopusServerUrl/api/$spaceId/projects/all" -Headers @{"X-Octopus-ApiKey" = "$ApiKey" }

    # return the specific project
    return ($octopusProject | Where-Object { $_.Name -eq $ProjectName })
}

Function Get-OctopusProjectVariables {
    # Define parameters
    param(
        $OctopusDeployProject,
        $OctopusServerUrl,
        $ApiKey,
        $SpaceId
    )
    # Get reference to the variable list
    return (Invoke-RestMethod -Method "get" -Uri "$OctopusServerUrl/api/$spaceId/variables/$($OctopusDeployProject.VariableSetId)" -Headers @{"X-Octopus-ApiKey" = "$ApiKey" })
}

Function Get-SpaceId {
    # Define parameters
    param(
        $Space
    )
    $spaceName = $Space
    $spaceList = Invoke-RestMethod "$OctopusServerUrl/api/spaces?partialName=$([uri]::EscapeDataString($spaceName))&skip=0&take=100" -Headers @{"X-Octopus-ApiKey" = $ApiKey }
    $spaceFilter = @($spaceList.Items | Where-Object { $_.Name -eq $spaceName })
    $spaceId = $spaceFilter[0].Id
    return $spaceId
}

Function Get-EnvironmentId {
    # Define parameters
    param(
        $EnvironmentName,
        $SpaceId
    )
    $environmentList = Invoke-RestMethod "$OctopusServerUrl/api/$spaceId/environments?skip=0&take=1000&name=$environmentName" -Headers @{"X-Octopus-ApiKey" = $ApiKey }
    $environmentFilter = @($environmentList.Items | Where-Object { $_.Name -eq $environmentName })
    $environmentId = $environmentFilter[0].Id
    return $environmentId
}


Function Remove-Variable {
    param(
        $VariableSet,
        $VariableName,
        $EnvironmentName
    )

    $environmentList = Invoke-RestMethod "$OctopusServerUrl/api/$spaceId/environments?skip=0&take=1000&name=$environmentName" -Headers @{"X-Octopus-ApiKey" = $ApiKey }
    $environmentFilter = @($environmentList.Items | Where-Object { $_.Name -eq $environmentName })
    $environmentId = $environmentFilter[0].Id
    return $environmentId


    $tempVars = @()

    #Create the variable object    
    $obj = New-Object -Type PSObject -Property @{
        'Name'        = $($VariableName)
        'Value'       = $($VariableValue)
        'Type'        = 'String'
        'IsSensitive' = $IsSensitive
        'Scope'       = @{
            'Environment' = @($environmentId)
            'Role'        = @()
        }
    }
 
    foreach ($variable in $VariableSet.Variables) {
        if ($variable.Name -ne $VariableName -and $variable.Scope.Environment -eq $environmentId) {
            $tempVars += $variable
        }
    }
    $variableset.Variables = $tempVars
}


### INPUT THESE VALUES ####

$OctopusServerUrl = "XXXX"  #PUT YOUR SERVER LOCATION HERE. (e.g. http://localhost)
$ApiKey = "XXXXX"   #PUT YOUR API KEY HERE
$ProjectName = "XXXXX"   #PUT THE NAME OF THE PROJECT THAT HOUSES THE VARIABLES HERE
$SpaceName = "Default" #PUT THE NAME OF THE SPACE THAT HOUSES THE PROJECT HERE

### INPUT THESE VALUES ####
try {
    # Convert SpaceName to SpaceId
    $SpaceId = Get-SpaceId -Space $SpaceName
    # Get reference to project
    $octopusProject = Get-OctopusProject -OctopusServerUrl $OctopusServerUrl -ApiKey $ApiKey -ProjectName $ProjectName -SpaceId $SpaceId
    # Get list of existing variables
    $octopusProjectVariables = Get-OctopusProjectVariables -OctopusDeployProject $octopusProject -OctopusServerUrl $OctopusServerUrl -ApiKey $ApiKey -SpaceId $SpaceId

      
    
    #--------------------------
    #Remove-Variable Information
    #--------------------------
    #Remove-Variable will delete any variable with the name regardless of scoping

    #Remove-Variable -VariableSet $octopusProjectVariables -VariableName "RemoveThis"
    
   


    ##### PUT ANY MODIFY AND ADD COMMANDS HERE #####

    Remove-Variable -VariableSet $octopusProjectVariables -VariableName "Test_Variable" -EnvironmentName "test_env"
    
    ##### PUT ANY MODIFY AND ADD COMMANDS HERE #####

    # Convert object to json to upload it
    #$octopusProjectVariables.Version++
    $jsonBody = $octopusProjectVariables | ConvertTo-Json -Depth 10
    #Write-Host $jsonBody
    # Save the variables to the variable set
    Invoke-RestMethod -Method "put" -Uri "$OctopusServerUrl/api/$spaceId/variables/$($octopusProjectVariables.Id)" -Body $jsonBody -Headers @{"X-Octopus-ApiKey" = $ApiKey }
    

}
catch {
    Write-Error $_.Exception.Message

    throw
}```

Hi @daniel.witter,

Thank you for contacting Octopus Support.

At a glance, I don’t see anything wrong with the way you have it set up (assuming you’ve filled out the ### INPUT THESE VALUES #### section).

Can you provide additional details about where the script is stopping? Are you getting an error? Is this working for some Variable/Environment/Project combinations, but not others?

Let me know at your earliest convenience.

Best Regards,
Donny Bell

Hi Donny,

There’s no error the script runs but doesn’t remove any variables, correct I am filling in the input values. If you run the script do you get the same?

Regards,

Dan

Hi @daniel.witter,

Thank you for getting back to me.

I ran the script on my end and that particular section of the script does not appear to be functional. Unfortunately, the script’s author is no longer with Octopus and after a bit of tinkering it was clear that this will need more of a deep dive to either fix the existing script or craft a new one entirely.

I likely won’t have a chance today to spend any more time on this. However, I’ll do my best to have another crack at it in the morning (UK time). In the meantime, I don’t recommend trying to run this script in its current form.

Quick question, are you looking to remove Project Variables scoped to Environments in all Projects or just certain ones?

Let me know at your earliest convenience.

Best Regards,
Donny Bell

Hi Donny,

Just certain ones, thanks for your assistance on this.

Regards,

Dan

1 Like

Hi @daniel.witter,

Thank you for your patience. Apologies for the delay in getting back to you.

Below is a simple script you may use to remove Variables from a Project scoped to a particular Environment:

# =======================================================
#    Delete Project Variables scoped to an Environment
# =======================================================

$ErrorActionPreference = "Stop";

# Define working variables
$OctopusURL = "https://Your_Octopus_URL" # no trailing /
$octopusAPIKey = "API-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
$Header = @{ "X-Octopus-ApiKey" = $octopusAPIKey }
$SpaceId = "Spaces-XXX"
$ProjectName = "Some Project"
$EnvironmentName = "Some Environment"

# Get Environment ID
$Environment = (Invoke-RestMethod -Method GET "$OctopusURL/api/$($SpaceId)/environments/all" -Headers $Header) | Where-Object {$_.Name -eq $EnvironmentName}


# Get Project ID
$Project = (Invoke-RestMethod -Method GET "$OctopusURL/api/$($SpaceId)/projects/all" -Headers $Header) | Where-Object {$_.Name -eq $ProjectName}

# Get Project Variables
$ProjectVariablesJSON = Invoke-RestMethod -Method GET "$OctopusURL/api/$($SpaceId)/variables/$($Project.VariableSetId)" -Headers $Header
$ProjectVariables = $ProjectVariablesJSON.Variables

# Filter Variables based on $EnvironmentName
$ModifiedProjectVariables = @()

Foreach ($ProjectVariable in $ProjectVariables) {
    $ModifiedProjectVariables += $ProjectVariable | Where-Object {$_.Scope.Environment -ne $($Environment.Id)}
}

$ModifiedProjectVariablesJSON = $ProjectVariablesJSON
$ModifiedProjectVariablesJSON.variables = $ModifiedProjectVariables

# Swap the comment from line 38 to line 37 after you have tested the script is working the way you want
$ModifiedProjectVariables | ConvertTo-Json -depth 10
# Invoke-RestMethod -Method PUT "$OctopusURL/api/$($SpaceId)/variables/$($Project.VariableSetId)" -Body ($ModifiedProjectVariablesJSON | ConvertTo-Json -Depth 10) -Headers $Header

I’ve set it up to print the filtered Variables before committing this change to your Project. Just swap the # comment hash once you are happy with what you are seeing.

Let me know if this works for you once you get a chance to try it.

Best Regards,
Donny Bell

Hi Donny,

Worked a treat, thank you very much

Regards,

Dan

2 Likes

Hi Donny,

I’ve amended the script so that is loops through every project and remove all the environment variables. We have 432 projects and for some reason it’s only finding 409 projects so some projects are being missed and I’m not sure why as I do a get call to get all the projects.

This is my script below can you see why that would be?

# =======================================================
#    Bulk Delete all Variables scoped to an Environment
# =======================================================

$ErrorActionPreference = "continue";

# Define working variables
$OctopusURL = "XXXX" # no trailing /
$octopusAPIKey = "XXXX"
$Header = @{ "X-Octopus-ApiKey" = $octopusAPIKey }
$SpaceId = "Spaces-1"
$EnvironmentName = "XXX"  # Enter Environment

# Get Environment ID
$Environment = (Invoke-RestMethod -Method GET "$OctopusURL/api/$($SpaceId)/environments/all" -Headers $Header) | Where-Object {$_.Name -eq $EnvironmentName}

$AllProjects = Invoke-RestMethod -Method GET "$OctopusURL/api/$($SpaceId)/projects/all" -Headers $Header

try{
foreach($ProjectName in $AllProjects)
{
# Get Project ID

#$Name = $ProjectName.Name
$Project = (Invoke-RestMethod -Method GET "$OctopusURL/api/$($SpaceId)/projects/all" -Headers $Header) | Where-Object {$_.Name -eq $ProjectName.Name}

# Get Project Variables
 $ProjectVariablesJSON = Invoke-RestMethod -Method GET "$OctopusURL/api/$($SpaceId)/variables/$($Project.VariableSetId)" -Headers $Header
$ProjectVariables = $ProjectVariablesJSON.Variables

# Filter Variables based on $EnvironmentName
$ModifiedProjectVariables = @()

Foreach ($ProjectVariable in $ProjectVariables) {
    $ModifiedProjectVariables += $ProjectVariable | Where-Object {$_.Scope.Environment -ne $($Environment.Id)}
}

$ModifiedProjectVariablesJSON = $ProjectVariablesJSON
$ModifiedProjectVariablesJSON.variables = $ModifiedProjectVariables

# Swap the comment from line 38 to line 37 after you have tested the script is working the way you want
#$ModifiedProjectVariables | ConvertTo-Json -depth 10
 Invoke-RestMethod -Method PUT "$OctopusURL/api/$($SpaceId)/variables/$($Project.VariableSetId)" -Body ($ModifiedProjectVariablesJSON | ConvertTo-Json -Depth 10) -Headers $Header

}
}
catch
{
    Write-Host $Name
    $output =  $Name | Out-File failed_projects.txt -Append
}




Thank you

Hi @daniel.witter,

Thank you for getting back to me.

Are these other Projects in a different Space? If you navigate in your browser to http://YOUR_OCTOPUS_URL/api/Spaces-XX/projects, does the “TotalResults” returned in the JSON match $AllProjects.count in the script?

Let me know at your earliest convenience.

Best Regards,
Donny Bell

Hi Donny,

Nope we’ve only got 1 space and the all projects count is saying 432. I add an outfile for the projects for the $ProjectName.Name and it’s only counting 409

Thanks,

Dan

Hi @daniel.witter,

Thank you the quick response.

If you just run the following, how many Projects does it detect?

$ErrorActionPreference = "continue";

# Define working variables
$OctopusURL = "XXXX" # no trailing /
$octopusAPIKey = "XXXX"
$Header = @{ "X-Octopus-ApiKey" = $octopusAPIKey }
$SpaceId = "Spaces-1"
$EnvironmentName = "XXX"  # Enter Environment

# Get Environment ID
$Environment = (Invoke-RestMethod -Method GET "$OctopusURL/api/$($SpaceId)/environments/all" -Headers $Header) | Where-Object {$_.Name -eq $EnvironmentName}

$AllProjects = Invoke-RestMethod -Method GET "$OctopusURL/api/$($SpaceId)/projects/all" -Headers $Header
$AllProjects.count

If it is 432, this might mean these “failing” Projects may have scoping that your API key does not have permissions for. If the count returns as 409, it means the API key does not have access to these Projects at all.

Let me know what you find once you get a chance to look at it again.

Best Regards,
Donny Bell

Hi Donny,

I get 432, I generated a new key to be sure also.

Thanks,

Dan

Hi @daniel.witter,

Thank you for confirming.

I’m assuming you’ve created the API key against your own account. If this is the case, can you browse to one of the Projects in question and check to see if there are Variables in the Project’s VariableSet? If so, can you see any Variables that are Scoped with something that you may not have permissions for, such as a particular Environment or Tenant?

Also, can you confirm if anyone of these Projects in question have a Variable scoped to the Environment specified in the script parameters?

Let me know at your earliest convenience.

Best Regards,
Donny Bell

Hi Donny,

I have full admin permissions, so I can see everything there are some projects which don’t have the environment scoped but they’re not the ones being missed. I have some which I’ve been able to scope using script and manually being cut out.

I’m debugging line by line so far I’ve got up to this section and it’s looping through to 432 as I’ve added a count.

# Filter Variables based on $EnvironmentName
$ModifiedProjectVariables = @()

Foreach ($ProjectVariable in $ProjectVariables) {
    $ModifiedProjectVariables += $ProjectVariable | Where-Object {$_.Scope.Environment -ne $($Environment.Id)}
}

$ModifiedProjectVariablesJSON = $ProjectVariablesJSON
$ModifiedProjectVariablesJSON.variables = $ModifiedProjectVariables

# Swap the comment from line 38 to line 37 after you have tested the script is working the way you want
#$ModifiedProjectVariables | ConvertTo-Json -depth 10
 Invoke-RestMethod -Method PUT "$OctopusURL/api/$($SpaceId)/variables/$($Project.VariableSetId)" -Body ($ModifiedProjectVariablesJSON | ConvertTo-Json -Depth 10) -Headers $Header

This must be the problem section, will be going through this section shortly.

Thanks,

Dan

1 Like

Seems to be the PUT at the end it loops 432 times until then, this is where it stops at 409

Hi @daniel.witter,

Have you tried running one of the Projects in question through the original script I provided to see if it works without looping through all Projects?

Let me know if that works or if you run into any issues with running an individual Project.

Best Regards,
Donny Bell

Hi Donny,

Yeah your script works with all the problem projects I’ve found so that’s certainly not the issue.

Regards,

Dan

Hi @daniel.witter,

Thank you for getting back to me and confirming. I don’t see anything else obvious as to why you are getting the discrepancy. Maybe you can remove the try/catch and see if you get more information if something is failing on the Invoke-RestMethod -Method PUT.

As much as I wish I could keep working on this with you, we simply don’t have the capacity to debug scripts and typically only provide general guidance. However, I’m happy to continue to assist if you have any additional questions.

Best Regards,
Donny Bell

This topic was automatically closed 31 days after the last reply. New replies are no longer allowed.