英文:
Unable to connect-AZAccount in Azure Automation with a Service Principal
问题
我有一个Azure自动化Runbook,需要使用Connect-AzAccount连接到Automation帐户中的Blob存储帐户导出CSV。我的服务主体有一个ApplicationID和一个Secret。根据Connect-AzAccount的文档,-Credential参数可以接受这些信息。
然而,当我尝试通过以下方式传递它:
$Credential = New-Object -TypeName System.Management.Automation.PSCredential($ApplicationID, $AppSecret)
Connect-AzAccount -ServicePrincipal -TenantId $TenantId -Credential $Credential
我收到以下错误消息:
无法将参数'Credential'绑定到参数,因为它为null。
有人能指出我哪里出错吗?
英文:
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?
答案1
得分: 2
以下是您要求的中文翻译:
**tl;dr**
由于 _根本原因_ 是以下错误:
> `找不到“PSCredential”的重载和参数计数:“2”。`
这意味着 **在您的 `New-Object -TypeName PSCredential` 调用中,`$AppSecret` 参数不是 [`[securestring]`](https://learn.microsoft.com/en-US/dotnet/api/System.Security.SecureString) 类型,这是[相关 `[pscredential]` 构造函数重载](https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.pscredential.-ctor#system-management-automation-pscredential-ctor(system-string-system-security-securestring))所需要的。
将其改为 `[securestring]` 实例解决了您的问题。
---
可以通过几种方式构建或获取 `[securestring]` 实例:
* 最好的方式是从秘密管理系统加载密钥,例如支持各种扩展模块的 [`Microsoft.PowerShell.SecretManagement`](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.secretmanagement/?view=ps-modules) 模块,例如用于本地文件系统存储的 [`Microsoft.PowerShell.SecretStore`](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.secretstore/?view=ps-modules) 和用于从Azure密钥保管库检索密钥的 [`Az.KeyVault`](https://www.powershellgallery.com/packages/Az.KeyVault) 模块。
* [出于安全原因不建议] 使用 [`ConvertTo-SecureString`](https://learn.microsoft.com/powershell/module/microsoft.powershell.security/convertto-securestring) `-AsPlainText` 将密钥的纯文本表示转换为 `[securestring]`。
或者,您可以以不同的方式获取整个 `[pscredential]` 实例:
* 以 _交互方式_,通过 [`Get-Credential`](https://learn.microsoft.com/powershell/module/microsoft.powershell.security/get-credential):
# 提示输入应用程序密钥(密码)并返回一个 [pscredential] 实例。
$Credential = Get-Credential $ApplicationID
* 仅在Windows上,导入以前使用 [`Export-Clixml`](https://learn.microsoft.com/powershell/module/microsoft.powershell.utility/export-clixml) 持久保存到 _文件_ 的 `[pscredential]` 实例,然后使用 [`Import-Clixml`](https://learn.microsoft.com/powershell/module/microsoft.powershell.utility/import-clixml) - 请参阅[此答案](https://stackoverflow.com/a/40029496/45375)。
一般警告:`[securestring]` 在Windows上提供了 _有限的_ 安全性,在类Unix平台上几乎没有安全性,甚至没有使用加密 - 请参阅[此答案](https://stackoverflow.com/a/60406968/45375)。
---
至于 **您尝试的内容** 和您看到的 **错误消息**:
> `New-Object -TypeName System.Management.Automation.PSCredential($ApplicationID, $AppSecret)`
这个命令可以简化为:
```shell
New-Object pscredential $ApplicationID, $AppSecret
# 等同于:
# New-Object -TypeName pscredential -ArgumentList $ApplicationID, $AppSecret
注意:
-
使用短名称
pscredential
,因为它是类型加速器用于完整类型名称System.Management.Automation.PSCredential
。 -
在参数周围没有
(...)
,因为它相当于应该避免的伪方法语法 - 请参阅此答案。
New-Object
调用转化为.NET中的 构造函数 调用,在PowerShell 5及以上版本中,现在有了一种使用PowerShell在类型上公开的静态 ::new()
方法直接调用构造函数的方式。因此,上述命令的等效方式是:
# 与上述相同的PSv5+版本。
# 请注意,这种语法确实需要方法调用语法。
[pscredential]::new($ApplicationID, $AppSecret)
这种方法的优点是您可以通过简单访问 ::new
不带 (...)
部分 来轻松检查构造函数的 重载(具有不同参数的变体):
# 打印构造函数的重载
[pscredential]::new
输出:
OverloadDefinitions
-------------------
pscredential new(string userName, securestring password)
pscredential new(psobject pso)
第一个重载 - 唯一接受 两个 参数的重载 - 还显示了参数的 类型,并且确实显示第二个参数需要一个 [securestring]
实例作为其参数。
不幸的是,当参数的 数量 正确但 类型 错误时,您获得的 错误消息 有点误导:
> 找不到“PSCredential”的重载和参数计数:“2”。
显然,您确实传递了 2 个参数,但是第二个参数的类型不正确触发了错误,而消息使其听起来好像您传递了错误的 参数数量。
改进此错误消息已经在 GitHub问题 #3658 中得到批准,但到目前为止还没有人采取行动来实现它。
<details>
<summary>英文:</summary>
<!-- language-all: sh -->
**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]`](https://learn.microsoft.com/en-US/dotnet/api/System.Security.SecureString)**, which is what the [relevant `[pscredential]` constructor overload](https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.pscredential.-ctor#system-management-automation-pscredential-ctor(system-string-system-security-securestring)) 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`](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.secretmanagement/?view=ps-modules) module, which supports various extension modules implementing _vaults_ (secrets stores), such as [`Microsoft.PowerShell.SecretStore`](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.secretstore/?view=ps-modules) for local file-system storage and the [`Az.KeyVault`](https://www.powershellgallery.com/packages/Az.KeyVault) module for retrieving secrets from an Azure Key Vault.
* [Not advisable for security reasons] Use [`ConvertTo-SecureString`](https://learn.microsoft.com/powershell/module/microsoft.powershell.security/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`](https://learn.microsoft.com/powershell/module/microsoft.powershell.security/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`](https://learn.microsoft.com/powershell/module/microsoft.powershell.utility/export-clixml) with [`Import-Clixml`](https://learn.microsoft.com/powershell/module/microsoft.powershell.utility/import-clixml) - see [this answer](https://stackoverflow.com/a/40029496/45375).
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](https://stackoverflow.com/a/60406968/45375).
---
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](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_Type_Accelerators) for the full type name, [`System.Management.Automation.PSCredential`](https://learn.microsoft.com/en-US/dotnet/api/System.Management.Automation.PSCredential).
* The absence of `(...)` around the arguments, as that amounts to _pseudo method syntax_ that is best avoided - see [this answer](https://stackoverflow.com/a/50636061/45375).
`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
Output:
```none
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论