manifests/collectors/Hybrid/VirtualMachines.psd1

#
# Originally GENERATED by scripts/ConvertTo-ScoutCollectorDefinition.ps1 from
# Modules/Public/InventoryModules/Hybrid/VirtualMachines.ps1 (AB#5660).
# See docs/design/decisions/declarative-collectors.md.
#
# HAND-EDITED for AB#6802, deliberately, and it cannot be regenerated: the source collector no
# longer exists (Modules/ was retired) and the defect was in what it READ, not in how it was
# converted. It declared `microsoft.azurestackhci/virtualmachineinstances` and consumed the
# Resource Graph `resources` table -- but that type is an ARM EXTENSION resource
# (https://learn.microsoft.com/azure/azure-resource-manager/management/extension-resource-types#microsoftazurestackhci),
# scoped under a `Microsoft.HybridCompute/machines` parent, and Resource Graph's own supported-type
# reference does not list it among the `microsoft.azurestackhci/*` types it indexes -- so this
# collector could not return a row in ANY tenant, deployed or not. The rows now come from the
# per-parent ARM REST sweep in src/collect/Get-ScoutArmChildResource.ps1
# ('AzureLocalVirtualMachineInstances' dataset), same shape as AB#6769's ResourceDiagnosticSettings
# fix. See docs/audits/AZURE-SCOUT-AUDIT.md for the full citation trail, including the correction
# of AB#6846's "not broken" verdict, whose live-tenant zero-rows result was real but whose
# reasoning was not: the AB#6842 existence gate proves the TYPE STRING is real ARM ground truth,
# never that Resource Graph indexes it.
#
# The child envelope's own NAME is always the fixed string 'default' (the instance is a
# per-machine singleton) -- PARENTNAME/PARENTLOCATION carry the actual Arc machine/Azure Local VM
# identity, matching the ResourceDiagnosticSettings PARENTNAME/PARENTTYPE convention.
#
@{
    ResourceTypes = @(
        'AZSC/ARMChild/AzureLocalVirtualMachineInstances'
    )

    ResourceTypeMatching = 'Grouped'

    AdditionalFilter = $null

    FilterPreamble = ''

    RowLoopVariable = '1'

    Preamble = @'
$ResUCount = 1
            $sub1 = $SUB | Where-Object { $_.id -eq $1.subscriptionId }
            $data = $1.PROPERTIES
            # An ARM child envelope carries no `tags` property at all, and reading an absent
            # property throws under StrictMode rather than returning $null. Guard first.
            $Tags = if ($1.PSObject.Properties['tags'] -and ![string]::IsNullOrEmpty($1.tags.psobject.properties)) { $1.tags.psobject.properties } else { '0' }
 
            # The parent is carried on the envelope by Get-ScoutArmChildResource -- the child's
            # own name/location are a fixed 'default' and absent, respectively.
            $parentResourceName = if ([string]::IsNullOrEmpty($1.PARENTNAME)) { 'Unknown' } else { [string]$1.PARENTNAME }
            $parentLocation = if ([string]::IsNullOrEmpty($1.PARENTLOCATION)) { 'Unknown' } else { [string]$1.PARENTLOCATION }
 
            # No retirement lookup: AB#6779/6845's $Retirements/$Unsupported feed is keyed to
            # Resource Graph resource ids, and this envelope's id is a synthetic ARM child id that
            # feed never carries -- it would always miss, so it is not carried forward.
 
            # Hardware profile
            $VMSize = $data.hardwareProfile.vmSize
            $ProcessorCount = $data.hardwareProfile.processors
            $MemoryMB = $data.hardwareProfile.memoryMB
 
            # Dynamic memory
            $DynamicMemory = if ($data.hardwareProfile.dynamicMemoryConfig) {
                'Enabled'
            } else { 'Disabled' }
            $DynMemMin = $data.hardwareProfile.dynamicMemoryConfig.minimumMemoryMB
            $DynMemMax = $data.hardwareProfile.dynamicMemoryConfig.maximumMemoryMB
 
            # OS profile
            $OSType = $data.osProfile.osType
            $ComputerName = $data.osProfile.computerName
 
            # Storage
            $DataDiskCount = if ($data.storageProfile.dataDisks) { @($data.storageProfile.dataDisks).Count } else { 0 }
            $ImageRef = if ($data.storageProfile.imageReference) {
                '{0}/{1}/{2}' -f $data.storageProfile.imageReference.publisher, $data.storageProfile.imageReference.offer, $data.storageProfile.imageReference.sku
            } else { $null }
 
            # Network interfaces
            $NICs = if ($data.networkProfile.networkInterfaces) {
                ($data.networkProfile.networkInterfaces | ForEach-Object { (([string]$_.id) -split '/')[-1] }) -join ', '
            } else { $null }
 
            # Status
            $PowerState = $data.instanceView.powerState
            $ProvisioningState = $data.provisioningState
            $StatusMsg = $data.status.provisioningStatus.status
'@


    AdditionalRowLoops = @()

    TagLoop = @{
        Variable = 'Tag'
        Source = '$Tags'
        Preamble = ''
    }

    Fields = @(
        @{
            Name = 'ID'
            Expression = '$1.id'
        }
        @{
            Name = 'Subscription'
            Expression = '(Get-AZSCSafeProperty -InputObject $sub1 -Path ''name'')'
        }
        @{
            Name = 'Resource Group'
            Expression = '$1.RESOURCEGROUP'
        }
        @{
            Name = 'Name'
            Expression = '$parentResourceName'
        }
        @{
            Name = 'Location'
            Expression = '$parentLocation'
        }
        @{
            Name = 'Power State'
            Expression = '$PowerState'
        }
        @{
            Name = 'Provisioning State'
            Expression = '$ProvisioningState'
        }
        @{
            Name = 'VM Size'
            Expression = '$VMSize'
        }
        @{
            Name = 'OS Type'
            Expression = '$OSType'
        }
        @{
            Name = 'Computer Name'
            Expression = '$ComputerName'
        }
        @{
            Name = 'Processor Count'
            Expression = '$ProcessorCount'
        }
        @{
            Name = 'Memory MB'
            Expression = '$MemoryMB'
        }
        @{
            Name = 'Dynamic Memory'
            Expression = '$DynamicMemory'
        }
        @{
            Name = 'Dynamic Mem Min MB'
            Expression = '$DynMemMin'
        }
        @{
            Name = 'Dynamic Mem Max MB'
            Expression = '$DynMemMax'
        }
        @{
            Name = 'Data Disk Count'
            Expression = '$DataDiskCount'
        }
        @{
            Name = 'Image Reference'
            Expression = '$ImageRef'
        }
        @{
            Name = 'Network Interfaces'
            Expression = '$NICs'
        }
        @{
            Name = 'Status'
            Expression = '$StatusMsg'
        }
        @{
            Name = 'Resource U'
            Expression = '$ResUCount'
        }
        @{
            Name = 'Tag Name'
            Expression = '[string]$Tag.Name'
        }
        @{
            Name = 'Tag Value'
            Expression = '[string]$Tag.Value'
        }
    )

    Export = @{
        WorksheetName = 'AzLocal VMs'
        TableNamePrefix = 'AzLocalVMs_'
        Columns = @(
            'Subscription'
            'Resource Group'
            'Name'
            'Location'
            'Power State'
            'Provisioning State'
            'VM Size'
            'OS Type'
            'Computer Name'
            'Processor Count'
            'Memory MB'
            'Dynamic Memory'
            'Dynamic Mem Min MB'
            'Dynamic Mem Max MB'
            'Data Disk Count'
            'Image Reference'
            'Network Interfaces'
            'Status'
            'Resource U'
        )
        TagColumns = @(
            'Tag Name'
            'Tag Value'
        )
        TagColumnsBefore = 'Resource U'
        NumberFormat = '0'
        # AB#6802: the removed 'Retiring Feature'/'Retiring Date' columns were what this
        # conditional-text rule highlighted; there is nothing left in this worksheet for it to
        # point at.
        ConditionalText = @()
    }

    SourceCollector = 'Modules/Public/InventoryModules/Hybrid/VirtualMachines.ps1'
}