Search code examples
azurepowershellazure-automation

Unable to connect-AZAccount in Azure Automation with a Service Principal


I have an Azure Automation Runbook that needs to Connect-AzAccount to export a CSV from the Automation Account to a Blob Storage Account. My Service Principal has an ApplicationID and a Secret. per the documentation for Connect-AzAccount -Credential can accept this.

However when I attempt to feed it in via:

$Credential = New-Object -TypeName System.Management.Automation.PSCredential($ApplicationID, $AppSecret)
Connect-AzAccount -ServicePrincipal -TenantId $TenantId -Credential $Credential

I get the following error:

Cannot bind argument to parameter 'Credential' because it is null

Would anyone be able to point me to where I am messing up?


Solution

  • tl;dr

    Since the root cause turned out to be the following error:

    Cannot find overload for "PSCredential" and the argument count: "2".

    the implication is that the $AppSecret argument in your New-Object -TypeName PSCredential call was not of type [securestring], which is what the relevant [pscredential] constructor overload requires.

    Making it a [securestring] instance solved your problem.


    A [securestring] instance can be constructed or obtained in several ways:

    Alternatively, you could obtain the entire [pscredential] instance differently:

    • Interactively, via Get-Credential:

      # Prompts for the app secret (password) and returns a [pscredential] instance.
      $Credential = Get-Credential $ApplicationID
      
    • On Windows only, import a [pscredential] instance that was previously persisted to a file with Export-Clixml with Import-Clixml - see this answer.

    A general caveat: [securestring] offers limited security on Windows, and virtually none on Unix-like platforms, where encryption isn't even employed - see this answer.


    As for what you tried and the error message you saw:

    New-Object -TypeName System.Management.Automation.PSCredential($ApplicationID, $AppSecret)

    This command can be simplified to:

    New-Object pscredential $ApplicationID, $AppSecret
    # Short for:
    #  New-Object -TypeName pscredential -ArgumentList $ApplicationID, $AppSecret
    

    Note:

    New-Object calls translate into .NET constructor calls, and in PowerShell 5 and above there's now a a more direct way to call constructors, using the static ::new() method exposed by PowerShell on types. Therefore, the equivalent of the command above is:

    # PSv5+ equivalent of the above.
    # Note that this syntax *does* require method-call syntax.
    [pscredential]::new($ApplicationID, $AppSecret)
    

    The advantage of this approach is that you can easily inspect the constructor overloads (variants with different parameters), simply by accessing ::new without the (...) part:

    # Print constructor overloads
    [pscredential]::new
    

    Output:

    OverloadDefinitions
    -------------------
    pscredential new(string userName, securestring password)
    pscredential new(psobject pso)
    

    The first overload - the only one to accept two arguments - also reveals the parameter types, and indeed shows that the second parameter requires a [securestring] instance as its argument.

    Unfortunately, the error message you get when the count of arguments is correct but the type isn't is somewhat misleading:

    Cannot find overload for "PSCredential" and the argument count: "2".

    Clearly, you did pass 2 arguments, but it was the fact that the 2nd argument had the wrong type that triggered the error, whereas the message makes it sound like you passed the wrong number of arguments.

    Improving this error message has been green-lit in GitHub issue #3658, but so far no one has stepped up to implement it.