Harden PromptForChoiceMultipleSelection host call - #28129
Jordan Borean (jborean93) wants to merge 1 commit into
Conversation
Fixes `IHostUISupportsMultipleChoiceSelection.PromptForChoice` over PowerShell remoting when `defaultChoices` is anything other than a `Collection<int>` or `$null`. There are two fixes in this commit. The first is to make sure that `PromptForChoice` serializes the `defaultChoices` value as `Collection<int>`. This ensures that unpatched clients connecting to a patched server can deserialize the expected value for this argument. The second is to support decoding a host method array value when the expected type is `IEnumerable<int>`. This ensures that patches clients connecting to an unpatched server can deserialize the array serialized value.
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
There was a problem hiding this comment.
This is a unit test, with the patched PowerShell it can no longer emit such objects. The test is here to ensure that the decode logic does not regress and PowerShell can continue to receive the serialized array value from older PowerShell versions.
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The compatibility fix is targeted, handles null and empty inputs, and has focused unit and integration coverage.
Review effort: Balanced
Findings: None
What changed in this PR
Hardens multiple-choice host prompts across mixed-version PowerShell remoting endpoints.
Changes:
- Normalizes default choices to
Collection<int>before transmission. - Decodes both array and collection wire formats.
- Adds unit and end-to-end remoting coverage.
| File | Description |
|---|---|
test/xUnit/csharp/test_RemoteHostEncoder.cs |
Tests encoder round trips and invalid formats. |
test/powershell/engine/Remoting/RemoteHostCalls.Tests.ps1 |
Tests remote prompts with supported collection forms. |
src/System.Management.Automation/engine/remoting/server/ServerRemoteHostUserInterface.cs |
Normalizes default choices before encoding. |
src/System.Management.Automation/engine/remoting/common/WireDataFormat/RemoteHostEncoder.cs |
Supports array and collection decoding. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
Ilya (iSazonov)
left a comment
There was a problem hiding this comment.
LGTM with one minor comment.
| defaultChoicesCollection = new Collection<int>(); | ||
| foreach (int choice in defaultChoices) | ||
| { | ||
| defaultChoicesCollection.Add(choice); | ||
| } |
There was a problem hiding this comment.
| defaultChoicesCollection = new Collection<int>(); | |
| foreach (int choice in defaultChoices) | |
| { | |
| defaultChoicesCollection.Add(choice); | |
| } | |
| defaultChoicesCollection = new Collection<int>(new List<int>(defaultChoices)); |
There was a problem hiding this comment.
Is that not going to add the items to a list then go through it again to add to the collection? I don't know much about the internal details here but with the current implementation it only enumerates and adds once. Most likely a moot point because this enumerable is going to be so small.
PR Summary
Fixes
IHostUISupportsMultipleChoiceSelection.PromptForChoiceover PowerShell remoting whendefaultChoicesis anything other than aCollection<int>or$null. There are two fixes in this commit.The first is to make sure that
PromptForChoiceserializes thedefaultChoicesvalue asCollection<int>. This ensures that unpatched clients connecting to a patched server can deserialize the expected value for this argument.The second is to support decoding a host method array value when the expected type is
IEnumerable<int>. This ensures that patches clients connecting to an unpatched server can deserialize the array serialized value.PR Context
Calling the multiple-choice
PromptForChoiceoverload directly in a local session when using[int[]]fordefaultChoicesworks out of the box:Calling the same overload in a remote PSSession with an
int[]fordefaultChoicesfails. The script below reproduces it without any WinRM or SSH setup by opening a named-pipe session back to the current process:Before this change:
After this change:
RemoteHostEncoder chooses the wire format from the value's runtime type when encoding, but the client decodes using the method's declared parameter type. The defaultChoices parameter is declared as
IEnumerable<int>, and the client always decoded it as aCollection<int>(anArrayListon the wire). Anint[]is encoded with the array format (mae/mal properties), so the server serializes and sends the call without error and the client then fails to decode it. Other types such asList<int>fail earlier, on the server, with "Remote host method data encoding is not supported for type ...".Passing an array is the usual case due to the simplicity in declaring
[int[]]over[Collections.ObjectModel.Collection[int]]. So in practice this API only worked remotely when defaultChoices was$nullor an explicitCollection<int>.This behaviour dates back to Windows PowerShell 5.1 so is present in all of 7.x.
PR Checklist
.h,.cpp,.cs,.ps1and.psm1files have the correct copyright header