Have you been given a task to automate some jobs that require some kind of credential authentication? I certainly have a lot of those in the past till today where the script requires a username and password value to proceed with the job. And it gets complicated when it requires a script calling another script that may not be developed by yourself.
Storing sensitive information as variable
How do you store sensitive information as variable in PowerShell? This is a very common task in scripting where you may requires to store that password value as a variable for repurposing it. But storing password value as a variable means that the variable value is in clear text which is not ideal.
That is why there is a ConvertTo-SecureString
cmdlet available that assist you in securing plain text String
to become a SecureString
type prior to storing it as a variable in memory.
Converting plain text String to SecureString type
Let us try to use ConvertTo-SecureString
cmdlet to convert a plain text String
value of “MyTopSecretPassword” as a SecureString
and store it as a variable in a script scope. We will also attempt to get the stored variable to output on to the console.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 $SCRIPT:INSECUREPASSWORD = 'MyTopSecretPassword' Write-Information ` -MessageData "What is my insecure Password? $SCRIPT:INSECUREPASSWORD" ` -InformationAction 'Continue' $SCRIPT:SECUREPASSWORD = ConvertTo-SecureString ` -String 'MyTopSecretPassword' ` -AsPlainText ` -Force Write-Information ` -MessageData "What is my secure Password? $SCRIPT:SECUREPASSWORD" ` -InformationAction 'Continue'
If you have copied the code above and run them on your PowerShell console, you will find that $SCRIPT:INSECUREPASSWORD
variable will return plain text value of your password and $SCRIPT:SECUREPASSWORD
variable will only returns the type name of the variable on the console. Looks pretty secure to me.
Output:
1 2 What is my insecure Password? MyTopSecretPassword What is my secure Password? System.Security.SecureString
Converting SecureString to String type
Now that we know $SCRIPT:SECUREPASSWORD
is a SecureString
type, can I convert it back to a String
type? Yes, you can convert a SecureString
type using ConvertFrom-SecureString
cmdlet as below:
1 $SCRIPT:SECUREPASSWORD | ConvertFrom-SecureString
Unfortunately, the output is basically not your plain text password String
, instead it returns an encrypted String
and therefore is basically not usable in some cases where you may want the SecureString
to returns back the original plain text password String
value for configuring a non-Microsoft products.
Note: The output below will not be identical with your output due to encryption.
Output:
1 2 3 4 5 01000000d08c9ddf0115d1118c7a00c04fc297eb01000000594d2a0d29aca7458ab4d8da81a486b e0000000002000000000003660000c0000000100000006e036855074752e50aedd3fd08707aa200 00000004800000a000000010000000753569fec88f896d534f933af15f4659280000006211ae529 05857e099cccb8f81f50bf7159e1db255e6926ed481ce850273ae84526fc20002f534d914000000 45209f670a1af769dd5e23b50be6450d6ea93252
Converting encrypted String to plain text String
Since an encrypted String
is not something that we can use, we will need to use the encrypted String
value that we got and unencrypt them back to plain text String
value.
If you are using PowerShell that still utilises old .Net Framework libraries, you will have to use Marshal
class fromSystem.Runtime.InteropServices
namespace with PtrToStringAuto
and SecureStringToBSTR
methods to convert the encrypted String
as below.
1 2 3 4 5 6 # .NET FRAMEWORK 2.0 [System.Runtime.InteropServices.Marshal]::PtrToStringAuto( ` [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR( ` (ConvertTo-SecureString ` -String $($SCRIPT:SECUREPASSWORD | ConvertFrom-SecureString) ` -Force)))
If you are using PowerShell that utilises newer .Net Framework libraries, you will have to use Marshal
class fromSystem.Runtime.InteropServices
namespace with PtrToStringAnsi
method, and SecureStringMarshal
class from System.Security
namespace with SecureStringToCoTaskMemAnsi
methods to convert the encrypted String
as below.
1 2 3 4 5 6 # .NET FRAMEWORK 4.7.1 [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi( ` [System.Security.SecureStringMarshal]::SecureStringToCoTaskMemAnsi( ` (ConvertTo-SecureString ` -String $($SCRIPT:SECUREPASSWORD | ConvertFrom-SecureString) ` -Force)))
1 2 3 4 5 6 # .NET FRAMEWORK 4.7.1 [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi( ` [System.Security.SecureStringMarshal]::SecureStringToCoTaskMemAnsi( ` (ConvertTo-SecureString ` -String $($SCRIPT:SECUREPASSWORD | ConvertFrom-SecureString) ` -Force)))
Note: The above methods do not work on PowerShell Core 6.0 of higher for non-Windows platforms such as Linux and macOS due to issue #1654 withConvertFrom-SecureString
cmdlet on those platforms since 5 Aug 2016. As such, we may have to wait until that issue #1654 is resolved or a workaround is available for those platforms. In short, we are still brain storming about it.
And you will obtain your original plain text password value outputs on the console as below.
Output:
1 MyTopSecretPassword
Conclusion
To summarize this, it is possible to secure a plain text String
into a SecureString
that is encrypted and it is also possible to reverse the encrypted SecureString
back to the original plain text String
value in PowerShell. Does that mean it is insecure to store any sensitive values as SecureString
? No, it is still very secure to some extent because someone will need to be able to hack into the machine in advance to run a malicious process with access to raw memory to reverse the encrypted SecureString
. Secondly, it is impossible to copy the SecureString
(long) encrypted String
value and reverse it from another machine due to a mismatch cryptography cipher key. For more information, please kindly refer to How secure is SecureString?
Why is there two different ways of converting encrypted String
back to plain text String
? That is because PowerShell on older operating system is using legacy .Net Framework. Since then Microsoft has been improving their .Net Framework and there are a few namespaces and classes rearrangement. Therefore, if you are not aware of how to do this with newer .Net Framework previously, I hope you know how to do it now and enjoyed reading this. If you reckon this is good information, help share this with others and keep them informed.
References
- Microsoft MSDN: System.Runtime.InteropServices.Marshal.PtrToStringAuto()
- Microsoft MSDN: System.Runtime.InteropServices.Marshal.SecureStringToBSTR()
- Microsoft MSDN: System.Runtime.InteropServices.Marshal.PtrToStringAnsi()
- Microsoft MSDN: System.Security.SecureStringMarshal.SecureStringToCoTaskMemAnsi()
About the Author
I am a technology evangelist [Microsoft MVP] who preaches infrastructure architecture, infrastructure automation, IT digital transformation and research on emerging technologies.
During the day, I tend to be managing IT operations, transforming operations framework, providing service delivery satisfaction, driving project delivery on time and budget for a living.
I am also known as a keyboard wizard that chants PowerShell, C#, Javascript and other language spells when casting digital magic without waving a mouse.
Reference
Tang, K. (2018). Working with secret in PowerShell. Available at:
https://kiazhi.github.io/blog/powershell/Working-with-secret-in-PowerShell/ [Accessed: June 16th 2019].