Skip to content

Commit 99b3bfa

Browse files
authored
Change Read-Host -MaskInput to use existing SecureString path, but return as plain text (#13256)
1 parent 2eade89 commit 99b3bfa

File tree

8 files changed

+31
-135
lines changed

8 files changed

+31
-135
lines changed

src/Microsoft.PowerShell.Commands.Utility/commands/utility/ReadConsoleCmdlet.cs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,9 @@ protected override void BeginProcessing()
130130
}
131131

132132
FieldDescription fd = new FieldDescription(promptString);
133-
if (AsSecureString)
133+
if (AsSecureString || MaskInput)
134134
{
135-
fd.SetParameterType(typeof(System.Security.SecureString));
135+
fd.SetParameterType(typeof(SecureString));
136136
}
137137
else
138138
{
@@ -149,27 +149,37 @@ protected override void BeginProcessing()
149149
{
150150
foreach (PSObject o in result.Values)
151151
{
152-
WriteObject(o);
152+
if (MaskInput && o?.BaseObject is SecureString secureString)
153+
{
154+
WriteObject(Utils.GetStringFromSecureString(secureString));
155+
}
156+
else
157+
{
158+
WriteObject(o);
159+
}
153160
}
154161
}
155162
}
156163
else
157164
{
158165
object result;
159-
if (AsSecureString)
166+
if (AsSecureString || MaskInput)
160167
{
161168
result = Host.UI.ReadLineAsSecureString();
162169
}
163-
else if (MaskInput)
164-
{
165-
result = Host.UI.ReadLineMaskedAsString();
166-
}
167170
else
168171
{
169172
result = Host.UI.ReadLine();
170173
}
171174

172-
WriteObject(result);
175+
if (MaskInput)
176+
{
177+
WriteObject(Utils.GetStringFromSecureString((SecureString)result));
178+
}
179+
else
180+
{
181+
WriteObject(result);
182+
}
173183
}
174184
}
175185

src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -112,17 +112,6 @@ public override string ReadLine()
112112
throw new PSNotImplementedException();
113113
}
114114

115-
/// <summary>
116-
/// Null implementation of ReadLineMaskedAsString.
117-
/// </summary>
118-
/// <returns>
119-
/// It throws an exception.
120-
/// </returns>
121-
public override string ReadLineMaskedAsString()
122-
{
123-
throw new PSNotImplementedException();
124-
}
125-
126115
/// <summary>
127116
/// ReadLineAsSecureString.
128117
/// </summary>

src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -179,39 +179,6 @@ public override string ReadLine()
179179
return ReadLine(false, string.Empty, out unused, true, true);
180180
}
181181

182-
/// <summary>
183-
/// See base class.
184-
/// </summary>
185-
/// <returns>
186-
/// The characters typed by the user.
187-
/// </returns>
188-
/// <exception cref="HostException">
189-
/// If obtaining a handle to the active screen buffer failed
190-
/// OR
191-
/// Win32's setting input buffer mode to disregard window and mouse input failed.
192-
/// OR
193-
/// Win32's ReadConsole failed.
194-
/// </exception>
195-
/// <exception cref="PipelineStoppedException">
196-
/// If Ctrl-C is entered by user.
197-
/// </exception>
198-
public override string ReadLineMaskedAsString()
199-
{
200-
HandleThrowOnReadAndPrompt();
201-
202-
// we lock here so that multiple threads won't interleave the various reads and writes here.
203-
object result = null;
204-
lock (_instanceLock)
205-
{
206-
result = ReadLineSafe(false, PrintToken);
207-
}
208-
209-
StringBuilder resultSb = result as StringBuilder;
210-
Dbg.Assert(resultSb != null, "ReadLineMaskedAsString did not return a stringBuilder");
211-
212-
return resultSb.ToString();
213-
}
214-
215182
/// <summary>
216183
/// See base class.
217184
/// </summary>

src/System.Management.Automation/engine/hostifaces/InternalHostUserInterface.cs

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -120,47 +120,6 @@ public override
120120
return result;
121121
}
122122

123-
/// <summary>
124-
/// See base class.
125-
/// </summary>
126-
/// <returns>
127-
/// The characters typed by the user.
128-
/// </returns>
129-
/// <exception cref="HostException">
130-
/// If the UI property of the external host is null, possibly because the PSHostUserInterface is not
131-
/// implemented by the external host.
132-
/// </exception>
133-
public override
134-
string
135-
ReadLineMaskedAsString()
136-
{
137-
if (_externalUI == null)
138-
{
139-
ThrowNotInteractive();
140-
}
141-
142-
string result = null;
143-
144-
try
145-
{
146-
result = _externalUI.ReadLineMaskedAsString();
147-
}
148-
catch (PipelineStoppedException)
149-
{
150-
// PipelineStoppedException is thrown by host when it wants
151-
// to stop the pipeline.
152-
LocalPipeline lpl = (LocalPipeline)((RunspaceBase)_parent.Context.CurrentRunspace).GetCurrentlyRunningPipeline();
153-
if (lpl == null)
154-
{
155-
throw;
156-
}
157-
158-
lpl.Stopper.Stop();
159-
}
160-
161-
return result;
162-
}
163-
164123
/// <summary>
165124
/// See base class.
166125
/// </summary>

src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -61,29 +61,6 @@ public abstract System.Management.Automation.Host.PSHostRawUserInterface RawUI
6161
/// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.Prompt"/>
6262
public abstract string ReadLine();
6363

64-
/// <summary>
65-
/// Same as ReadLine except that the input is not echoed to the user while it is collected
66-
/// or is echoed in some obfuscated way, such as showing a dot for each character.
67-
/// </summary>
68-
/// <returns>
69-
/// The characters typed by the user.
70-
/// </returns>
71-
/// <remarks>
72-
/// Note that credentials (a user name and password) should be gathered with
73-
/// <see cref="System.Management.Automation.Host.PSHostUserInterface.PromptForCredential(string, string, string, string)"/>
74-
/// <see cref="System.Management.Automation.Host.PSHostUserInterface.PromptForCredential(string, string, string, string, System.Management.Automation.PSCredentialTypes, System.Management.Automation.PSCredentialUIOptions)"/>
75-
/// </remarks>
76-
/// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.ReadLine"/>
77-
/// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.PromptForCredential(string, string, string, string)"/>
78-
/// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.PromptForCredential(string, string, string, string, System.Management.Automation.PSCredentialTypes, System.Management.Automation.PSCredentialUIOptions)"/>
79-
/// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.PromptForChoice"/>
80-
/// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.Prompt"/>
81-
public virtual string ReadLineMaskedAsString()
82-
{
83-
// Default implementation of the function to maintain backwards compatibility of the base class.
84-
throw new PSNotImplementedException();
85-
}
86-
8764
/// <summary>
8865
/// Same as ReadLine, except that the result is a SecureString, and that the input is not echoed to the user while it is
8966
/// collected (or is echoed in some obfuscated way, such as showing a dot for each character).

src/System.Management.Automation/engine/remoting/server/ServerRemoteHostUserInterface.cs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -197,17 +197,6 @@ public override void WriteWarningLine(string message)
197197
_serverMethodExecutor.ExecuteVoidMethod(RemoteHostMethodId.WriteWarningLine, new object[] { message });
198198
}
199199

200-
/// <summary>
201-
/// Read line as string masked.
202-
/// </summary>
203-
/// <returns>
204-
/// Not implemented. It throws an exception.
205-
/// </returns>
206-
public override string ReadLineMaskedAsString()
207-
{
208-
throw new PSNotImplementedException();
209-
}
210-
211200
/// <summary>
212201
/// Read line as secure string.
213202
/// </summary>

test/powershell/Modules/Microsoft.PowerShell.Utility/Read-Host.Tests.ps1

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Describe "Read-Host Test" -Tag "CI" {
1212

1313
AfterEach {
1414
$ps.Commands.Clear()
15+
$th.UI.Streams.Clear()
1516
}
1617

1718
AfterAll {
@@ -30,17 +31,26 @@ Describe "Read-Host Test" -Tag "CI" {
3031
$prompt = $th.ui.streams.prompt[0]
3132
$prompt | Should -Not -BeNullOrEmpty
3233
$prompt.split(":")[-1] | Should -Be myprompt
34+
$result | Should -BeExactly 'this is a prompt response'
3335
}
3436

3537
It "Read-Host returns a secure string when using -AsSecureString parameter" {
3638
$result = $ps.AddScript("Read-Host -AsSecureString").Invoke() | Select-Object -First 1
3739
$result | Should -BeOfType SecureString
38-
[pscredential]::New("foo",$result).GetNetworkCredential().Password | Should -BeExactly TEST
40+
$result | ConvertFrom-SecureString -AsPlainText | Should -BeExactly 'TEST'
3941
}
4042

4143
It "Read-Host returns a string when using -MaskInput parameter" {
4244
$result = $ps.AddScript("Read-Host -MaskInput").Invoke()
43-
$result | Should -Be $th.UI.ReadLineData
45+
$result | Should -BeExactly 'TEST'
46+
}
47+
48+
It "Read-Host returns a string when using -MaskInput parameter used with -Prompt" {
49+
$result = $ps.AddScript("Read-Host -MaskInput -Prompt Test").Invoke()
50+
$prompt = $th.ui.streams.prompt[0]
51+
$prompt | Should -Not -BeNullOrEmpty
52+
$prompt.split(":")[-1] | Should -BeExactly 'Test'
53+
$result | Should -BeExactly 'this is a prompt response'
4454
}
4555

4656
It "Read-Host throws an error when both -AsSecureString parameter and -MaskInput parameter are used" {

test/tools/Modules/HelpersHostCS/HelpersHostCS.psm1

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,11 +183,6 @@ namespace TestHost
183183
return ReadLineData;
184184
}
185185
186-
public override string ReadLineMaskedAsString()
187-
{
188-
return ReadLineData;
189-
}
190-
191186
public override SecureString ReadLineAsSecureString()
192187
{
193188
SecureString ss = new SecureString();

0 commit comments

Comments
 (0)