LibreDevOpsHelpers.AzurePowerShell/LibreDevOpsHelpers.AzurePowerShell.psm1
|
Set-StrictMode -Version Latest function ConvertTo-LdoSecureString { # Internal. Builds a read-only SecureString from a plaintext value without using # ConvertTo-SecureString -AsPlainText, which static analysis flags. [CmdletBinding()] [OutputType([System.Security.SecureString])] param([Parameter(Mandatory)][string]$PlainText) $secure = [System.Security.SecureString]::new() foreach ($char in $PlainText.ToCharArray()) { $secure.AppendChar($char) } $secure.MakeReadOnly() return $secure } function Connect-LdoAzurePowerShellClientSecret { <# .SYNOPSIS Signs in to Azure PowerShell with a service principal client secret. .PARAMETER ClientId The application (client) ID of the service principal. .PARAMETER ClientSecret The client secret as a SecureString. .PARAMETER TenantId The Entra tenant ID. .PARAMETER SubscriptionId Optional subscription to select after sign-in. .EXAMPLE Connect-LdoAzurePowerShellClientSecret -ClientId $id -ClientSecret $secure -TenantId $tid .OUTPUTS None #> [CmdletBinding()] [OutputType([void])] param( [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$ClientId, [Parameter(Mandatory)][ValidateNotNull()][System.Security.SecureString]$ClientSecret, [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$TenantId, [string]$SubscriptionId ) Write-LdoLog -Level INFO -Message 'Signing in to Azure PowerShell with a client secret.' $credential = [System.Management.Automation.PSCredential]::new($ClientId, $ClientSecret) Connect-AzAccount -ServicePrincipal -Credential $credential -Tenant $TenantId -ErrorAction Stop | Out-Null if ($SubscriptionId) { Set-AzContext -SubscriptionId $SubscriptionId -ErrorAction Stop | Out-Null } Write-LdoLog -Level SUCCESS -Message 'Client-secret sign-in complete.' } function Connect-LdoAzurePowerShellManagedIdentity { <# .SYNOPSIS Signs in to Azure PowerShell with a managed identity. .PARAMETER SubscriptionId Subscription to select after sign-in. .PARAMETER ManagedIdentityObjectId Optional client/object ID of a user-assigned managed identity. When omitted the system-assigned identity is used. .EXAMPLE Connect-LdoAzurePowerShellManagedIdentity -SubscriptionId $sub .OUTPUTS None #> [CmdletBinding()] [OutputType([void])] param( [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$SubscriptionId, [string]$ManagedIdentityObjectId ) Write-LdoLog -Level INFO -Message 'Signing in to Azure PowerShell with a managed identity.' if ($ManagedIdentityObjectId) { Connect-AzAccount -Identity -AccountId $ManagedIdentityObjectId -ErrorAction Stop | Out-Null } else { Connect-AzAccount -Identity -ErrorAction Stop | Out-Null } Set-AzContext -SubscriptionId $SubscriptionId -ErrorAction Stop | Out-Null Write-LdoLog -Level SUCCESS -Message 'Managed identity sign-in complete.' } function Connect-LdoAzurePowerShellDeviceCode { <# .SYNOPSIS Signs in to Azure PowerShell interactively using device code flow. .PARAMETER TenantId Optional tenant to sign in to. .PARAMETER SubscriptionId Optional subscription to select after sign-in. .EXAMPLE Connect-LdoAzurePowerShellDeviceCode -TenantId $tid .OUTPUTS None #> [CmdletBinding()] [OutputType([void])] param( [string]$TenantId, [string]$SubscriptionId ) Write-LdoLog -Level INFO -Message 'Signing in to Azure PowerShell with device code.' $connectParams = @{ UseDeviceAuthentication = $true; ErrorAction = 'Stop' } if ($TenantId) { $connectParams['Tenant'] = $TenantId } Connect-AzAccount @connectParams | Out-Null if ($SubscriptionId) { Set-AzContext -SubscriptionId $SubscriptionId -ErrorAction Stop | Out-Null } Write-LdoLog -Level SUCCESS -Message 'Device-code sign-in complete.' } function Test-LdoAzurePowerShellConnection { <# .SYNOPSIS Tests whether there is an active Azure PowerShell context. .DESCRIPTION Returns $true when Get-AzContext reports an active context with a subscription, otherwise $false. Does not throw. .EXAMPLE if (-not (Test-LdoAzurePowerShellConnection)) { throw 'Not signed in' } .OUTPUTS System.Boolean #> [CmdletBinding()] [OutputType([bool])] param() try { $context = Get-AzContext -ErrorAction Stop if ($context -and $context.Subscription) { Write-LdoLog -Level INFO -Message "Connected to Azure as $($context.Account.Id) on subscription $($context.Subscription.Name)." return $true } } catch { Write-LdoLog -Level DEBUG -Message "Get-AzContext failed: $($_.Exception.Message)" } Write-LdoLog -Level WARN -Message 'No active Azure PowerShell context.' return $false } function Disconnect-LdoAzurePowerShell { <# .SYNOPSIS Signs out of the current Azure PowerShell session. .EXAMPLE Disconnect-LdoAzurePowerShell .OUTPUTS None #> [CmdletBinding()] [OutputType([void])] param() try { Write-LdoLog -Level INFO -Message 'Disconnecting Azure PowerShell session.' Disconnect-AzAccount -ErrorAction Stop | Out-Null } catch { Write-LdoLog -Level WARN -Message "Azure PowerShell sign-out failed: $($_.Exception.Message)" } } function Connect-LdoAzurePowerShell { <# .SYNOPSIS Signs in to Azure PowerShell using the selected method and verifies the context. .DESCRIPTION Dispatches to the client-secret, managed-identity or device-code sign-in based on Method, reading the standard ARM_* environment variables. After sign-in it verifies an active context and throws if none is present. Environment variables used: ClientSecret : ARM_CLIENT_ID, ARM_CLIENT_SECRET, ARM_TENANT_ID, ARM_SUBSCRIPTION_ID ManagedIdentity : ARM_SUBSCRIPTION_ID, optional MANAGED_IDENTITY_OBJECT_ID DeviceCode : ARM_TENANT_ID, ARM_SUBSCRIPTION_ID .PARAMETER Method One of ClientSecret, ManagedIdentity or DeviceCode. Defaults to ManagedIdentity. .EXAMPLE Connect-LdoAzurePowerShell -Method ClientSecret .OUTPUTS None #> [CmdletBinding()] [OutputType([void])] param( [ValidateSet('ClientSecret', 'ManagedIdentity', 'DeviceCode')] [string]$Method = 'ManagedIdentity' ) switch ($Method) { 'ClientSecret' { Assert-LdoEnvironmentVariable -Name 'ARM_CLIENT_ID', 'ARM_CLIENT_SECRET', 'ARM_TENANT_ID', 'ARM_SUBSCRIPTION_ID' $secret = ConvertTo-LdoSecureString -PlainText $env:ARM_CLIENT_SECRET Connect-LdoAzurePowerShellClientSecret ` -ClientId $env:ARM_CLIENT_ID ` -ClientSecret $secret ` -TenantId $env:ARM_TENANT_ID ` -SubscriptionId $env:ARM_SUBSCRIPTION_ID } 'ManagedIdentity' { Assert-LdoEnvironmentVariable -Name 'ARM_SUBSCRIPTION_ID' Connect-LdoAzurePowerShellManagedIdentity ` -SubscriptionId $env:ARM_SUBSCRIPTION_ID ` -ManagedIdentityObjectId $env:MANAGED_IDENTITY_OBJECT_ID } 'DeviceCode' { Assert-LdoEnvironmentVariable -Name 'ARM_SUBSCRIPTION_ID' Connect-LdoAzurePowerShellDeviceCode ` -TenantId $env:ARM_TENANT_ID ` -SubscriptionId $env:ARM_SUBSCRIPTION_ID } } if (-not (Test-LdoAzurePowerShellConnection)) { throw 'Azure PowerShell sign-in did not produce an active context.' } } Export-ModuleMember -Function ` Connect-LdoAzurePowerShellClientSecret, ` Connect-LdoAzurePowerShellManagedIdentity, ` Connect-LdoAzurePowerShellDeviceCode, ` Test-LdoAzurePowerShellConnection, ` Disconnect-LdoAzurePowerShell, ` Connect-LdoAzurePowerShell |