保存凭据以供 powershell 重用并出现错误 ConvertTo-SecureString:密钥在指定状态下使用无效

发布于 2024-11-30 12:40:51 字数 1830 浏览 0 评论 0原文

我正在做类似这篇文章中描述的事情,将凭据保存在安全文件中,以便我们的自动化进程可以使用它通过 Invoke 命令运行远程 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 |转换为安全字符串

有什么想法吗?

I was doing something like described in this post to save credentials in a secured file so our automated process can use that to run remote PS scripts via Invoke-command:
http://blogs.technet.com/b/robcost/archive/2008/05/01/powershell-tip-storing-and-using-password-credentials.aspx

This works great when I run this under my account - password is read from encrypted file, passed to Invoke-command and everything is fine.

Today, when my script was ready for its prime time, I tried to run it under windows account that will be used by automated process and got this error below while my script was trying to read secured password from a file:

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

Asked my workmate to run under his account and he got the same error.

This is the code I am using to save credentials:

$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 ***"

This is the code in the script to run by automated process to read them to use in 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

Error happens on line $password = get-content $PathToFolderWithCredentials\pass.txt | convertto-securestring

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

晨曦慕雪 2024-12-07 12:40:51

您必须在同一台计算机上创建密码字符串,并使用与运行它相同的登录名。

You have to create the password string on the same computer and with the same login that you will use to run it.

请恋爱 2024-12-07 12:40:51

ConvertFrom-SecureString 采用 Key(和 SecureKey)参数。您可以指定密钥来保存加密的标准字符串,然后在 ConvertTo-SecureString 中再次使用该密钥来取回安全字符串,无论用户帐户如何。

http://technet.microsoft.com/en-us/library/dd315356.aspx

在一个项目中,我实现了非对称加密,人们使用公钥对密码进行加密,而自动化过程则使用私钥来解密密码:处理生产配置中的密码以进行自动化部署

ConvertFrom-SecureString takes a Key ( and SecureKey) parameter. You can specify the key to save the encrypted standard string and then use the key again in ConvertTo-SecureString to get back the secure string, irrespective of the user account.

http://technet.microsoft.com/en-us/library/dd315356.aspx

In a project, I have implemented asymmetric encryption, whereby people encrypt the password using the public key and the automation process has the private key to decrypt passwords: Handling passwords in production config for automated deployment

奢华的一滴泪 2024-12-07 12:40:51

下面的代码将允许将凭据保存为文件,然后这些凭据将由不同用户远程运行的另一个脚本使用。

该代码取自 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

请注意,如果用户可以访问密码文件和密钥文件,他们就可以解密密码用户。

The below will allow credentials to be saved as a file, then those credentials to be used by another script being run by a different user, remotely.

The code was taken from a great article produced by David Lee, with only some minor adjustments from myself https://blog.kloud.com.au/2016/04/21/using-saved-credentials-securely-in-powershell-scripts/

First step is to save a a secure password to a file using AES. The below will run as a stand alone script:

            # 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

Then in your script where you need to use credentials use the following:

            #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

Please be aware that if the user can get access to the password file and the key file, they can decrypt the password for the user.

盛装女皇 2024-12-07 12:40:51

另一种方法是使用范围“LocalMachine”而不是 ConvertFrom-SecureString 使用的“CurrentUser”来保护数据。

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 使用。

Another approach would be to protect the data using scope 'LocalMachine' instead of 'CurrentUser' which is the one used by 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();
}

The encrypted string can be used by ConvertTo-SecureString which is using scope 'CurrentUser'.

清风疏影 2024-12-07 12:40:51

假设您有一个已知的将使用凭据的 N 个用户列表(例如,一个开发人员 userMe 和一个系统/服务用户 userSys),您可以(让这些用户)制作 N 个 pass.txt 文件副本:每个用户一份。

因此,userX 的密码将生成 2 个 *.pass.txt 文件:

  • userX.userMe.pass.txt
  • userX。 userSys.pass.txt

当 userMe 想要信用时,他/她会读取 userX.userMe.pass.txt 等。

Assuming you have a known list of N users who will use the credentials (e.g. one developer userMe and a system/service user userSys) you can just (get those users to) make N copies of the pass.txt file: one for each user.

So the password of userX will result in e.g. 2 *.pass.txt files:

  • userX.userMe.pass.txt
  • userX.userSys.pass.txt

When userMe wants the creds he/she reads userX.userMe.pass.txt etc.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文