保存凭据以供 powershell 重用和错误 ConvertTo-SecureString : Key not valid for use in specified state
Posted
技术标签:
【中文标题】保存凭据以供 powershell 重用和错误 ConvertTo-SecureString : Key not valid for use in specified state【英文标题】:Saving credentials for reuse by powershell and error ConvertTo-SecureString : Key not valid for use in specified state 【发布时间】:2011-08-18 15:24:56 【问题描述】:我正在执行本文中描述的操作,将凭据保存在安全文件中,以便我们的自动化进程可以使用它通过 Invoke-command 运行远程 PS 脚本: http://blogs.technet.com/b/robcost/archive/2008/05/01/powershell-tip-storing-and-using-password-credentials.aspx
当我在我的帐户下运行它时效果很好 - 从加密文件中读取密码,传递给 Invoke-command,一切都很好。
今天,当我的脚本准备好进入黄金时段时,我尝试在将由自动化进程使用的 Windows 帐户下运行它,并在我的脚本尝试从文件中读取安全密码时出现以下错误:
ConvertTo-SecureString : Key not valid for use in specified state.
At \\remoted\script.ps1:210 char:87
+ $password = get-content $PathToFolderWithCredentials\pass.txt | convertto-sec
urestring <<<<
+ CategoryInfo : InvalidArgument: (:) [ConvertTo-SecureString], C
ryptographicException
+ FullyQualifiedErrorId : ImportSecureString_InvalidArgument_Cryptographic
Error,Microsoft.PowerShell.Commands.ConvertToSecureStringCommand
让我的同事在他的帐户下运行,他得到了同样的错误。
这是我用来保存凭据的代码:
$PathToFolderWithCredentials = "\\path\removed"
write-host "Enter login as domain\login:"
read-host | out-file $PathToFolderWithCredentials\login.txt
write-host "Enter password:"
read-host -assecurestring | convertfrom-securestring | out-file $PathToFolderWithCredentials\pass.txt
write-host "*** Credentials have been saved to $pathtofolder ***"
这是脚本中的代码,由自动化进程运行以读取它们以在 Invoke-command 中使用:
$login= get-content $PathToFolderWithCredentials\login.txt
$password = get-content $PathToFolderWithCredentials\pass.txt | convertto-securestring
$credentials = new-object -typename System.Management.Automation.PSCredential -argumentlist $login,$password
错误发生在 $password = get-content $PathToFolderWithCredentials\pass.txt |转换为安全字符串
有什么想法吗?
【问题讨论】:
我读到:“ConvertFrom-SecureString cmdlet 使用 Windows 标准数据保护 API 加密此数据。这确保只有您的用户帐户才能正确解密其内容”。这就是为什么它不起作用...任何想法是保存密码的最佳方法,然后可以由另一个 Windows 帐户解密? 发现这篇博文也很有帮助powertoe.wordpress.com/2011/06/05/… 我还建议您阅读“Powershell Cookbook” - 适合初学者和高级用户的 goob 书。它涵盖了这一点以及许多其他内容。 【参考方案1】:您必须在同一台计算机上创建密码字符串,并使用您将用于运行它的相同登录名。
【讨论】:
"...并且使用相同的登录名。"这对我来说很重要。 "...并且使用相同的登录名。" 【参考方案2】:ConvertFrom-SecureString
采用Key
(和SecureKey
)参数。您可以指定密钥来保存加密的标准字符串,然后在ConvertTo-SecureString
中再次使用该密钥来取回安全字符串,而与用户帐户无关。
http://technet.microsoft.com/en-us/library/dd315356.aspx
在一个项目中,我实现了非对称加密,人们使用公钥加密密码,自动化过程使用私钥解密密码:Handling passwords in production config for automated deployment
【讨论】:
谢谢,它有效!你又救了我! :) 只是一个问题(可能是愚蠢的),但如果我在脚本中输入一个密钥,这与在那里输入密码不一样吗? 我没有过多地使用密钥方法,但一般的想法是你将它放在运行脚本的机器上的特定位置(密钥库),脚本从那里读取并解密。在非对称版本中,公钥是已知的,因此人们可以加密密码,但只有拥有私钥的人才能解密。私钥在运行脚本的机器上。脚本只知道在哪里寻找它。希望这是有道理的。【参考方案3】:下面将允许将凭据保存为文件,然后由另一个用户远程运行的另一个脚本使用这些凭据。
代码取自 David Lee 的一篇很棒的文章,我自己只是做了一些小的调整https://blog.kloud.com.au/2016/04/21/using-saved-credentials-securely-in-powershell-scripts/
第一步是使用 AES 将安全密码保存到文件中。以下将作为独立脚本运行:
# Prompt you to enter the username and password
$credObject = Get-Credential
# The credObject now holds the password in a ‘securestring’ format
$passwordSecureString = $credObject.password
# Define a location to store the AESKey
$AESKeyFilePath = “aeskey.txt”
# Define a location to store the file that hosts the encrypted password
$credentialFilePath = “credpassword.txt”
# Generate a random AES Encryption Key.
$AESKey = New-Object Byte[] 32
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($AESKey)
# Store the AESKey into a file. This file should be protected! (e.g. ACL on the file to allow only select people to read)
Set-Content $AESKeyFilePath $AESKey # Any existing AES Key file will be overwritten
$password = $passwordSecureString | ConvertFrom-SecureString -Key $AESKey
Add-Content $credentialFilePath $password
然后在您需要使用凭据的脚本中使用以下内容:
#set up path and user variables
$AESKeyFilePath = “aeskey.txt” # location of the AESKey
$SecurePwdFilePath = “credpassword.txt” # location of the file that hosts the encrypted password
$userUPN = "domain\userName" # User account login
#use key and password to create local secure password
$AESKey = Get-Content -Path $AESKeyFilePath
$pwdTxt = Get-Content -Path $SecurePwdFilePath
$securePass = $pwdTxt | ConvertTo-SecureString -Key $AESKey
#crete a new psCredential object with required username and password
$adminCreds = New-Object System.Management.Automation.PSCredential($userUPN, $securePass)
#use the $adminCreds for some task
some-Task-that-needs-credentials -Credential $adminCreds
请注意,如果用户可以访问密码文件和密钥文件,他们可以为用户解密密码。
【讨论】:
对于那些使用New-Object System.Net.NetworkCredential($userUPN, $securePass)
的人,只需将其替换为New-Object System.Management.Automation.PSCredential($userUPN, $securePass)
,假设您创建文件并遵循脚本逻辑的步骤,它应该可以正常工作。似乎对我来说工作得很好,正是我正在寻找的东西,而不是需要在不使用此方法运行的每台机器或配置文件上使用 Get-Credential
定义凭据。谢谢克里斯!!【参考方案4】:
另一种方法是使用范围“LocalMachine”而不是“CurrentUser”来保护数据,后者是 ConvertFrom-SecureString 使用的范围。
public static string Protect(SecureString input, DataProtectionScope dataProtectionScope = DataProtectionScope.CurrentUser, byte[] optionalEntropy = null)
byte[] data = SecureStringToByteArray(input);
byte[] data2 = ProtectedData.Protect(data, optionalEntropy, dataProtectionScope);
for (int i = 0; i < data.Length; i++)
data[i] = 0;
return ByteArrayToString(data2);
private static byte[] SecureStringToByteArray(SecureString s)
var array = new byte[s.Length * 2];
if (s.Length > 0)
IntPtr intPtr = Marshal.SecureStringToGlobalAllocUnicode(s);
try
Marshal.Copy(intPtr, array, 0, array.Length);
finally
Marshal.FreeHGlobal(intPtr);
return array;
private static string ByteArrayToString(byte[] data)
var stringBuilder = new StringBuilder();
for (int i = 0; i < data.Length; i++)
stringBuilder.Append(data[i].ToString("x2", CultureInfo.InvariantCulture));
return stringBuilder.ToString();
加密的字符串可以被使用范围'CurrentUser'的ConvertTo-SecureString使用。
【讨论】:
由于原始问题使用PowerShell
,您能否将此答案从C#
也转换为PowerShell
?【参考方案5】:
假设您有一个已知的 N 个用户列表,这些用户将使用这些凭据(例如,一个开发人员 userMe
和一个系统/服务用户 userSys
),您可以(让这些用户)制作 N 个 @987654323 副本@ 文件:每个用户一个。
所以userX
的密码将导致例如2 个*.pass.txt
文件:
userX.userMe.pass.txt
userX.userSys.pass.txt
当 userMe 想要他/她阅读 userX.userMe.pass.txt
等的信用时。
【讨论】:
以上是关于保存凭据以供 powershell 重用和错误 ConvertTo-SecureString : Key not valid for use in specified state的主要内容,如果未能解决你的问题,请参考以下文章
iOS,Swift:如何保存包含自定义对象的数组以便我可以加载以供重用?
在 C# 中使用不同的凭据调用远程 powershell 脚本