Delete Variable Using REST API

Hi Team,

I need help with following PowerShell snippet where i am trying to delete a variable name from the project variable set.

# Project variable
$DeploymentRelam = ""
$ProjectName = ""
$EnvironmentType = $($DeploymentRelam)

# Octopus Server URL
$OctopusServerURL = ""

# Octopus Server URL API key
$OctopusServerApiKey = ""

# Octopus Space Name
$SpaceName = "Default"

# Octopus Space Name
$ChannelName = "Default"

# Process
$Header = @{ "X-Octopus-ApiKey" = $OctopusServerApiKey }

# Function To Get The spaceId For Defind SpaceName
Function Get-SpaceId {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String[]]$Space       
    )
    $SpaceName = $Space
    $SpaceList = Invoke-RestMethod -Method Get -UseBasicParsing -Uri "$OctopusServerUrl/api/spaces?Name=$spaceName" -Headers $Header
    $SpaceFilter = @($SpaceList.Items | Where-Object { ($_.Name -eq "$SpaceName") })
    $SpaceId = $spaceFilter[0].Id
    return ($SpaceId)
}

# Function To Get The ProjectName Under Defind SpaceName
Function Get-OctopusProject {
    [CmdletBinding()]
    param(
        [Parameter(Position = 0, Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String[]]$OctopusServerUrl,

        [Parameter(Position = 1, Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String[]]$OctopusServerApiKey,

        [Parameter(Position = 2, Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String[]]$ProjectName,

        [Parameter(Position = 3, Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String[]]$SpaceId
    )
    $OctopusProject = Invoke-RestMethod -Method Get -UseBasicParsing -Uri "$OctopusServerUrl/api/projects/all" -Headers @{"X-Octopus-ApiKey" = "$OctopusServerApiKey" }
    $OctopusProjectFilter = $OctopusProject | Where-Object { ($_.Name -eq $ProjectName -and $_.SpaceId -eq $SpaceId) }
    return ($OctopusProjectFilter)
}

# Function To Get The ChannelName Under Defind ProjectName
Function Get-OctopusChannel {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String[]]$ChannelName   
    )
    $Channels = Invoke-RestMethod -Method Get -UseBasicParsing -Uri "$OctopusServerURL/api/projects/$($OctopusProject.Id)/channels" -Headers @{"X-Octopus-ApiKey" = "$OctopusServerApiKey" }
    $Channel = $Channels | Where-Object { $_.Items.Name -eq $ChannelName }
    return ($Channel)
}

# Function To Get The EnvironmentType On Which Project Will Be Execute
Function Get-EnvironmentType {
    [CmdletBinding()]
    param(
        [Parameter(Position = 0, Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String[]]$EnvironmentName,

        [Parameter(Position = 1, Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String[]]$SpaceId
    )
    $EnvironmentList = Invoke-RestMethod -Method Get -UseBasicParsing -Uri "$OctopusServerUrl/api/$spaceId/environments?skip=0&take=1000&name=$EnvironmentName" -Headers $Header
    $EnvironmentFilter = @($EnvironmentList.Items | Where-Object { $_.Name -eq $EnvironmentName })   
    return ($EnvironmentFilter)
}

# Create Function To Get ProjectVariablesSet By Project Name
Function Get-OctopusProjectVariables {
    [CmdletBinding()]
    param(
        [Parameter(Position = 0, Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [PSCustomObject]$OctopusDeployProject,

        [Parameter(Position = 1, Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String[]]$OctopusServerUrl,

        [Parameter(Position = 2, Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String[]]$OctopusServerApiKey,

        [Parameter(Position = 3, Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String[]]$SpaceId
    )
    $ProjectVariablesSet = Invoke-RestMethod -Method Get -UseBasicParsing -Uri "$OctopusServerUrl/api/variables/$($OctopusDeployProject.VariableSetId)" -Headers @{"X-Octopus-ApiKey" = "$OctopusServerApiKey" }
    return ($ProjectVariablesSet)
}


try {
    # Get Space-ID From SpaceName
    $SpaceId = Get-SpaceId -Space $SpaceName

    # Get Channel-ID From ChannelName
    $Channel = Get-OctopusChannel -ChannelName $ChannelName
    
    # Get Project Refrence
    $OctopusProject = Get-OctopusProject -OctopusServerUrl $OctopusServerUrl -OctopusServerApiKey $OctopusServerApiKey -ProjectName $ProjectName -SpaceId $SpaceId
    
    # Get List Of Existing ProjectVariableSet Variables
    [PSCustomObject]$OctopusProjectVariables = Get-OctopusProjectVariables -OctopusDeployProject $OctopusProject -OctopusServerUrl $OctopusServerURL -OctopusServerApiKey $OctopusServerApiKey -SpaceId $SpaceId
    
    # Delete Variable
    $VariableToRemove = ($OctopusProjectVariables.Variables | Where-Object { $_.Name -eq "EnvironmentName" })
    if ($null -eq $VariableToRemove) {
        $OctopusProjectVariables.PSObject.Properties.Remove('$VariableToRemove')
    }
    
    # Construct Payload Of JsonBody Over Invoke-RestMethod Session
    $JsonBody = $OctopusProjectVariables | ConvertTo-Json -Depth 10

    # Transfer Json Payload To ProjectVariableSet
    Invoke-RestMethod -Method Put -UseBasicParsing -Uri "$OctopusServerUrl/api/variables/$($octopusProjectVariables.Id)" -Body $JsonBody -Headers $Header
}
catch {
    Write-Error $_.Exception.Message
    throw
}

Hey Vivek,

Thanks for reaching out.

I took a quick look at your script and depending on your version of Octopus, you may need to increment version in the json body before doing the PUT call. Can you please implement that logic, try it again and let me know if it works?

Thanks,
Jeremy

Hi Jeremy,

Thanks for writing. You mean to create an empty array and then do the increment version like this snippet below snipprt , if yes then i am getting error and respective array doest now have op_Addition function.

# Get List Of Existing ProjectVariableSet Variables
    $OctopusProjectVariables = @()
    $OctopusProjectVariables = Get-OctopusProjectVariables -OctopusDeployProject $OctopusProject -OctopusServerUrl $OctopusServerURL -OctopusServerApiKey $OctopusServerApiKey -SpaceId $SpaceId
    
    # Delete Variable
    $VariableToRemove = ($OctopusProjectVariables.Variables | Where-Object { $_.Name -eq "EnvironmentName" })
    if ($null -eq $VariableToRemove) {
        $OctopusProjectVariables.PSCustomObject.Properties.Remove('$VariableToRemove')
    }
    
    # Construct Payload Of JsonBody Over Invoke-RestMethod Session
    $OctopusProjectVariables += $OctopusProjectVariables
    $JsonBody = $OctopusProjectVariables | ConvertTo-Json -Depth 10

Hi ,

I am using Octopus Deploy Version : 2020.1.11

Thanks
Vivek

Hi Vivek,

Sorry about the confusion. What I meant was in that json body that you’re bringing down with the variables then putting back up with a PUT call, there is a “version” field. It will need to be incremented once before the API call will work. If it’s 7, make it 8, etc. I’m not sure on the syntax but you should be able to do a dot operator on the version and ++ it.

What is the response code you’re getting when you make the call?

Please let me know how it goes.

Thanks,
Jeremy

Hi Jeremy,

I have updated the snippet, but I guess I am too not getting the System.Int32 member type with an increment. I am missing some logic of iteration . Here is the snippet :

# Get List Of Existing ProjectVariableSet Variables
    [PSCustomObject]$OctopusProjectVariables = Get-OctopusProjectVariables -OctopusDeployProject $OctopusProject -OctopusServerUrl $OctopusServerURL -OctopusServerApiKey $OctopusServerApiKey -SpaceId $SpaceId
    
    # Delete Variable
    $VariableToRemove = ($OctopusProjectVariables.Variables | Where-Object { $_.Name -eq "EnvironmentName" })
    if ($null -eq $VariableToRemove) {
        $OctopusProjectVariables.PSObject.Properties.Remove('$VariableToRemove')
        forach ($OctopusProjectVariables.PSObject.Properties | Where-Object {$_.Name -eq "Version" }){
            $_.Value++;
        }
    }
    
    # Construct Payload Of JsonBody Over Invoke-RestMethod Session
    $JsonBody = $OctopusProjectVariables | ConvertTo-Json -Depth 10

Hey Vivek,

I think the problem lies in how you’re removing the variable. That properties.remove command removes a root level property from the object. The JSON body has the properties: Id, OwnerId, Version, Variables, ScopeValues, SpaceId, and Links. You could use that command to remove an entire section of those.

I did a quick test.

Here is my JSON body before:

PS C:\Users\Jeremy> $OctopusProjectVariables

Id          : variableset-Projects-441
OwnerId     : Projects-441
Version     : 18
Variables   : {@{Id=68956cff-a686-44b9-910b-35a15ad9f6b7; Name=TestNewEnv2; Value=Env Scoped; Description=; Scope=; IsEditable=True; Prompt=; Type=String; IsSensitive=False}, @{Id=9da38ef5-de7f-4025-8d84-04191144dccb; Name=TestNewRole; Value=Role Scoped; Description=; Scope=; IsEditable=True; Prompt=; Type=String; IsSensitive=False}, 
              @{Id=2b6b20dc-437e-40bc-abcb-8130baaf3815; Name=ObjectTesting2; Value=Both Env and Role Scoped; Description=; Scope=; IsEditable=True; Prompt=; Type=String; IsSensitive=False}, @{Id=8c25dbc3-929a-4d31-979c-064f4ec6786f; Name=SensitiveVariable; Value=; Description=; Scope=; IsEditable=True; Prompt=; Type=Sensitive; 
              IsSensitive=True}...}
ScopeValues : @{Environments=System.Object[]; Machines=System.Object[]; Actions=System.Object[]; Roles=System.Object[]; Channels=System.Object[]; TenantTags=System.Object[]; Processes=System.Object[]}
SpaceId     : Spaces-1
Links       : @{Self=/api/Spaces-1/variables/variableset-Projects-441}

Then I ran PS C:\Users\Jeremy> $OctopusProjectVariables.PSObject.Properties.Remove("Version")

Then the results is

PS C:\Users\Jeremy> $OctopusProjectVariables

Id          : variableset-Projects-441
OwnerId     : Projects-441
Variables   : {@{Id=68956cff-a686-44b9-910b-35a15ad9f6b7; Name=TestNewEnv2; Value=Env Scoped; Description=; Scope=; IsEditable=True; Prompt=; Type=String; IsSensitive=False}, @{Id=9da38ef5-de7f-4025-8d84-04191144dccb; Name=TestNewRole; Value=Role Scoped; Description=; Scope=; IsEditable=True; Prompt=; Type=String; IsSensitive=False}, 
              @{Id=2b6b20dc-437e-40bc-abcb-8130baaf3815; Name=ObjectTesting2; Value=Both Env and Role Scoped; Description=; Scope=; IsEditable=True; Prompt=; Type=String; IsSensitive=False}, @{Id=8c25dbc3-929a-4d31-979c-064f4ec6786f; Name=SensitiveVariable; Value=; Description=; Scope=; IsEditable=True; Prompt=; Type=Sensitive; 
              IsSensitive=True}...}
ScopeValues : @{Environments=System.Object[]; Machines=System.Object[]; Actions=System.Object[]; Roles=System.Object[]; Channels=System.Object[]; TenantTags=System.Object[]; Processes=System.Object[]}
SpaceId     : Spaces-1
Links       : @{Self=/api/Spaces-1/variables/variableset-Projects-441}

I’m not familiar with this method of deletion from a powershell object, but my gut tells me you’d have to somehow go one layer deeper. You may need to create a powershell object out of the variables property by themselves, then run the remove on that object, then put the variables back inside the rest of the object with the rest of the properties.

Please let me know what you think.

Thanks,
Jeremy

Hi Jeremy,

Thanks for the response. I need to look into it of creating PSObjects for deletion and getting back the rest of the objects as you have suggested. I will update the thread tomorrow after some analysis.

In Mean while : I was trying the another method with Octopus.Client.dll which is not throwing the any error however not working as well :

Add-Type -Path 'C:\Octopus\Octopus.Client.dll' 
$Apikey = " "
$OctopusURI = " "

$ProjectName = " "
$VariableName = "EnvironmentName"

$Endpoint = New-Object -TypeName Octopus.Client.OctopusServerEndpoint $OctopusURI,$Apikey 
$Repository = New-Object -TypeName Octopus.Client.OctopusRepository $Endpoint

$Project = $Repository.Projects.FindByName($ProjectName)
$Variableset = $Repository.VariableSets.Get($Project.links.variables)

$VariableToRemove = New-Object -TypeName Octopus.Client.Model.VariableResource
$VariableToRemove.Name = $VariableName

$Variableset.Variables.Remove($VariableToRemove)
$Repository.VariableSets.Modify($Variableset)

Note : I will work REST API in mean while.

Thanks
Vivek

Hey Vivek,

I think the problem is this line: $Variableset.Variables.Remove($VariableToRemove)

You are creating it with only a variable name, not all of the contents. I believe they need to be identical resources.

Here is my working code. I had to add in some stuff since I work with spaces so the beginning is a bit different, but the part I think you will need to modify is the third to last line. $VariableToRemove = $variableset.Variables | Where-Object {$_.Name -eq $VariableName}

Add-Type -Path 'C:\Temp\Octopus.Client.dll' 
$Apikey = ""
$OctopusURI = ""

$ProjectName = "variable creation test"
$VariableName = "ArrayTesting"

$endpoint = New-Object Octopus.Client.OctopusServerEndpoint $OctopusURI,$ApiKey
$client = new-object Octopus.Client.OctopusClient $endpoint

$spaceName = "Default"
$space = $client.ForSystem().Spaces.FindByName($spaceName)
$spaceRepository = $client.ForSpace($space)

$Project = $SpaceRepository.Projects.FindByName($ProjectName)
$Variableset = $SpaceRepository.VariableSets.Get($Project.links.variables)

$VariableToRemove = New-Object -TypeName Octopus.Client.Model.VariableResource
$VariableToRemove = $variableset.Variables | Where-Object {$_.Name -eq $VariableName}

$Variableset.Variables.Remove($VariableToRemove)
$SpaceRepository.VariableSets.Modify($Variableset)

Please let me know if that works for you.

Thanks,
Jeremy

Hi Jeremy,

I was not able to able thread the thread, I have used the Octopus.Client.dll to delete variable along with whole code of REST Method. Actually, it was bit tricky & time consuming for me to understand how I can delete single project variable using REST Method. You can think on this to work if you want and I will too do to explore about it.

Thanks
Vivek

Hey Vivek,

I wrote a function that works with my script over at: https://github.com/OctopusDeploy/OctopusDeploy-Api/blob/master/REST/PowerShell/Variables/AddOrEditVariablesWithScoping.ps1

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

    $tempVars = @()
 
    foreach ($variable in $VariableSet.Variables){
        if ($variable.Name -ne $VariableName){
            $tempVars += $variable
        }

    }
    $variableset.Variables = $tempVars
}

It worked for me in my initial testing. The logic is that it creates a temporary array of variables by skipping the variable we want to remove when iterating and copying everything over. After it has created that temporary set, we just copy the set to the original’s variable array.

If you do use this please use thorough testing as I just checked if it removes the variable, I didn’t test anything outside of that. It may cause adverse effects on the variable set in ways I didn’t anticipate in your scenario.

Let me know what you think.

Thanks,
Jeremy

Hi Jeremy,

Thanks for the write up of PowerShell function. Actually it did worked as expected. I am going to enhance it at scope level.

Thanks
Vivek

1 Like

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