New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Start-Process: Fix -Credential error as non-admin #21393
Conversation
Just as an FYI I did not create a test in this as it would require being able to create another user (requires admin) then run as non-admin. The test runner doesn't seem to have an easy way to really do this so I skipped it. |
When using Start-Process -Credential in a non-administrator context with a different user's credentials the code currently throws an exception when attempting to get the new process' handle. This change treats this error as a warning only if -PassThru was specified as it only affects certain members on the returned object like ExitCode but others like WaitForExit() still work fine.
We could try to create a test hook. Keyword is |
Isn't that to just tell PowerShell to do something differently internally? I'm not sure how that would help here as the exception occurs in .NET code and not PowerShell. Unless I'm mistaken? The problem that we need to test is doing |
Test hooks are definitely something we do internally. It's kind of like having our own test Web server. And that's not easy to implement for processes. This effort makes sense if we want to actively develop this cmdlet. On the other hand, I suppose we could use the GiHub action config to create a regular user with a single-session password. Or try |
Yea the proper method would be to configure CI to create a test user for this (and other tests) as an admin before it starts pester as the non-admin user. I’ve got no experience with the CI setup in this repository and I probably don’t want to go fiddling around with it without someone from that side advising what they want to do there. As for the test hook I can see if being useful if we want to test out specific code branches but in this case it’s an exception being raised in code that we are calling rather than in code that we control. It wouldn’t make sense to raise an exception ourselves here to just catch it IMO. |
Interesting, .Net uses WindowsTestAccount to create a test user. |
Creating the test user is the simple part with builtin cmdlets |
I forget that we have Windows PowerShell. 😄 We run unelevated tests with Lines 1664 to 1682 in b23607e
So it seems it is easy to create a test user account. |
The question is more when to integrate it. We would need to create the test user before running the Pester process and pass through the credentials somehow. It also would need to cleanup the user once the test is done. I don’t feel comfortable enough without the people who maintain the CI part of this repo to provide their input. I’m also somewhat concerned that the talk to add tests will bog down the fix especially since it should be backported to the next 7.4 release. |
I think this PR will be reviewed quickly as it is a regression. Also, I think we can easily add (and remove) a user to build.psm1 in the try-catch-finally block that is listed above. The only requirement is to generate a password dynamically. It will be in a pwsh variable for the duration of the test. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code changes look good but need Cmdlet WG to review the behavior.
For WG. It seems we never write "warnings" to avoid "noise". So we could remove the "warning" at all or replace it with "verbose" or "debug". |
{ | ||
_ = process.Handle; | ||
} | ||
catch (Win32Exception e) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we check the HRESULT for the specific error rather than treating them all the same?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As getting the Handle
was an attempt to try and set the internal state and not something that is being used in the code I didn't think it was worth setting a specific error code. I can change it but I didn't think it warranted catching a specific error because we aren't doing anything to work around the error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SteveL-MSFT Here we should rather move in the other direction. Since the only operation we do is getting a handle, we rather need to catch and ignore all exceptions, especially since if there is a question about behavior, we can always display the debug message.
Although I think Win32Exception covers everything that is needed.
The @PowerShell/wg-powershell-cmdlets discussed this and compared the behavior to WinPS5.1. We recommend changing from Warning to a Debug message, then handle is null w/o any message so the behavior is consistent with 5.1. |
Updated to become |
Thanks for the reviews and merge! |
We will wait on this change to be released in a preview before considering a backport to 7.4. |
Will that even make a difference. There are people already affected by this and the chances of someone actually using the preview for such use cases I see as rare. |
PR Summary
When using Start-Process -Credential in a non-administrator context with a different user's credentials the code currently throws an exception when attempting to get the new process' handle. This change treats this error as a warning only if -PassThru was specified as it only affects certain members on the returned object like ExitCode but others like WaitForExit() still work fine.
Fixes: #21073
PR Context
The code to retrieve the
Handle
property was added by #20749 which tries to set the internal state of theProcess
object. This works in most cases but can fail if the user is not running as admin and the credentials specified was for another user. This PR turns the exception it raises about being unable to retrieve the handle to now become a warning as some things can still be used with the returned Process object.This isn't a change in the status quo as going back to .NET Framework the returned Process object in the above scenario still could not do things like get the
ExitCode
due to permissions problems. This just ensures that an error/exception is not raised and code that worked in the back will still continue to do so.The ultimately fix here is to start the process through the .NET
System.Diagnostics.Process
class instead of using PInvoke withCreateProcess*
but until they add an API to create a suspended process or build theProcess
object from aSafeHandle
PowerShell cannot do so for all scenarios it deals withProcessStartInfo.CreationFlags
(for Windows only) dotnet/runtime#71515The PR should be considered for a backport to 7.4.x as that was when the change was also introduced.
PR Checklist
.h
,.cpp
,.cs
,.ps1
and.psm1
files have the correct copyright headerWIP:
or[ WIP ]
to the beginning of the title (theWIP
bot will keep its status check atPending
while the prefix is present) and remove the prefix when the PR is ready.(which runs in a different PS Host).