Skip to content

Conversation

@jborean93
Copy link
Collaborator

PR Summary

Emit an exception when attempting to use Get-PSSession -ComputerName on a non-Windows platform that makes it clear it cannot be used on those platforms. Now when running this on non-Windows it will emit the following error.

PS /home/jborean/dev/PowerShell> Get-PSSession -ComputerName foo
Get-PSSession: Remote PSSession enumeration with -ComputerName is only supported on Windows and not "Arch Linux".

PR Context

I don't think this feature will ever be implemented, even if it is it would be nice to error with a proper message not the current

Get-PSSession: The term 'New-WSManSessionOption' is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

Fixes: #20995

PR Checklist

@iSazonov iSazonov added the CL-General Indicates that a PR should be marked as a general cmdlet change in the Change Log label Jan 5, 2024
@iSazonov iSazonov requested a review from TravisEz13 January 5, 2024 12:27
@iSazonov
Copy link
Collaborator

iSazonov commented Jan 5, 2024

There was WG conclusion about root of the issue #6321 (comment)

@jborean93
Copy link
Collaborator Author

There was WG conclusion about root of the issue #6321 (comment)

I think Paul may have been confused there, Get-PSSession -ComputerName is and has always been focused purely on WSMan. It sends a SOAP request to the WSMan service to ask it to enumerate the number of shells open and has it return that list. There is nothing here that can be replicated under ssh and even if there was it would be part of a new -HostName parameter to match up with how other PSRemoting cmdlets like Invoke-Command and Enter-PSSession. In short getting -ComputerName to work on non-Windows requires the PowerShell team to start shipping the Microsoft.WSMan.Management module on non-Windows which requires more work with the omi library to get working properly. They've repeatedly said in the past they have don't want anything to do with WSMan anymore so instead of waiting forever for this to be re-implemented I thought at least a better error saying this only works on Windows is best.

@jborean93 jborean93 closed this Jan 5, 2024
@jborean93 jborean93 reopened this Jan 5, 2024
@pull-request-quantifier-deprecated

This PR has 19 quantified lines of changes. In general, a change size of upto 200 lines is ideal for the best PR experience!


Quantification details

Label      : Extra Small
Size       : +18 -1
Percentile : 7.6%

Total files changed: 3

Change summary by file extension:
.cs : +15 -1
.resx : +3 -0

Change counts above are quantified counts, based on the PullRequestQuantifier customizations.

Why proper sizing of changes matters

Optimal pull request sizes drive a better predictable PR flow as they strike a
balance between between PR complexity and PR review overhead. PRs within the
optimal size (typical small, or medium sized PRs) mean:

  • Fast and predictable releases to production:
    • Optimal size changes are more likely to be reviewed faster with fewer
      iterations.
    • Similarity in low PR complexity drives similar review times.
  • Review quality is likely higher as complexity is lower:
    • Bugs are more likely to be detected.
    • Code inconsistencies are more likely to be detected.
  • Knowledge sharing is improved within the participants:
    • Small portions can be assimilated better.
  • Better engineering practices are exercised:
    • Solving big problems by dividing them in well contained, smaller problems.
    • Exercising separation of concerns within the code changes.

What can I do to optimize my changes

  • Use the PullRequestQuantifier to quantify your PR accurately
    • Create a context profile for your repo using the context generator
    • Exclude files that are not necessary to be reviewed or do not increase the review complexity. Example: Autogenerated code, docs, project IDE setting files, binaries, etc. Check out the Excluded section from your prquantifier.yaml context profile.
    • Understand your typical change complexity, drive towards the desired complexity by adjusting the label mapping in your prquantifier.yaml context profile.
    • Only use the labels that matter to you, see context specification to customize your prquantifier.yaml context profile.
  • Change your engineering behaviors
    • For PRs that fall outside of the desired spectrum, review the details and check if:
      • Your PR could be split in smaller, self-contained PRs instead
      • Your PR only solves one particular issue. (For example, don't refactor and code new features in the same PR).

How to interpret the change counts in git diff output

  • One line was added: +1 -0
  • One line was deleted: +0 -1
  • One line was modified: +1 -1 (git diff doesn't know about modified, it will
    interpret that line like one addition plus one deletion)
  • Change percentiles: Change characteristics (addition, deletion, modification)
    of this PR in relation to all other PRs within the repository.


Was this comment helpful? 👍  :ok_hand:  :thumbsdown: (Email)
Customize PullRequestQuantifier for this repository.

@iSazonov
Copy link
Collaborator

iSazonov commented Jan 6, 2024

Hmm, I see Paul said that we can enumerate any PSSession objects which was created in current process.

@jborean93
Copy link
Collaborator Author

Yep and using -ComputerName is for sessions on a completely different host. In fact it uses a mechanism in the WSMan service and not PowerShell itself to track the sessions on the remote host. Maybe how PowerShell tracks that information can be expanded in the future but it shouldn’t hold up something like this.

@iSazonov
Copy link
Collaborator

iSazonov commented Jan 6, 2024

@jborean93 For my education, does -ComputerName return all remote pssessions on the remote computer or only sessions created from the current pwsh process?

@jborean93
Copy link
Collaborator Author

jborean93 commented Jan 6, 2024

When you do Get-PSSession -ComputerName foo PowerShell internally runs the following:

$getParams = @{
    ResourceURI = 'Shell'
    Enumerate = $true
    ComputerName = 'foo'
    SessionOption = (New-WSManSessionOption)
}
Get-WSManInstance @getParams

In protocol terms this sends the following WSMan POST message to foo:

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:n="http://schemas.xmlsoap.org/ws/2004/09/enumeration" xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:p="http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd" xmlns:b="http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd">
  <s:Header>
    <a:To>http://foo:5985/wsman</a:To>
    <w:ResourceURI s:mustUnderstand="true">http://schemas.microsoft.com/wbem/wsman/1/windows/shell</w:ResourceURI>
    <a:ReplyTo>
      <a:Address s:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address>
    </a:ReplyTo>
    <a:Action s:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/09/enumeration/Enumerate</a:Action>
    <w:MaxEnvelopeSize s:mustUnderstand="true">512000</w:MaxEnvelopeSize>
    <a:MessageID>uuid:B03C7765-66AC-4DAB-B84D-BC62464A1AC8</a:MessageID>
    <w:Locale xml:lang="en-US" s:mustUnderstand="false"/>
    <p:DataLocale xml:lang="en-US" s:mustUnderstand="false"/>
    <p:SessionId s:mustUnderstand="false">uuid:00DC848B-B247-485C-B144-EB709AA1586A</p:SessionId>
    <p:OperationID s:mustUnderstand="false">uuid:CB4C0368-D3A8-45D0-AE6E-2C1B90FAD70E</p:OperationID>
    <p:SequenceId s:mustUnderstand="false">1</p:SequenceId>
    <w:OperationTimeout>PT60.000S</w:OperationTimeout>
  </s:Header>
  <s:Body>
    <n:Enumerate>
      <w:OptimizeEnumeration/>
      <w:MaxElements>32000</w:MaxElements>
    </n:Enumerate>
  </s:Body>
</s:Envelope>

This Enumerate action tells the WSMan service on foo to return all "shells" that have been opened on the service. Note there is no client information like the process or host it is from which means foo will be returning all shells it knows about. After receiving this request foo will return the following EnumerateResponse

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:n="http://schemas.xmlsoap.org/ws/2004/09/enumeration" xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:p="http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd" xml:lang="en-US">
  <s:Header>
    <a:Action>http://schemas.xmlsoap.org/ws/2004/09/enumeration/EnumerateResponse</a:Action>
    <a:MessageID>uuid:142D87D6-7CBC-4E9E-9D4F-95CD0EE5CAA2</a:MessageID>
    <a:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:To>
    <p:OperationID s:mustUnderstand="false">uuid:CB4C0368-D3A8-45D0-AE6E-2C1B90FAD70E</p:OperationID>
    <p:SequenceId>1</p:SequenceId>
    <a:RelatesTo>uuid:B03C7765-66AC-4DAB-B84D-BC62464A1AC8</a:RelatesTo>
  </s:Header>
  <s:Body>
    <n:EnumerateResponse>
      <n:EnumerationContext/>
      <w:Items>
        <rsp:Shell xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell">
          <rsp:ShellId>E578F8FB-5A82-4491-AC46-E04EDBD41CD7</rsp:ShellId>
          <rsp:Name>WinRM1</rsp:Name>
          <rsp:ResourceUri>http://schemas.microsoft.com/powershell/Microsoft.PowerShell</rsp:ResourceUri>
          <rsp:Owner>DOMAIN\vagrant-domain</rsp:Owner>
          <rsp:ClientIP>192.168.56.12</rsp:ClientIP>
          <rsp:ProcessId>832</rsp:ProcessId>
          <rsp:IdleTimeOut>PT7200.000S</rsp:IdleTimeOut>
          <rsp:InputStreams>stdin pr</rsp:InputStreams>
          <rsp:OutputStreams>stdout</rsp:OutputStreams>
          <rsp:MaxIdleTimeOut>PT2147483.647S</rsp:MaxIdleTimeOut>
          <rsp:Locale>en-US</rsp:Locale>
          <rsp:DataLocale>en-US</rsp:DataLocale>
          <rsp:CompressionMode>XpressCompression</rsp:CompressionMode>
          <rsp:ProfileLoaded>Yes</rsp:ProfileLoaded>
          <rsp:Encoding>UTF8</rsp:Encoding>
          <rsp:BufferMode>Block</rsp:BufferMode>
          <rsp:State>Connected</rsp:State>
          <rsp:ShellRunTime>P0DT0H2M29S</rsp:ShellRunTime>
          <rsp:ShellInactivity>P0DT0H2M29S</rsp:ShellInactivity>
          <rsp:MemoryUsed>62MB</rsp:MemoryUsed>
          <rsp:ChildProcesses>0</rsp:ChildProcesses>
        </rsp:Shell>
        <rsp:Shell xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell">
          <rsp:ShellId>D76BA8D1-C52A-4E10-8A28-46262426AC09</rsp:ShellId>
          <rsp:Name>Runspace1</rsp:Name>
          <rsp:ResourceUri>http://schemas.microsoft.com/powershell/PowerShell.7</rsp:ResourceUri>
          <rsp:Owner>DOMAIN\vagrant-domain</rsp:Owner>
          <rsp:ClientIP>192.168.56.12</rsp:ClientIP>
          <rsp:ProcessId>6900</rsp:ProcessId>
          <rsp:IdleTimeOut>PT7200.000S</rsp:IdleTimeOut>
          <rsp:InputStreams>stdin pr</rsp:InputStreams>
          <rsp:OutputStreams>stdout</rsp:OutputStreams>
          <rsp:MaxIdleTimeOut>PT2147483.647S</rsp:MaxIdleTimeOut>
          <rsp:Locale>en-US</rsp:Locale>
          <rsp:DataLocale>en-US</rsp:DataLocale>
          <rsp:CompressionMode>XpressCompression</rsp:CompressionMode>
          <rsp:ProfileLoaded>Yes</rsp:ProfileLoaded>
          <rsp:Encoding>UTF8</rsp:Encoding>
          <rsp:BufferMode>Block</rsp:BufferMode>
          <rsp:State>Connected</rsp:State>
          <rsp:ShellRunTime>P0DT0H2M18S</rsp:ShellRunTime>
          <rsp:ShellInactivity>P0DT0H2M16S</rsp:ShellInactivity>
          <rsp:MemoryUsed>97MB</rsp:MemoryUsed>
          <rsp:ChildProcesses>1</rsp:ChildProcesses>
        </rsp:Shell>
      </w:Items>
      <w:EndOfSequence/>
    </n:EnumerateResponse>
  </s:Body>
</s:Envelope>

In this case foo has 2 shells that are open, one for Microsoft.PowerShell and another for PowerShell.7. They are both Connected which means they are still active and in use by a client. These could be Disconnected and waiting to be reconnected but the point is that the WSMan service reports all shells it has open. PowerShell then uses the information of each shell and filters out the results that don't match whatever the filter criteria specified by the user was. It also filters out any shells that don't have a resource uri prefix of http://schemas.microsoft.com/powershell/ to only return PowerShell sessions.

Ultimately it's all sessions managed by the remote service not just ones opened by the current process/computer. This is why -ComputerName is purely a WSMan thing as it has no idea about SSH PSSessions or any other connection type.

@iSazonov
Copy link
Collaborator

iSazonov commented Jan 7, 2024

Thanks for the full answer!

I believe the user must have the appropriate permissions for WSMan to return the list of sessions. In this case, the user could connect to the remote computer via SSH, get a list of all pwsh processes and even connect to them via local socket. Maybe this is what Paul meant.

@jborean93
Copy link
Collaborator Author

I believe the user must have the appropriate permissions for WSMan to return the list of sessions

It certainly needs permission to perform the Enumerate action but I'm not aware of any extra permissions applied to what WSMan returns. Typically the access checks is done when you attempt to open one of the PSSessions as now you need to reauthenticate as the same user it was created with.

In this case, the user could connect to the remote computer via SSH, get a list of all pwsh processes and even connect to them via local socket. Maybe this is what Paul meant.

Potentially, honestly I don't see Get-PSSession continuing to be used for enumerating PSSession's remotely. It could be expanded in the future to somehow track active PSSessions on the current host using a common mechanism in PowerShell and then combined with Invoke-Command to provide remote access. The benefit of Get-PSSession -ComputerName ... on Windows is the ability to get disconnected sessions and re-connect them on the new client. As WSMan is the only PSRemoting protocol that supports disconnected sessions (and custom transports cannot do so) then it makes sense only keeping this as Windows only.

@iSazonov
Copy link
Collaborator

iSazonov commented Jan 8, 2024

As WSMan is the only PSRemoting protocol that supports disconnected sessions (and custom transports cannot do so)

Eh, this will definitely be in demand for the management tool that is PowerShell. If WSMan does this, then users will expect the same from any custom transport that replaces WSMan. It would be better for UX if the base cmdlets didn't change and were independent of transport.

@jborean93
Copy link
Collaborator Author

I honestly feel like PSRemoting is inferior in pretty much most circumstances for interactive use which is where you typically want disconnection support. Using pure ssh with tools like tmux offer such a better experience and will be what I typically recommend going forward.

Someone may want to reimplement disconnection support for custom transports but it’ll require a lot of work and an even more special server side protocol to make use of it. Until that time I think it’s safe to just make this functionality Windows only.

@microsoft-github-policy-service microsoft-github-policy-service bot added the Review - Needed The PR is being reviewed label Jan 15, 2024
@jborean93
Copy link
Collaborator Author

@SteveL-MSFT it's been over 3 months without any review by someone from the PowerShell team. Any chance this can be added to the next cycle.

Emit an exception when attempting to use Get-PSSession -ComputerName on
a non-Windows platform that makes it clear it cannot be used on those
platforms.
Copy link
Collaborator

@iSazonov iSazonov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jborean93 Please add one test for Unix.
I believe we can merge (after you address my requests) since it is obvious improvement.

<value>Out of process memory.</value>
</data>
<data name="UnsupportedOSForRemoteEnumeration" xml:space="preserve">
<value>Remote PSSession enumeration with -ComputerName is only supported on Windows and not "{0}".</value>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes no sense to point OS version. Please remove:

Suggested change
<value>Remote PSSession enumeration with -ComputerName is only supported on Windows and not "{0}".</value>
<value>Remote PSSession enumeration with -ComputerName is only supported on Windows.</value>

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it provides a few extra debug details and doesn't hurt to include. It's also somewhat helpful to identify where the cmdlet was run when it comes to remoting ones as people may be confused if the OS platform is local or remote based. Including the local OS information in the error helps to avoid that ambiguity.

{
base.BeginProcessing();
#if UNIX
if (ComputerName?.Length > 0)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our common pattern is to check whether a parameter presents.

if (MyInvocation.BoundParameters.ContainsKey(nameof(ComputerName)))

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a particular reason for this. The code uses the ComputerName property value and thus it makes more sense to do the check on the actual property rather than a pwsh-ism here. It's also cleaner and shorter than accessing a dictionary to check if a key exists vs just checking the property value.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah there are situations where it's better but I think it's fine here.

@microsoft-github-policy-service microsoft-github-policy-service bot added Waiting on Author The PR was reviewed and requires changes or comments from the author before being accept and removed Review - Needed The PR is being reviewed Waiting on Author The PR was reviewed and requires changes or comments from the author before being accept labels Oct 4, 2024
@microsoft-github-policy-service microsoft-github-policy-service bot added the Review - Needed The PR is being reviewed label Oct 13, 2024
Copy link
Collaborator

@SeeminglyScience SeeminglyScience left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks Jordan!

@iSazonov iSazonov changed the title Get-PSSession: Add error for -ComputerName on Unix Add error for Get-PSSession -ComputerName on Unix Dec 5, 2024
@iSazonov iSazonov removed the Review - Needed The PR is being reviewed label Dec 5, 2024
@iSazonov iSazonov merged commit 1e07bd0 into PowerShell:master Dec 5, 2024
@microsoft-github-policy-service
Copy link
Contributor

microsoft-github-policy-service bot commented Dec 5, 2024

📣 Hey @jborean93, how did we do? We would love to hear your feedback with the link below! 🗣️

🔗 https://aka.ms/PSRepoFeedback

@jborean93 jborean93 deleted the pssession-computer branch December 5, 2024 11:31
@jshigetomi jshigetomi mentioned this pull request Dec 12, 2024
21 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CL-General Indicates that a PR should be marked as a general cmdlet change in the Change Log Extra Small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Get-PSSession with -ComputerName does not work

3 participants