Search code examples
powershellvspherepowercli

If else statement inside foreach results in overwrite each time it loops


I apologize for the unclear title. I'm finding it hard to articulate my problem. I'm writing a script in powershell for the first time. I primarily use python for short scripts but for this task I'm forced to use powershell because of some limitations where I need to use powercli cmdlets. Let me quickly explain the problem. This is to create and/or assign tags to vms in vsphere.

I read the list of VMs into a variable $vms2tag. These are the ones that need to be tagged. I read a json file into a variable and create tag name and description variables based on the data in the json (there's key value pairs that i can directly plug into the names and descriptions) This file also has a 'Server' key which has a value of the VM name exactly as it would appear in "Output-VM.csv" file. This file has data about every single VM that exists. Only ones that need tagged the ones in $vms2tag

Based on some if else conditions like if tag category exists, or if tag exists, it will either create one or use/assign one.

Basically the following code "works" in the sense it will create these tags BUT, it will quickly get overwritten by the next $vm until it keeps overwriting each time and the only tag that sticks around on all the $vms is the one created for the last VM in the list.


$myJson = Get-Content 'C:\For-Powershell.json'| Out-String | ConvertFrom-Json
$vms2tag = Get-Content 'C:\Output-VM.txt'

foreach ($vm in $vms2tag) {
    For ($j=0; $j -lt $myJson.Length; $j++) {
        if ($vm -eq $myJson.Server[$j]) {
            Write-Output "Match!"

            # Variables for Application Owner
            $nameAO = [string]$myJson.Application_Owner[$j]
            $descriptionAO = [string]$myJson.Application_Owner[$j]


            # check if Tag Category and/or Tag exist

            if ((Get-TagCategory -Name "app_owner") -eq $null) {
                New-TagCategory -Name "app_owner" -Cardinality "Multiple"
            }
            
            if ((Get-Tag -Category "app_owner" | Set-Tag -Name $nameAO -Description $descriptionAO) -eq $null) {
                $myTagAO = Get-TagCategory -Name "app_owner" | New-Tag -Name $nameAO -Description $descriptionAO
                New-TagAssignment -Tag $myTagAO -Entity $myJson.Server[$j]
            }
            else {
                $myTagAO = Get-Tag -Category "app_owner" | Set-Tag -Name $nameAO -Description $descriptionAO
                New-TagAssignment -Tag $myTagAO -Entity $myJson.Server[$j]
            }
        }
    }
}


I tested while the script runs and the tag is properly applied to the VM based on its data but when I refresh it after the script completes, all the tags on each VM exist but they are incorrect as they contain the information that's valid only for the last VM in the $vms2tag list. It seems pretty simple but I just don't see where I'm messing up. My guess is something with if else statements is nested incorrectly? It took me a while (~6 hours) to get this to work as I had other issues with the script but when I finally got the tags to correctly set based on the other conditions, I ended up with this problem so it's possible I'm just burnt out and not seeing it.


Solution

  • The problem is with the Tag logic. The following line is overwriting existing tags every loop:

               if ((Get-Tag -Category "app_owner" | Set-Tag -Name $nameAO -Description $descriptionAO) -eq $null) {
    

    The Set-Tag cmdlet should never be used in a test to find existing tags.

    I would write the test and assignment block like the following:

                $myTagAO = Get-Tag -Category "app_owner" -Name $nameAO -ErrorAction SilentlyContinue
                if ($myTagAO -eq $null) {
                    $myTagAO = Get-TagCategory -Name "app_owner" | New-Tag -Name $nameAO -Description $descriptionAO
                }
    
                New-TagAssignment -Tag $myTagAO -Entity $myJson.Server[$j]
    

    This ensures that each tag is only created once, with the appropriate description.