microsoft / sudo

It's sudo, for Windows

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

megathread: sudo should better support PowerShell

zadjii-msft opened this issue · comments

Currently, sudo only works for elevating an actual executable1. For something like Get-ChildItem (gci) in PowerShell, that's not an executable, it's a cmdlet. We'll need a proper PowerShell module to be able to properly support various PowerShell scenarios.

In the time being, we're working on the sudo.ps1 script to provide a better experience for using sudo from PowerShell.

Tasks

  1. Issue-Feature

Footnotes

  1. It also supports CMD intrinsics, when run from CMD.exe.

My two cents are... The less, the better.

PowerShell already has some degree of support for Unix/Linux sudo both on Linux and WSL, thanks to the so-called "MiniShell mode"
image

When PS invokes an external command and finds a scriptblock, it serializes it and adds special arguments to allow Standard I/O CLIXML serialization. It also auto-fallbacks to output-format text if you don't capture the result (which really improves performance). Here is a dump of how it works:

image

This makes sudo pwsh {scriptblock} -args $arg1, $arg2... syntax work out-of-the-box on Linux's sudo, gsudo, and ms-sudo.

gsudo has syntax sugar for shell detection, which makes the pwsh word not required. You can do that by prepending pwsh.exe to the command to elevate when it starts with -encodedCommand. Beware than doing that may confuse users, making them believe the elevation is running in-process.

Regarding other syntaxes besides ScriptBlocks, such as sudo Do-Something:

  • I would love to be wrong here, please let me know if so... but IMO that PS syntax is a string-escaping-hell (quotes, ampersands, | pipes, etc...). Also, operator precedence | will confuse occasional users.
  • if the user just adds some parenthesis then part of the command now runs before the sudo invocation, which makes things confusing. See a confused power user here
    image.
  • Doing this will likely require a sudo.ps1, and it would need to parse the incoming args intended to sudo.exe in order to identify where the command to elevate starts. This duplicates some logic between sudo.ps1 and sudo.exe

Another debatable reason for sudo.ps1 may be to implement sudo !!, but in my opinion, that feature, a relic of the 1980s, is frustrating in modern PowerShell. Try it on gsudo. I hate it, even though I coded it

Lastly, when you run sudo Do-Something your out of process sudo.exe will never know if Do-Something is an .exe or a PS alias. A sudo.ps1 could detect that, but helplessly won't be able to ensure that Do-Something function has the exact source on the elevated pwsh.

For all these reasons, plus the difficulty of per-user installation, I think shipping a sudo.ps1 should be avoided.

What I suggest, is to add an auto-completion script to ms-sudo, to be added to each $PROFILE, like sudo completition powershell | Invoke-Expression, analog to kubectl completion powershell | Out-String | Invoke-Expression See docs.
Once that is implemented, sudo+[tab-key] can be a modern sudo !! and auto-complete with your last ran command, (but rewritten with the {scriptblock} syntax. Extra points if it detects the $variables and replace them with args[0], args[1], and so... for example:

PS C:\> $process = 'notepad.exe'

PS C:\> Get-Process $process | Stop-Process
Stop-Process: Access Denied.

PS C:\> sudo [press-tab-key]
[Then the line auto completes as:]

PS C:\> sudo pwsh {Get-Process $args[0] | Stop-Process } -args $process

This autocompletion script micro-spec, would work for Linux sudo too... So maybe is in the interest of the PowerShell team to implement ?

I hope you find this insights useful.

PowerShell should not be the shell of priority here. Rather, all "Shell Specific Commamnds" can be supported through sudo as said in #62 (comment)

I wonder if sudo is expected to work with shell builtins like PowerShell Cmdlets.

https://superuser.com/questions/241129/why-wont-sudo-cd-work

if the user just adds some parenthesis then part of the command now runs before the sudo invocation, which makes things confusing

Isn't that how sudo works on linux too? You should escape parts of the command if you want it to be executed in the sudo context, otherwise it is always computed before sudo is run 🤔