Public/ps1/Set-VMTagIfMissing.ps1

<#
.Synopsis
    Assigns a default tag to VMs in a specified datacenter, VM folder, or a specified list of VMs if they lack a specific category tag.
 
.Description
    The Set-VMTagIfMissing function checks each VM in the specified datacenter, VM folder, or list for tags in a specific category. If no tags in the category are found, it assigns a predefined tag to the VM.
 
.Parameter InputType
    Specifies whether the target is a 'Datacenter', 'VMFolder', or 'VMList'. Accepts only these values.
 
.Parameter InputValue
    Specifies the name of the Datacenter, VM Folder, or an array of VM names from which to retrieve VMs. This parameter cannot be null or empty.
 
.Parameter VMList
    Specifies an array of VM names to be processed. This parameter is used when 'InputType' is set to 'VMList'. Each VM name in the array is processed to check and assign the specified tag if necessary.
 
.Parameter Category
    Specifies the category of tags to check against each VM.
 
.Parameter TagName
    Specifies the name of the tag to apply if no tags of the specified category are found.
 
.Example
    Set-VMTagIfMissing -InputType "Datacenter" -InputValue "dc1" -Category "System Owner" -TagName "Unassigned"
    This example assigns the 'Unassigned' tag to all VMs in the 'dc1' datacenter that do not have a 'System Owner' tag.
 
.Example
    $vmList = @("vm1", "vm5", "vm10")
    Set-VMTagIfMissing -InputType "VMList" -InputValue $vmList -Category "System Owner" -TagName "Unassigned"
    This example assigns the 'Unassigned' tag to specified VMs in the list that do not have a 'System Owner' tag.
 
.Notes
    Author: bensiegit
    Version: 1.0.0
 
    Requires that you are connected to a vCenter server with appropriate permissions to retrieve VMHost information.
#>

function Set-VMTagIfMissing {
    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
    Param(
        [Parameter(Mandatory = $true)]
        [ValidateSet("Datacenter", "VMFolder", "VMList")]
        [string]$InputType,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        $InputValue
    )

    try {
        # Initialize the VM collection variable
        $vms = @()

        # Determine how to get VMs based on the input type
        switch ($InputType) {
            "Datacenter" {
                $vms = Get-Datacenter $InputValue | Get-VM *
            }
            "VMFolder" {
                $vms = Get-Folder $InputValue | Get-VM *
            }
            "VMList" {
                $vms = $InputValue | ForEach-Object { Get-VM -Name $_ }
            }
        }

        # Retrieve the tag object
        $newTag = Get-Tag $TagName

        # Loop through each VM
        foreach ($vm in $vms) {
            # Check if the VM has any tags of the specified category
            $tags = (Get-TagAssignment -Entity $vm).Tag.Category.Name | Where-Object {$_ -eq $Category}
            if ($tags.Count -eq 0) {
                if ($PSCmdlet.ShouldProcess($vm.Name, "Assign tag '$TagName'")) {
                    New-TagAssignment -Tag $newTag -Entity $vm
                    Write-Verbose "Tag '$TagName' assigned to VM '$($vm.Name)'"
                    $result = [PSCustomObject]@{
                        VMName = $vm.Name
                        Action = "TagAssigned"
                        Tag    = $TagName
                    }
                    Write-Output $result
                }
            } else {
                Write-Verbose "VM '$($vm.Name)' already has a tag in the category '$Category'. No action taken."
            }
        }
    } catch {
        Write-Error "An error occurred: $_"
    }
}