Public/Connect-PSDVOrg.ps1
|
function Connect-PSDVOrg { <# .SYNOPSIS Establishes a connection to a Microsoft Dataverse organization. .DESCRIPTION Connect-PSDVOrg creates an authenticated connection to a Microsoft Dataverse environment using various authentication methods. It supports service principal authentication with client secrets or certificates, managed identity authentication, and interactive browser login. Upon successful connection, it retrieves and stores an access token for subsequent Dataverse API calls. .PARAMETER ClientID The Application (client) ID of the Azure AD application registration used for service principal authentication. .PARAMETER ClientSecret The client secret (secure string) for the Azure AD application used for service principal authentication. .PARAMETER Certificate The X.509 certificate with private key used for service principal authentication. .PARAMETER CertificateThumbprint The thumbprint of a certificate with private key in the CurrentUser or LocalMachine personal certificate store. .PARAMETER CertificatePath The path to a PFX certificate file used for service principal authentication. .PARAMETER CertificatePassword The optional PFX certificate password. .PARAMETER ManagedIdentityID The client ID, object ID, or Azure resource ID of the managed identity to use for authentication in Azure environments (user-assigned managed identity). FunctionRuntime token acquisition supports client ID or Azure resource ID. .PARAMETER UseSystemManagedIdentity When specified, uses the system-assigned managed identity for authentication. No additional identity configuration is required. .PARAMETER AzureTenantId The Microsoft Entra tenant ID where the Dataverse environment is located. Required for client secret and interactive authentication. .PARAMETER SubscriptionId Optional legacy parameter retained for compatibility with older examples. It is no longer used because this module no longer connects an Azure subscription context. .PARAMETER DataverseOrgURL The URL of the Dataverse organization (e.g., https://orgname.crm.dynamics.com/). .PARAMETER Environment The Azure cloud authority host to use for OAuth token acquisition. Defaults to AzureCloud. .PARAMETER UseDeviceCode Uses device code authentication instead of the default browser-based interactive authentication. .PARAMETER ManagedIdentityTokenSource Controls how managed identity tokens are acquired. AzureIdentity uses the bundled Azure.Identity SDK. FunctionRuntime calls the Azure Functions/App Service managed identity endpoint directly without loading Azure.Identity. .PARAMETER AccessToken A bearer access token (secure string) already acquired for the Dataverse resource using external tooling such as Get-AzAccessToken or 'az account get-access-token'. When supplied, the module uses this token directly and does not load Azure.Identity or acquire a token itself. The token cannot be refreshed automatically; reconnect with a new token when it expires. .PARAMETER AccessTokenExpiresOn The expiration time of the supplied access token. If omitted, the expiration is read from the token's 'exp' claim when possible. Provide this value (for example, the ExpiresOn returned by Get-AzAccessToken) when the expiration cannot be determined automatically. .EXAMPLE Connect-PSDVOrg -AzureTenantId "12345678-1234-1234-1234-123456789012" -DataverseOrgURL "https://contoso.crm.dynamics.com/" Connects to Dataverse using interactive authentication. .EXAMPLE $secret = ConvertTo-SecureString "MyClientSecret" -AsPlainText -Force Connect-PSDVOrg -ClientID "12345678-1234-1234-1234-123456789012" -ClientSecret $secret -AzureTenantId "87654321-4321-4321-4321-210987654321" -DataverseOrgURL "https://contoso.crm.dynamics.com/" -Environment "AzureCloud" Connects to Dataverse using service principal authentication. .EXAMPLE Connect-PSDVOrg -ClientID "12345678-1234-1234-1234-123456789012" -CertificateThumbprint "ABCDEF1234567890ABCDEF1234567890ABCDEF12" -AzureTenantId "87654321-4321-4321-4321-210987654321" -DataverseOrgURL "https://contoso.crm.dynamics.com/" Connects to Dataverse using service principal certificate authentication. .EXAMPLE Connect-PSDVOrg -ManagedIdentityID "12345678-1234-1234-1234-123456789012" -DataverseOrgURL "https://contoso.crm.dynamics.com/" Connects to Dataverse using user-assigned managed identity authentication. .EXAMPLE Connect-PSDVOrg -UseSystemManagedIdentity -DataverseOrgURL "https://contoso.crm.dynamics.com/" Connects to Dataverse using system-assigned managed identity authentication. .EXAMPLE Connect-PSDVOrg -UseSystemManagedIdentity -ManagedIdentityTokenSource FunctionRuntime -DataverseOrgURL "https://contoso.crm.dynamics.com/" Connects to Dataverse using the Azure Functions/App Service managed identity endpoint directly without loading Azure.Identity. .EXAMPLE $token = Get-AzAccessToken -ResourceUrl "https://contoso.crm.dynamics.com/" -AsSecureString Connect-PSDVOrg -AccessToken $token.Token -AccessTokenExpiresOn $token.ExpiresOn -DataverseOrgURL "https://contoso.crm.dynamics.com/" Connects to Dataverse using a bearer token acquired with Get-AzAccessToken, without loading Azure.Identity. #> [CmdletBinding(DefaultParameterSetName = 'InteractiveLogin')] param ( [Parameter(Mandatory, ParameterSetName = 'ClientSecret')] [Parameter(Mandatory, ParameterSetName = 'ClientCertificate')] [Parameter(Mandatory, ParameterSetName = 'ClientCertificateThumbprint')] [Parameter(Mandatory, ParameterSetName = 'ClientCertificatePath')] [String] $ClientID, [Parameter(Mandatory, ParameterSetName = 'ClientSecret')] [SecureString] $ClientSecret, [Parameter(Mandatory, ParameterSetName = 'ClientCertificate')] [System.Security.Cryptography.X509Certificates.X509Certificate2] $Certificate, [Parameter(Mandatory, ParameterSetName = 'ClientCertificateThumbprint')] [String] $CertificateThumbprint, [Parameter(Mandatory, ParameterSetName = 'ClientCertificatePath')] [String] $CertificatePath, [Parameter(ParameterSetName = 'ClientCertificatePath')] [SecureString] $CertificatePassword, [Parameter(Mandatory, ParameterSetName = 'ManagedIdentity')] [String] $ManagedIdentityID, [Parameter(Mandatory, ParameterSetName = 'SystemManagedIdentity')] [Switch] $UseSystemManagedIdentity, [Parameter(Mandatory, ParameterSetName = 'ClientSecret')] [Parameter(Mandatory, ParameterSetName = 'ClientCertificate')] [Parameter(Mandatory, ParameterSetName = 'ClientCertificateThumbprint')] [Parameter(Mandatory, ParameterSetName = 'ClientCertificatePath')] [Parameter(Mandatory, ParameterSetName = 'InteractiveLogin')] [String] $AzureTenantId, [Parameter(ParameterSetName = 'InteractiveLogin')] [String] $SubscriptionId, [Parameter(Mandatory)] [String] $DataverseOrgURL, [Parameter()] [ValidateSet('AzureCloud', 'AzureChinaCloud', 'AzureUSGovernment', 'AzureGermanCloud')] [String] $Environment = 'AzureCloud', [Parameter(ParameterSetName = 'InteractiveLogin')] [Switch] $UseDeviceCode, [Parameter(ParameterSetName = 'ManagedIdentity')] [Parameter(ParameterSetName = 'SystemManagedIdentity')] [ValidateSet('AzureIdentity', 'FunctionRuntime')] [String] $ManagedIdentityTokenSource = 'AzureIdentity', [Parameter(Mandatory, ParameterSetName = 'AccessToken')] [SecureString] $AccessToken, [Parameter(ParameterSetName = 'AccessToken')] [DateTimeOffset] $AccessTokenExpiresOn ) #Ensure DataverseOrgURL has a trailing slash if (-not $DataverseOrgURL.EndsWith('/')) { $DataverseOrgURL = $DataverseOrgURL + '/' } if ($PSBoundParameters.ContainsKey('SubscriptionId')) { Write-Warning 'The -SubscriptionId parameter is deprecated and no longer used. It is planned for removal in the next major version.' } $authContext = @{ ParameterSetName = $PSCmdlet.ParameterSetName ResourceUrl = $DataverseOrgURL ClientID = $ClientID ClientSecret = $ClientSecret Certificate = $Certificate CertificateThumbprint = $CertificateThumbprint CertificatePath = $CertificatePath CertificatePassword = $CertificatePassword AzureTenantId = $AzureTenantId ManagedIdentityID = $ManagedIdentityID Environment = $Environment SubscriptionId = $SubscriptionId UseDeviceCode = $UseDeviceCode.IsPresent ManagedIdentityTokenSource = $ManagedIdentityTokenSource } $suppliedAccessToken = $null if ($PSCmdlet.ParameterSetName -eq 'AccessToken') { if ($PSBoundParameters.ContainsKey('AccessTokenExpiresOn')) { $tokenExpiresOn = $AccessTokenExpiresOn.UtcDateTime } else { $tokenExpiresOn = $null try { $rawToken = ConvertFrom-PSDVSecureString -SecureString $AccessToken $tokenParts = $rawToken.Split('.') if ($tokenParts.Count -ge 2) { $payloadSegment = $tokenParts[1].Replace('-', '+').Replace('_', '/') switch ($payloadSegment.Length % 4) { 2 { $payloadSegment += '==' } 3 { $payloadSegment += '=' } } $payloadJson = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($payloadSegment)) $payloadClaims = $payloadJson | ConvertFrom-Json if (($payloadClaims.PSObject.Properties.Name -contains 'exp') -and $payloadClaims.exp) { $tokenExpiresOn = [DateTimeOffset]::FromUnixTimeSeconds([long]$payloadClaims.exp).UtcDateTime } } } catch { $tokenExpiresOn = $null } if ($null -eq $tokenExpiresOn) { throw 'Unable to determine the supplied access token expiration. Provide -AccessTokenExpiresOn (for example, the ExpiresOn value returned by Get-AzAccessToken).' } } $suppliedAccessToken = [PSCustomObject]@{ Token = $AccessToken ExpiresOn = $tokenExpiresOn } } try { Write-Verbose "Getting Dataverse Access Token for $DataverseOrgUrl" if ($PSCmdlet.ParameterSetName -eq 'AccessToken') { $dvAccessToken = $suppliedAccessToken } else { $dvAccessToken = Get-PSDVAccessToken -AuthContext $authContext } Set-PSDVAccessToken -AccessToken $dvAccessToken -AuthContext $authContext -Operation 'Initial token acquisition' $Global:DATAVERSEAUTHCONTEXT = $authContext $Global:DATAVERSEORGURL = $DataverseOrgURL } catch { throw "Error executing $($_.InvocationInfo.MyCommand.Name), $($_ | Out-String)" } } |