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?
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:
Preferably, load the secret from a secrets-management system, such as the Microsoft.PowerShell.SecretManagement
module, which supports various extension modules implementing vaults (secrets stores), such as Microsoft.PowerShell.SecretStore
for local file-system storage and the Az.KeyVault
module for retrieving secrets from an Azure Key Vault.
[Not advisable for security reasons] Use ConvertTo-SecureString
-AsPlainText
to convert a plain-text representation of the secret to a [securestring]
.
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:
The use of short name pscredential
, given that it is a type accelerator for the full type name, System.Management.Automation.PSCredential
.
The absence of (...)
around the arguments, as that amounts to pseudo method syntax that is best avoided - see this answer.
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.