From 03f10f052d3881252b33e67b25acfaba5acc51c5 Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Wed, 11 Dec 2019 15:40:41 -0800 Subject: [PATCH] Add `-AsPlainText` to `ConvertFrom-SecureString` (#11142) --- .../security/SecureStringCommands.cs | 37 +++++++++++-------- .../SecureString.Tests.ps1 | 5 ++- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/Microsoft.PowerShell.Security/security/SecureStringCommands.cs b/src/Microsoft.PowerShell.Security/security/SecureStringCommands.cs index 45f577e0a3..85ecca4d02 100644 --- a/src/Microsoft.PowerShell.Security/security/SecureStringCommands.cs +++ b/src/Microsoft.PowerShell.Security/security/SecureStringCommands.cs @@ -139,6 +139,12 @@ namespace Microsoft.PowerShell.Commands } } + /// + /// Gets or sets a switch to get the secure string as plain text. + /// + [Parameter(ParameterSetName = "AsPlainText")] + public SwitchParameter AsPlainText { get; set; } + /// /// Processes records from the input pipeline. /// For each input object, the command encrypts @@ -165,6 +171,19 @@ namespace Microsoft.PowerShell.Commands { encryptionResult = SecureStringHelper.Encrypt(SecureString, Key); } + else if (AsPlainText) + { + IntPtr valuePtr = IntPtr.Zero; + try + { + valuePtr = Marshal.SecureStringToGlobalAllocUnicode(SecureString); + exportedString = Marshal.PtrToStringUni(valuePtr); + } + finally + { + Marshal.ZeroFreeGlobalAllocUnicode(valuePtr); + } + } else { exportedString = SecureStringHelper.Protect(SecureString); @@ -342,22 +361,8 @@ namespace Microsoft.PowerShell.Commands } else { - if (!Force) - { - string error = - SecureStringCommands.ForceRequired; - Exception e = new ArgumentException(error); - WriteError(new ErrorRecord(e, "ImportSecureString_ForceRequired", ErrorCategory.InvalidArgument, null)); - } - else - { - // The entire purpose of the SecureString is to prevent a secret from being - // permanently stored in memory as a .Net string. If they use the - // -AsPlainText and -Force flags, they consciously have made the decision to be OK - // with that. - importedString = new SecureString(); - foreach (char currentChar in String) { importedString.AppendChar(currentChar); } - } + importedString = new SecureString(); + foreach (char currentChar in String) { importedString.AppendChar(currentChar); } } } catch (ArgumentException e) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/SecureString.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/SecureString.Tests.ps1 index 88906ad364..838719ad1a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/SecureString.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/SecureString.Tests.ps1 @@ -22,10 +22,11 @@ Describe "SecureString conversion tests" -Tags "CI" { $ss = ConvertTo-SecureString -AsPlainText -Force abcd $ss | Should -BeOfType SecureString } + It "can convert back from a secure string" { $secret = "abcd" $ss1 = ConvertTo-SecureString -AsPlainText -Force $secret - $ss2 = convertfrom-securestring $ss1 | convertto-securestring - [pscredential]::New("user",$ss2).GetNetworkCredential().Password | Should -Be $secret + $ss2 = ConvertFrom-SecureString $ss1 | ConvertTo-SecureString + $ss2 | ConvertFrom-SecureString -AsPlainText | Should -Be $secret } }