Skip to content

Add Azure Function deployment, Log Analytics ingestion, and Bicep infrastructure - #11

Merged
marcelloformica merged 10 commits into
mainfrom
dev
Apr 27, 2026
Merged

marcelloformica merged 10 commits into
mainfrom
dev

Conversation

@marcelloformica

Copy link
Copy Markdown
Contributor

Summary

Transforms the standalone PowerShell script into a fully deployed Azure Function with IaC, Log Analytics ingestion, and production-verified pipeline.

What changed

Infrastructure (Bicep/)

  • Single resource-group scoped Bicep template deploying the full stack: Log Analytics workspace, custom tables (GetAvailResources_CL, GetAvailSummary_CL), Data Collection Endpoint, Data Collection Rule, Storage Account, Flex Consumption Function App, Application Insights, Private Endpoints, and RBAC assignments
  • Parameterized via parameters.dev.bicepparam — all Function App settings auto-wired at deploy time (no manual configuration after func publish)

Azure Function (Functions/GetAvail/)

  • Timer-triggered Function App (RunGetAvailability) on Flex Consumption (FC1), PowerShell 7.4, system-assigned managed identity
  • run.ps1 reads all config from App Settings and invokes get-availability.ps1
  • profile.ps1 authenticates via managed identity on cold start
  • host.json, requirements.psd1, .funcignore configured for Flex Consumption (no managed dependencies)
  • Modules/ folder for vendored Az modules (Save-Module)

Log Analytics ingestion

  • Send-ToLogAnalytics function: gzip-compressed, batched at 900 KB, with retry (3 attempts, exponential backoff) via the Azure Monitor Ingestion API
  • Two custom tables: per-resource detail and aggregated summaries
  • DCR with kind: Direct and TimeGenerated injection transforms

Script improvements (get-availability.ps1)

  • -DceEndpoint / -DcrImmutableId parameters for optional Log Analytics ingestion
  • -SourceWorkspaceId renamed from -Workspace for clarity
  • Perpetually-deallocated VM detection — VMs that were never running during the period are excluded (N/A)
  • Get-PlainToken helper — centralizes Az.Accounts token acquisition (handles both SecureString and plain string returns)
  • Removed -UseBasicParsing (no-op in PowerShell Core) and $ProgressPreference save/restore pattern

Repository structure

  • C# implementation moved to Old/ with its own README
  • CI/CD workflows updated for PowerShell-only paths
  • README overhauled: deployment guide, Bicep parameters, RBAC docs, auto-wired app settings, post-deployment steps

Bug fixes

  • DCR transform errors: fixed extend on existing columns in KQL transforms
  • DCR kind: Direct: required for custom table ingestion without agent
  • PowerShell byte[] pipeline unrolling: gzip compression produced individual bytes instead of byte array — fixed with nested function and explicit [byte[]] cast

Verified

  • Function published and triggered manually — completed in ~9s
  • 9 resource rows + 11 summary rows ingested to Log Analytics
  • 0 transform errors, 0 dropped rows in DCR metrics
  • AppExceptions table: 0 entries

- Add -DceEndpoint and -DcrImmutableId parameters to get-availability.ps1
- Add Send-ToLogAnalytics function (gzip, 900KB batching)
- Add ingestion block: builds resource + summary payloads, sends to custom tables
- Add subscription-scoped Bicep (getavailability.bicep + resources module)
  creates: Log Analytics workspace, 2 custom tables, DCE, DCR
- Update parameters.dev.bicepparam for new Bicep
- Rewrite Setup/README.md for Get-Availability infrastructure
- Create csharp/README.md with C#-specific content from root README
- Update root README.md: add new params, ingestion section, link to C# README
- Combine getavailability-resources.bicep into getavailability.bicep
- Switch from subscription-scoped to resource-group scoped deployment
- Remove resourceGroupName param (RG created separately via az group create)
- Location defaults to resourceGroup().location
- Delete getavailability-resources.bicep module
- Update parameters.dev.bicepparam and Setup/README.md accordingly
Disambiguates the historical data source workspace from the ingestion
target (DCE/DCR). The new name makes clear it expects a GUID and that
it is NOT the workspace used for result ingestion.
- Remove unused $batchSize variable
- Remove dead status-code check after -ErrorAction Stop
- Extract duplicated gzip logic into local $compressJson scriptblock
- Early-return on empty payload; hoist headers out of loop
- Add ## doc comments to Resolve-ObservationWindow and Get-ResourceInventory
…forms

- Replace gzip scriptblock with nested function + [byte[]] cast to prevent
  PowerShell pipeline array unrolling that corrupted request bodies
- Switch from Invoke-WebRequest to Invoke-RestMethod with retry logic
  (3 attempts, exponential backoff) and status code logging
- Add kind: 'Direct' to DCR (required for Logs Ingestion API)
- Fix DCR stream declarations: PeriodStart/PeriodEnd as string with
  todatetime() in transform KQL to avoid extend-on-existing-column errors
- host.json: remove managedDependency (incompatible with Flex Consumption)
- profile.ps1: replace legacy MSI_SECRET with FUNCTIONS_WORKER_RUNTIME check
- requirements.psd1: simplify comments for Flex Consumption
- get-availability.ps1: extract Get-PlainToken helper (4 call sites),
  remove -UseBasicParsing (no-op in PS Core), drop ProgressPreference
  save/restore in Test-BatchEndpoints, remove stale C# reference
- README.md: consolidate C# legacy references into single blockquote
@marcelloformica
marcelloformica merged commit d04c68e into main Apr 27, 2026
1 check passed
@marcelloformica
marcelloformica deleted the dev branch April 27, 2026 17:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant