modules/Azure/Discovery/Public/Save-CIEMAzureArmResource.ps1

function Save-CIEMAzureArmResource {
    [CmdletBinding(DefaultParameterSetName = 'ByProperties')]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Upsert operation for bulk data')]
    [OutputType('CIEMAzureArmResource[]')]
    param(
        [Parameter(Mandatory, ParameterSetName = 'ByProperties')]
        [string]$Id,

        [Parameter(Mandatory, ParameterSetName = 'ByProperties')]
        [string]$Type,

        [Parameter(Mandatory, ParameterSetName = 'ByProperties')]
        [string]$Name,

        [Parameter(ParameterSetName = 'ByProperties')]
        [string]$Location,

        [Parameter(ParameterSetName = 'ByProperties')]
        [string]$ResourceGroup,

        [Parameter(ParameterSetName = 'ByProperties')]
        [string]$SubscriptionId,

        [Parameter(ParameterSetName = 'ByProperties')]
        [string]$TenantId,

        [Parameter(ParameterSetName = 'ByProperties')]
        [string]$Kind,

        [Parameter(ParameterSetName = 'ByProperties')]
        [string]$Sku,

        [Parameter(ParameterSetName = 'ByProperties')]
        [string]$Identity,

        [Parameter(ParameterSetName = 'ByProperties')]
        [string]$ManagedBy,

        [Parameter(ParameterSetName = 'ByProperties')]
        [string]$Plan,

        [Parameter(ParameterSetName = 'ByProperties')]
        [string]$Zones,

        [Parameter(ParameterSetName = 'ByProperties')]
        [string]$Tags,

        [Parameter(ParameterSetName = 'ByProperties')]
        [string]$Properties,

        [Parameter(ParameterSetName = 'ByProperties')]
        [string]$CollectedAt,

        [Parameter(ParameterSetName = 'ByProperties')]
        [long]$LastSeenAt = 0,

        [Parameter(Mandatory, ParameterSetName = 'InputObject', ValueFromPipeline)]
        [PSObject[]]$InputObject,

        [Parameter()]
        [Microsoft.Data.Sqlite.SqliteConnection]$Connection
    )

    begin {
        $items = [System.Collections.Generic.List[object]]::new()
    }

    process {
        if ($PSCmdlet.ParameterSetName -eq 'InputObject') {
            foreach ($obj in $InputObject) {
                $items.Add([pscustomobject]@{
                    Id = $obj.Id
                    Type = $obj.Type
                    Name = $obj.Name
                    Location = $obj.Location
                    ResourceGroup = $obj.ResourceGroup
                    SubscriptionId = $obj.SubscriptionId
                    TenantId = $obj.TenantId
                    Kind = $obj.Kind
                    Sku = $obj.Sku
                    Identity = $obj.Identity
                    ManagedBy = $obj.ManagedBy
                    Plan = $obj.Plan
                    Zones = $obj.Zones
                    Tags = $obj.Tags
                    Properties = $obj.Properties
                    CollectedAt = if ($obj.CollectedAt) { $obj.CollectedAt } else { (Get-Date).ToString('o') }
                    LastSeenAt = if ($obj.PSObject.Properties.Name -contains 'LastSeenAt') { [long]$obj.LastSeenAt } else { 0 }
                })
            }
            return
        }

        $items.Add([pscustomobject]@{
            Id = $Id
            Type = $Type
            Name = $Name
            Location = $Location
            ResourceGroup = $ResourceGroup
            SubscriptionId = $SubscriptionId
            TenantId = $TenantId
            Kind = $Kind
            Sku = $Sku
            Identity = $Identity
            ManagedBy = $ManagedBy
            Plan = $Plan
            Zones = $Zones
            Tags = $Tags
            Properties = $Properties
            CollectedAt = if ($CollectedAt) { $CollectedAt } else { (Get-Date).ToString('o') }
            LastSeenAt = $LastSeenAt
        })
    }

    end {
        if ($items.Count -eq 0) {
            return
        }

        $columns = @(
            'id', 'type', 'name', 'location', 'resource_group', 'subscription_id', 'tenant_id', 'kind',
            'sku', 'identity', 'managed_by', 'plan', 'zones', 'tags', 'properties', 'collected_at', 'last_seen_at'
        )

        $chunks = [System.Collections.Generic.List[object[]]]::new()
        for ($offset = 0; $offset -lt $items.Count; $offset += $script:CIEMSqlBatchSize) {
            $remaining = $items.Count - $offset
            $chunkSize = [Math]::Min($script:CIEMSqlBatchSize, $remaining)
            $chunkItems = [object[]]::new($chunkSize)
            for ($i = 0; $i -lt $chunkSize; $i++) {
                $chunkItems[$i] = $items[$offset + $i]
            }
            $chunks.Add($chunkItems)
        }

        foreach ($chunk in $chunks) {
            $parameters = @{}
            $rows = @()
            for ($rowIndex = 0; $rowIndex -lt $chunk.Count; $rowIndex++) {
                $item = $chunk[$rowIndex]
                $suffix = $rowIndex + 1
                $rows += "(@id_$suffix, @type_$suffix, @name_$suffix, @location_$suffix, @resource_group_$suffix, @subscription_id_$suffix, @tenant_id_$suffix, @kind_$suffix, @sku_$suffix, @identity_$suffix, @managed_by_$suffix, @plan_$suffix, @zones_$suffix, @tags_$suffix, @properties_$suffix, @collected_at_$suffix, @last_seen_at_$suffix)"

                $parameters["id_$suffix"] = $item.Id
                $parameters["type_$suffix"] = $item.Type
                $parameters["name_$suffix"] = $item.Name
                $parameters["location_$suffix"] = $item.Location
                $parameters["resource_group_$suffix"] = $item.ResourceGroup
                $parameters["subscription_id_$suffix"] = $item.SubscriptionId
                $parameters["tenant_id_$suffix"] = $item.TenantId
                $parameters["kind_$suffix"] = $item.Kind
                $parameters["sku_$suffix"] = $item.Sku
                $parameters["identity_$suffix"] = $item.Identity
                $parameters["managed_by_$suffix"] = $item.ManagedBy
                $parameters["plan_$suffix"] = $item.Plan
                $parameters["zones_$suffix"] = $item.Zones
                $parameters["tags_$suffix"] = $item.Tags
                $parameters["properties_$suffix"] = $item.Properties
                $parameters["collected_at_$suffix"] = $item.CollectedAt
                $parameters["last_seen_at_$suffix"] = $item.LastSeenAt
            }

            $sql = "INSERT OR REPLACE INTO azure_arm_resources ($($columns -join ', ')) VALUES $($rows -join ', ')"

            if ($Connection) {
                Invoke-PSUSQLiteQuery -Connection $Connection -Query $sql -Parameters $parameters -AsNonQuery | Out-Null
            }
            else {
                Invoke-CIEMQuery -Query $sql -Parameters $parameters -AsNonQuery | Out-Null
            }
        }
    }
}