Public/ps1/Get-VMsWithoutSpecificTag.ps1

<#
.Synopsis
    Gets a list of VMs without specific category tags from a specified datacenter, VM folder, or a list of VM names and outputs the list to the console or a variable.
 
.Description
    The Get-VMsWithoutSpecificTags function retrieves VMs based on the input type,
    filters them based on the absence of tags in a specified category or the complete absence of tags,
    and outputs the filtered VMs list.
 
.Parameter InputType
    Specifies whether the source 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.
 
.Parameter ExcludedCategory
    Specifies the category of tags to check against each VM. Defaults to 'System Owner'.
 
.Example
    $vmList = Get-VMsWithoutSpecificTag -InputType "Datacenter" -InputValue "dc1" -ExcludedCategory "System Owner"
    This example retrieves names of VMs in 'dc1' that do not have any 'System Owner' tags and stores the result in the variable $vmList.
 
.Notes
    Author: bensiegit
    Version: 1.0.0
 
    Requires that you are connected to a vCenter server with appropriate permissions to retrieve VMHost information.
#>

function Get-VMsWithoutSpecificTag {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory = $true)]
        [ValidateSet("Datacenter", "VMFolder", "VMList")]
        [string]$InputType,

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

        [Parameter(Mandatory = $true)]
        [string]$ExcludedCategory
    )

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

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

        # Retrieve the category object for the excluded category
        $category = Get-TagCategory -Name $ExcludedCategory

        # Check if the category exists
        if (-not $category) {
            Write-Error "Specified category '$ExcludedCategory' does not exist."
            return
        }

        # Filter VMs based on the absence of tags in the specified category
        $filteredVMs = $vms | Where-Object {
            $tags = Get-TagAssignment -Entity $_ | Select-Object -ExpandProperty Tag
            # Check if VM has no tags or none of the tags belong to the excluded category
            -not ($tags | Where-Object { $_.Category -eq $category.Name })
        } | Select-Object Name

        # Output the filtered VM names
        $filteredVMs 
    } catch {
        Write-Error "An error occurred: $_"
    }
}