我有一个Powershell函数,它接受一个PSCredential对象。如果PSCredential为null,我想自己在函数中专门处理它。但是,最终发生的事情是我收到了PSCredential提示(与运行Get-Credential
时的提示相同)。
在我的下面的脚本中,我创建了Credential
参数集所需的参数,我希望它可以使用[AllowNull()]
为空,但这并不会阻止提示出现。
这是我的功能:
<#
.description
Create a new Connection String Builder object
.parameter existingCSB
Use the passed CSB as the base, but allow it to be overridden.
.parameter property
Hashtable containing named properties for a connection string builder.
Will override values on -existingCSB.
.parameter credential
Use these credentials. Will override values on -existingCSB and any values
passed as -property.
NOTE: If this parameter is null, or if EITHER the username OR password in
the credential is an empty string, use a trusted connection aka
integrated security instead
.parameter username
Use this username. Will override values on -existingCSB and any values
passed as -property
NOTE: If EITHER the username OR password is null or an empty string, use a
trusted connection / integrated security instead
.parameter password
Use this password. Can be a string or a SecureString object. Will override
values on -existingCSB and any values passed as -property
NOTE: If EITHER the username OR password is null or an empty string, use a
trusted connection / integrated security instead
#>
function New-DbConnectionStringBuilder {
[cmdletbinding(DefaultParameterSetName="NoCredential")] param(
[System.Data.Common.DbConnectionStringBuilder] $existingCSB,
[Hashtable] $property,
[Parameter(Mandatory=$true, ParameterSetName="Credential")]
[AllowNull()] [System.Management.Automation.PSCredential] $credential,
[Parameter(Mandatory=$true, ParameterSetName="UserPass")]
[AllowEmptyString()] [string] $username,
[Parameter(Mandatory=$true, ParameterSetName="UserPass")]
[AllowNull()] $password
)
$newDbCSB = New-Object System.Data.Common.DbConnectionStringBuilder $true
if ($existingCSB.Keys.Count -gt 0) {
$existingCSB.Keys |% { $newDbCSB[$_] = [String]::Copy($existingCSB[$_]) }
}
if ($property.Keys.Count -gt 0) {
$property.Keys |% { $newDbCSB[$_] = [String]::Copy($property[$_]) }
}
if ($PsCmdlet.ParameterSetName -notmatch "NoCredential") {
if ($credential) {
$username = $credential.UserName
$password = $credential.Password
}
if ($password -and $password.GetType().FullName -eq "System.Security.SecureString") {
$password = Decrypt-SecureString $password
}
if ($username -and $password) {
$newDbCSB["Uid"] = $username
$newDbCSB["Pwd"] = $password
$newDbCSB.Remove("Trusted_Connection") | Out-Null
}
else {
$newDbCSB["Uid"] = $null
$newDbCSB["Pwd"] = $null
$newDbCSB["Trusted_Connection"] = "yes"
}
}
return $newDbCSB
}
这里有一些代码可以调用它:
$csb = New-DbConnectionStringBuilder -credential $null
Write-Host "UID: $($csb['Uid'])"
Write-Host "Trusted_Connection: $($csb['Trusted_Connection'])"
如果您有兴趣,我这样做的原因是为了与现有代码兼容。我们有一些脚本可以从签入Git的加密文件中获取凭据。如果凭证不存在,现有代码将返回$ null,作为应该使用集成安全性的指示。
我想要总结的行为是:如果根本没有传递凭据,请不要将凭据信息添加到CSB;如果凭据被传递但$ null,则使用集成安全性(又名&#34;可信连接&#34;);如果凭据被传递而不是null,则在CSB中使用它们。
答案 0 :(得分:3)
没有任何东西叫做空值PSCredential
- 参数。它会强制您输入某种类型的凭据。最简单的解决方案是检查要传递到-Credential
的输入,并将其替换为[pscredential]::Empty
,如果它是$null
。实施例
$creds = $null
if($creds -eq $null) { $creds = ([System.Management.Automation.PSCredential]::Empty) }
$csb = New-DbConnectionStringBuilder -credential $creds
此外,您可以使用以下方法简化密码部分:
if ($credential) {
$username = $credential.UserName
$password = $credential.GetNetworkCredential().Password
}
修改后的解决方案:
function New-DbConnectionStringBuilder {
[cmdletbinding(DefaultParameterSetName="NoCredential")] param(
[System.Data.Common.DbConnectionStringBuilder] $existingCSB,
[Hashtable] $property,
[Parameter(Mandatory=$true, ParameterSetName="Credential")]
[System.Management.Automation.PSCredential] $credential,
[Parameter(Mandatory=$true, ParameterSetName="UserPass")]
[string] $username,
[Parameter(Mandatory=$true, ParameterSetName="UserPass")]
$password
)
$newDbCSB = New-Object System.Data.Common.DbConnectionStringBuilder $true
if ($existingCSB.Keys.Count -gt 0) {
$existingCSB.Keys |% { $newDbCSB[$_] = [String]::Copy($existingCSB[$_]) }
}
if ($property.Keys.Count -gt 0) {
$property.Keys |% { $newDbCSB[$_] = [String]::Copy($property[$_]) }
}
if($PsCmdlet.ParameterSetName -ne "NoCredential") {
if ($PsCmdlet.ParameterSetName -eq "Credential" -and $credential -ne [System.Management.Automation.PSCredential]::Empty) {
$username = $credential.UserName.Split("\")[-1]
$password = $credential.GetNetworkCredential().Password
}
if ($username -and $password) {
$newDbCSB["Uid"] = $username
$newDbCSB["Pwd"] = $password
$newDbCSB.Remove("Trusted_Connection") | Out-Null
}
else {
$newDbCSB["Uid"] = $null
$newDbCSB["Pwd"] = $null
$newDbCSB["Trusted_Connection"] = "yes"
}
}
$newDbCSB
}
演示:
Write-host
Write-host Null creds
Write-host
$creds = $null
if($creds -eq $null) { $creds = ([System.Management.Automation.PSCredential]::Empty) }
$csb = New-DbConnectionStringBuilder -credential $creds
Write-Host "UID: $($csb["Uid"])"
write-host "pass: $($csb["pwd"])"
Write-Host "Trusted_Connection: $($csb["Trusted_Connection"])"
Write-host
Write-host Creds
Write-host
$creds = New-Object System.Management.Automation.PSCredential "frode", (ConvertTo-SecureString -String "lol" -AsPlainText -Force)
if($creds -eq $null) { $creds = ([System.Management.Automation.PSCredential]::Empty) }
$csb = New-DbConnectionStringBuilder -credential $creds
Write-Host "UID: $($csb["Uid"])"
write-host "pass: $($csb["pwd"])"
Write-Host "Trusted_Connection: $($csb["Trusted_Connection"])"
Write-host
Write-host Username and password
Write-host
$csb = New-DbConnectionStringBuilder -username frode -password pass
Write-Host "UID: $($csb["Uid"])"
write-host "pass: $($csb["pwd"])"
Write-Host "Trusted_Connection: $($csb["Trusted_Connection"])"
Write-host
Write-host Nothing
Write-host
$csb = New-DbConnectionStringBuilder
Write-Host "UID: $($csb["Uid"])"
write-host "pass: $($csb["pwd"])"
Write-Host "Trusted_Connection: $($csb["Trusted_Connection"])"
输出:
Null creds
UID:
pass:
Trusted_Connection: yes
Creds
UID: frode
pass: lol
Trusted_Connection:
Username and password
UID: frode
pass: pass
Trusted_Connection:
Nothing
UID:
pass:
Trusted_Connection:
编辑:实际上,您可以使用[object]
参数接受空值凭据并验证它是脚本中的PSCredential
- 对象,但是您将写New-DbConnectionStringBuilder -Credential "frode"
时,会失去提示输入密码的好处。
我更喜欢上面的解决方案并验证调用者脚本中的输入(修复空值)。这样,该功能仍然是“最佳实践”,用户(您)将负责清理/验证输入,就像您应该的那样。
function New-DbConnectionStringBuilder {
[cmdletbinding(DefaultParameterSetName="NoCredential")] param(
[System.Data.Common.DbConnectionStringBuilder] $existingCSB,
[Hashtable] $property,
[Parameter(ParameterSetName="Credential")]
[object] $credential,
[Parameter(Mandatory=$true, ParameterSetName="UserPass")]
[string] $username,
[Parameter(Mandatory=$true, ParameterSetName="UserPass")]
$password
)
#Validate credential-type
if($credential -ne $null -and $credential -isnot [System.Management.Automation.PSCredential]) { Write-Error -Message "credential parameter is not null or PSCredential" -Category InvalidArgument -ErrorAction Stop }
$newDbCSB = New-Object System.Data.Common.DbConnectionStringBuilder $true
if ($existingCSB.Keys.Count -gt 0) {
$existingCSB.Keys |% { $newDbCSB[$_] = [String]::Copy($existingCSB[$_]) }
}
if ($property.Keys.Count -gt 0) {
$property.Keys |% { $newDbCSB[$_] = [String]::Copy($property[$_]) }
}
Write-Host ($credential -eq [System.Management.Automation.PSCredential]::Empty)
if($PsCmdlet.ParameterSetName -ne "NoCredential") {
if ($credential -ne $null -and $credential -ne [System.Management.Automation.PSCredential]::Empty) {
$username = $credential.UserName.Split("\")[-1]
$password = $credential.GetNetworkCredential().Password
}
if ($username -and $password) {
$newDbCSB["Uid"] = $username
$newDbCSB["Pwd"] = $password
$newDbCSB.Remove("Trusted_Connection") | Out-Null
}
else {
$newDbCSB["Uid"] = $null
$newDbCSB["Pwd"] = $null
$newDbCSB["Trusted_Connection"] = "yes"
}
}
$newDbCSB
}
$creds = $null
$csb = New-DbConnectionStringBuilder -credential $creds
Write-Host "UID: $($csb["Uid"])"
write-host "pass: $($csb["pwd"])"
Write-Host "Trusted_Connection: $($csb["Trusted_Connection"])"
答案 1 :(得分:0)
通过简单地省略参数中的类型注释,我能够达到我想要的程度。当我这样做时,Powershell不会启动PSCredential弹出窗口,我可以处理我的函数内的所有内容。
也许不是最优雅的解决方案,但确实有效。
这是我的代码:
<#
.description
Create a new Connection String Builder object
.parameter existingCSB
Use the passed CSB as the base, but allow it to be overridden.
.parameter property
Hashtable containing named properties for a connection string builder. Will override values on -existingCSB.
.parameter credential
Use these credentials. Will override values on -existingCSB and any values passed as -property.
NOTE: If this parameter is null, or if EITHER the username OR password in the credential is an empty string, use a trusted connection / integrated security instead
.parameter username
Use this username. Will override values on -existingCSB and any values passed as -property
NOTE: If EITHER the username OR password is null or an empty string, use a trusted connection / integrated security instead
.parameter password
Use this password. Can be a string or a SecureString object. Will override values on -existingCSB and any values passed as -property
NOTE: If EITHER the username OR password is null or an empty string, use a trusted connection / integrated security instead
#>
function New-DbConnectionStringBuilder {
[cmdletbinding(DefaultParameterSetName="NoCredential")] param(
[System.Data.Common.DbConnectionStringBuilder] $existingCSB,
[Hashtable] $property,
# Do not give a type, so that this may be $null or a PSCredential object
# NOTE that there is no such thing as a null PSCredential object - the closest thing is [PSCredential]::Empty
[Parameter(Mandatory=$true, ParameterSetName="Credential")]
# [System.Management.Automation.PSCredential]
[AllowNull()] $credential,
[Parameter(Mandatory=$true, ParameterSetName="UserPass")]
[AllowEmptyString()] [string] $username,
# Do not give a type, so that this might be a string or a SecureString
[Parameter(Mandatory=$true, ParameterSetName="UserPass")]
[AllowNull()] $password
)
$newDbCSB = New-Object System.Data.Common.DbConnectionStringBuilder $true
if ($existingCSB.Keys.Count -gt 0) {
$existingCSB.Keys |% { $newDbCSB[$_] = [String]::Copy($existingCSB[$_]) }
}
if ($property.Keys.Count -gt 0) {
$property.Keys |% { $newDbCSB[$_] = [String]::Copy($property[$_]) }
}
if ($PsCmdlet.ParameterSetName -eq "Credential") {
if ($credential) {
# Note that we assume this is a PSCredential object, but it could be anything with a string UserName property and a string or SecureString Password property
$tmpUser = $credential.UserName
$tmpPass = $credential.Password
}
else {
$tmpUser = $tmpPass = $null
}
}
elseif ($PsCmdlet.ParameterSetName -eq "UserPass") {
$tmpUser = $username
$tmpPass = $password
}
if ($PsCmdlet.ParameterSetName -notmatch "NoCredential") {
if ($tmpPass -and $tmpPass.GetType().FullName -eq "System.Security.SecureString") {
$tmpPass = Decrypt-SecureString $tmpPass
}
if ($tmpUser -and $tmpPass) {
$newDbCSB["Uid"] = $tmpUser
$newDbCSB["Pwd"] = $tmpPass
$newDbCSB.Remove("Trusted_Connection") | Out-Null
}
else {
$newDbCSB["Uid"] = $null
$newDbCSB["Pwd"] = $null
$newDbCSB["Trusted_Connection"] = "yes"
}
}
return $newDbCSB
}