GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||
GeezerVison is showing github.com — Fix `Start-Process -Credential -Wait` to work on Windows by SteveL-MSFT · Pull Request #19082 · PowerShell/PowerShell Conversation
|
|
@PowerShell/wg-powershell-cmdlets discussed the issue and agreed that in the credential case, it's ok to not support the job object case with child processes |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
So I believe it is safe to remove try-catch and immediately call process.WaitForExit() if Credential parameter present. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Ilya (@iSazonov) yes, that makes sense. I'll update the code. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
5318b3b to
3e8f71a
Compare
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
LGTM with one minor comment.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
…nt/Process.cs Co-authored-by: Ilya <[email protected]>
|
This PR has Quantification details
Why proper sizing of changes matters
Optimal pull request sizes drive a better predictable PR flow as they strike a
What can I do to optimize my changes
How to interpret the change counts in git diff output
Was this comment helpful? 👍 :ok_hand: :thumbsdown: (Email) |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| // Wait for the job object to finish | ||
| jobObject.WaitOne(_waithandle); | ||
| // If we are running as a different user, we cannot use a job object, so just wait on the process | ||
| process.WaitForExit(); |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason not to always use process.WaitForExit()? Also if the user provides explicit credentials for the current user account, process.WaitForExit() will be used instead of the job object. Is this Ok?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
-Wait will wait not just for the new process but any processes that the new process spawns. By waiting on the job object it will wait until all of them have finished rather than just the current one.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I think the intent of the job object is to also wait on any child processes, but processes in for a different user can't be added to the job object so in that case we can only WaitForExit() of the initial process. WG had discussed this and was ok with this difference.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
but processes in for a different user can't be added to the job object
This is not true, did you read my last comment - #19082 (comment)?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
That may be true but specifying a credential does not result in the process being run in a new session, it's still the same one. A new session happens when you do something like log into RDP as another user, or run something from a service which is in session 0. Ultimately this isn't the problem here. The problem that you get today with
Now this actually works today when you are running as admin, it will wait for the process, as well as any child processes the new process spawns as expected. Where this fails is if you try and run it as a non-administrator as while the user was able to spawn the object, process permissions on the new one will not allow the caller to get the Handle needed for The problem with this fix is that while it might work in some scenarios it is technically a breaking change as Just to show that this works even for non-admins if done correctly you can run this code. # Uses Ctypes - https://www.powershellgallery.com/packages/Ctypes/0.1.0 ctypes_struct STARTUPINFOW -CharSet Unicode { [int]$CB [MarshalAs('LPWStr')][string]$Reserved [MarshalAs('LPWStr')][string]$Desktop [MarshalAs('LPWStr')][string]$Title [int]$X [int]$Y [int]$XSize [int]$YSize [int]$XCountChars [int]$YCountChars [int]$FillAttribute [int]$Flags [short]$ShowWindow [short]$Reserved2 [IntPtr]$Reserved3 [IntPtr]$StdInput [IntPtr]$StdOutput [IntPtr]$StdError } ctypes_struct PROCESS_INFORMATION -LayoutKind Sequential { [IntPtr]$Process [IntPtr]$Thread [int]$Pid [int]$Tid } [Flags()] enum ProcessCreationFlags { NONE = 0x00000000 CREATE_SUSPENDED = 0x00000004 CREATE_NEW_CONSOLE = 0x00000010 CREATE_UNICODE_ENVIRONMENT = 0x00000400 } $si = [STARTUPINFOW]@{ CB = [System.Runtime.InteropServices.Marshal]::SizeOf([Type][STARTUPINFOW]) } $pi = [PROCESS_INFORMATION]::new() $advapi32 = New-CtypesLib Advapi32.dll $kernel32 = New-CtypesLib Kernel32.dll $commandLine = [System.Text.StringBuilder]::new("C:\Windows\System32\cmd.exe") $res = $advapi32.SetLastError().CharSet('Unicode').CreateProcessWithLogonW[bool]( "vagrant", $null, "vagrant", 0, $commandLine.ToString(), $commandLine, [int][ProcessCreationFlags]'CREATE_SUSPENDED, CREATE_NEW_CONSOLE, CREATE_UNICODE_ENVIRONMENT', $null, "C:\Windows", [ref]$si, [ref]$pi ) if (-not $res) { throw [System.ComponentModel.Win32Exception]$advapi32.LastError } $job = $kernel32.SetLastError().CreateJobObjectW[IntPtr]($null, "MyJob") if ($job -eq [IntPtr]::Zero) { throw [System.ComponentModel.Win32Exception]$kernel32.LastError } $res = $kernel32.SetLastError().AssignProcessToJobObject[bool]($job, $pi.Process) if (-not $res) { throw [System.ComponentModel.Win32Exception]$kernel32.LastError } $res = $kernel32.SetLastError().ResumeThread($pi.Thread) if ($res -eq -1) { throw [System.ComponentModel.Win32Exception]$kernel32.LastError } $kernel32.CloseHandle[void]($pi.Process) $kernel32.CloseHandle[void]($pi.Thread) $kernel32.CloseHandle[void]($job) I even do this in my ProcessEx module with no problems. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Jordan Borean (@jborean93) Can you create a new issue about this? |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
Paul Higinbotham (@PaulHigin) there is one already #17033. Why would we merge a change where it changes the existing behaiour? It should be fixed properly in the first place. I'm a bit disappointed this was merged before someone actually read and addressed my last comment. Especially since PowerShell has traditionally tried to shy away from behaviour changes. It's especially concerning that a change like this was merged without:
The last point also ties into issues I had with the 7.3 release where there were a few breaking/behaviour changes but no real way for people to understand what that might be until they upgraded and things failed. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Jordan Borean (@jborean93) would you be willing to submit a PR to fix this to work with a job object? |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Opened #19096, just need to figure out a good way to test it out. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
This issue has been resolved as implemented (via #19082) |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Thomas Lee (@doctordns) What do you mean? |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
This issue was raised to the cmdlet working group, and we felt the issue was concluded via #19082. Steve Lee (@SteveL-MSFT) agreed, so I labeled this issue as resolved-fixed. Is there a problem? |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
You write in 19082 - it is not issue, it is PR. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
🎉 Handy links: |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
…19082) * address Ilya's feedback, simplify to just WaitForExit() when cred is used * Update src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs Co-authored-by: Ilya <[email protected]> --------- Co-authored-by: Ilya <[email protected]>
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
Start-Process -Wait doesn't work when running as a different user (-Credential)
There was an error while loading. Please reload this page.