Private/Connect-Sentinel.ps1
|
function Connect-Sentinel { <# .SYNOPSIS Authenticates to Azure and resolves the target Sentinel workspace. .OUTPUTS PSCustomObject with SubscriptionId, ResourceGroup, WorkspaceName, WorkspaceId, ResourceId, tokens, workspace facts and Endpoints. #> [CmdletBinding()] param( [Parameter(Mandatory)][string]$SubscriptionId, [Parameter(Mandatory)][string]$ResourceGroup, [Parameter(Mandatory)][string]$WorkspaceName, [string]$WorkspaceId ) # Authenticate only if not already connected to the right subscription $ctx = Get-AzContext -ErrorAction SilentlyContinue if (-not $ctx -or $ctx.Subscription.Id -ne $SubscriptionId) { Write-Verbose "Authenticating to subscription $SubscriptionId ..." Connect-AzAccount -SubscriptionId $SubscriptionId -ErrorAction Stop -WarningAction SilentlyContinue | Out-Null $ctx = Get-AzContext } else { Write-Verbose "Already connected to subscription $SubscriptionId." } # Endpoints for the signed-in cloud (public defaults when the environment does not supply them) $endpoints = Resolve-LogHorizonEndpoints -Environment $ctx.Environment Write-Verbose "Azure environment: $($endpoints.Name) (ARM $($endpoints.Arm))" # Acquire ARM token $token = Resolve-AzToken -ResourceUrl $endpoints.Arm # Acquire Log Analytics token $laToken = Resolve-AzToken -ResourceUrl $endpoints.LogAnalyticsResource # Resolve workspace via REST (no Az.Resources dependency) $resourceId = "/subscriptions/$SubscriptionId/resourceGroups/$ResourceGroup" + "/providers/Microsoft.OperationalInsights/workspaces/$WorkspaceName" $wsUri = "$($endpoints.Arm)${resourceId}?api-version=2025-07-01" $ws = Invoke-AzRestWithRetry -Uri $wsUri -Headers @{ Authorization = "Bearer $token" } $resolvedWsId = $ws.properties.customerId # Log Analytics workspace GUID if ([string]::IsNullOrWhiteSpace("$resolvedWsId")) { throw "Workspace '$WorkspaceName' in resource group '$ResourceGroup' returned no customerId; check the name and your permissions." } if ($WorkspaceId -and $resolvedWsId -ne $WorkspaceId) { Write-Warning "Supplied WorkspaceId ($WorkspaceId) differs from resolved ID ($resolvedWsId). Using resolved." } [PSCustomObject]@{ SubscriptionId = $SubscriptionId TenantId = $ctx.Tenant.Id ResourceGroup = $ResourceGroup WorkspaceName = $WorkspaceName WorkspaceId = $resolvedWsId ResourceId = $resourceId ArmToken = $token LaToken = $laToken Region = $ws.location WorkspaceRetentionDays = if ($null -ne $ws.properties.retentionInDays) { [int]$ws.properties.retentionInDays } else { $null } DefaultDataCollectionRuleResourceId = $ws.properties.defaultDataCollectionRuleResourceId Endpoints = $endpoints } } function Resolve-AzToken { <# .SYNOPSIS Wraps Get-AzAccessToken and handles both plain-string and SecureString token formats across Az module versions. #> [CmdletBinding()] param( [string]$ResourceUrl, [string]$TenantId ) $splat = @{ ResourceUrl = $ResourceUrl; ErrorAction = 'Stop' } if (-not [string]::IsNullOrWhiteSpace($TenantId)) { $splat.TenantId = $TenantId } $tokenObj = Get-AzAccessToken @splat $raw = $tokenObj.Token if ($raw -is [System.Security.SecureString]) { [System.Net.NetworkCredential]::new('', $raw).Password } else { [string]$raw } } |