0

I have a script executed as bicep DeploymentScript in Azure DevOps. It executes Azure SQL Server commands and has worked up until the breaking changes made by Microsoft 5th June this year.

TLDR: The scripts below use the new MS Graph syntax for the June 5th breaking changes.

  • What format is the (Get-AzAccessToken -ResourceTypeName MSGraph).Token?
  • How do I use it in Invoke-Sqlcmd and returning the token from the bicep DeploymentScript?
  • How do I get the Token's string to return back from the DeploymentScript?

NOTE: I've tried both $token and $secureToken and neither worked.

The DeploymentScript commands is:

resource identity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = {
  name: sqlAdminUmiName
}

var sqlServerHostname = environment().suffixes.sqlServerHostname
var tokenResourceUrl = 'https://${substring(sqlServerHostname, 1)}'
      
resource deploymentScriptServerGroupAssignment 'Microsoft.Resources/deploymentScripts@2020-10-01' = {
  name: name
  location: location
  kind: 'AzurePowerShell'
  identity: {
    type: 'UserAssigned'
    userAssignedIdentities: {
      '${identity.id}': {}
    }
  }
  properties: {
    azPowerShellVersion: '8.3'
    arguments: '-dbHost "${dbHost}" -tokenResourceUrl "${tokenResourceUrl}" -dbName "${dbName}" -fxaName "${fxaName}" '
    scriptContent: '''
      param(
        [string] $dbHost,
        [string] $tokenResourceUrl,
        [string] $dbName,
        [string] $fxaName,
        [string] $dbRoleNames
      )
      
      echo "Step 0: about to Install-Module Microsoft.Graph -Force"
      Install-Module -Name SqlServer -Force
      Import-Module -Name SqlServer
      $token = (Get-AzAccessToken -ResourceTypeName MSGraph).Token
      echo "Step 1: token - $token"

      $secureToken = ConvertTo-SecureString $token -AsPlainText -Force
      echo "Step 2: secureToken - $secureToken"
      
      
      $query = @()
      $query += "DROP USER IF EXISTS `"$fxaName`""
      $query += "CREATE USER `"$fxaName`" FROM external provider"
      $query += "ALTER ROLE db_owner ADD MEMBER `"$fxaName`""
      $query += "ALTER ROLE db_datareader ADD MEMBER `"$fxaName`""
      $query += "ALTER ROLE db_datawriter ADD MEMBER `"$fxaName`""
      $query += "ALTER ROLE db_ddladmin ADD MEMBER `"$fxaName`""

      $query = $query -join ";"
      Invoke-Sqlcmd -ServerInstance $dbHost -Database $dbName -AccessToken "$secureToken" -Query $query
    '''
    retentionInterval: 'PT1H'
    cleanupPreference: 'OnSuccess'
    forceUpdateTag: currentTime
  }
}

The Error in the Deployment plan in Azure portal is:

Microsoft.Data.SqlClient.SqlException (0x80131904): Login failed for user '<token-identified principal>'.

and

Microsoft.SqlTools.ServiceLayer.BatchParser.BatchParserException: Incorrect syntax was encountered while parsing

I asked a similar question this week for PowerShell execution and the recent MS Graph breaking changes per here

The both the older version of my code with the breaking change, and the syntax that worked for the previous question both still given the same errors. For reference, the new syntax I'm using is:

  $token = (Get-AzAccessToken -ResourceTypeName MSGraph).Token

I have another script which has the same line and is not working (same type of Bicep DeploymentScript wrapper as the one above - sub snippet for conciseness):

  $token = (Get-AzAccessToken -ResourceTypeName MSGraph).Token
  echo "Step 1: token - $token"
  
  $secureToken = ConvertTo-SecureString $token -AsPlainText -Force
  echo "Step 2: secureToken - $secureToken"
  
  Write-Host "##vso[task.setvariable variable=dbToken;isOutput=true]$secureToken"
  
  $DeploymentScriptOutputs = @{}
  $DeploymentScriptOutputs['dbAccess'] = $secureToken

It returns the error:

The template output 'dbToken' is not valid: The provided value for the template output 'dbToken' is not valid. Expected a value of type 'String, Uri', but received a value of type 'Object'.
2
  • Use the MS Graph token directly as a plain string in Invoke-Sqlcmd -AccessToken $token without converting to SecureString, and return it from the DeploymentScript using $DeploymentScriptOutputs = @{ dbAccess = $token } to meet Bicep output type requirements. @AidenDipple Commented Jun 7 at 7:55
  • Thanks for the input @Vinay B. As mentioned under the TLDR: NOTE: I've tried both $token and $secureToken and neither worked. Using the $token without converting it gives the same error message. Given the "object type return value" error message, is the .Token and object or a string? Commented Jun 7 at 18:24

1 Answer 1

0

I found a very helpful article that discusses the inability of Invoke-SqlCmd to accept a SecureString object.

https://github.com/Azure/azure-powershell/issues/25533

One contributor (dadthiele) share the magic code that solves the question about returned object error not being a string (half points to me!):

$accessToken = (ConvertFrom-SecureString $token -AsPlainText)

Note the Convert**From**SecureString instead of Convert**To**SecureString

However, this still does not solve the error on authenticating to Invoke-SqlCmd.

Microsoft.Data.SqlClient.SqlException (0x80131904): Login failed for user ''.

To solve that I read the full article and there was the answer already in the above post.

Instead of getting the token with:

  $token = (Get-AzAccessToken -ResourceTypeName MSGraph).Token

it needed this:

  $token = (Get-AzAccessToken -ResourceUrl https://database.windows.net -AsSecureString).Token
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.