-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Add exec cmdlet for bash compatibility
#16462
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
Merged
Merged
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
1e499d4
Add `exec` function for bash compatibility
SteveL-MSFT 8895262
add tests
SteveL-MSFT a884a63
change implementation to call execv()
SteveL-MSFT ecf5c1c
fix so that alias also only shows up on Unix
SteveL-MSFT ac14ffa
Update src/System.Management.Automation/engine/Modules/SwitchProcessC…
SteveL-MSFT 22a9a54
Update src/System.Management.Automation/engine/Modules/SwitchProcessC…
SteveL-MSFT 8f8e2a9
address Ilya's feedback and added test to verify process got switched
SteveL-MSFT cdf81d6
change test to use string instead of array
SteveL-MSFT 25ee498
change first arg to just be program name instead of path
SteveL-MSFT 9d5829a
Fix Windows tests
SteveL-MSFT e235abd
skip help test for Switch-Process as the content doesn't exist
SteveL-MSFT eb84151
add tracing to see why test is failing in CI
SteveL-MSFT a233116
fix test by only selecting first instance of sleep command
SteveL-MSFT c44b5c7
Update src/System.Management.Automation/engine/Modules/SwitchProcessC…
SteveL-MSFT 1064ceb
Update src/System.Management.Automation/resources/CommandBaseStrings.…
SteveL-MSFT f103f0a
Update test/powershell/Modules/Microsoft.PowerShell.Core/Exec.Tests.ps1
SteveL-MSFT 4dedf66
update error message to include the command line
SteveL-MSFT 72814ba
Update src/System.Management.Automation/engine/Modules/SwitchProcessC…
SteveL-MSFT 9e9a088
Update src/System.Management.Automation/resources/CommandBaseStrings.…
SteveL-MSFT ef166e5
Change to not accept input from pipeline
SteveL-MSFT File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
115 changes: 115 additions & 0 deletions
115
src/System.Management.Automation/engine/Modules/SwitchProcessCommand.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| #nullable enable | ||
|
|
||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Management.Automation; | ||
| using System.Runtime.InteropServices; | ||
|
|
||
| using Dbg = System.Management.Automation.Diagnostics; | ||
|
|
||
| #if UNIX | ||
|
|
||
| namespace Microsoft.PowerShell.Commands | ||
| { | ||
| /// <summary> | ||
| /// Implements a cmdlet that allows use of execv API. | ||
| /// </summary> | ||
| [Experimental(ExperimentalFeature.PSExecFeatureName, ExperimentAction.Show)] | ||
| [Cmdlet(VerbsCommon.Switch, "Process", HelpUri = "https://go.microsoft.com/fwlink/?linkid=2181448")] | ||
| public sealed class SwitchProcessCommand : PSCmdlet | ||
| { | ||
| /// <summary> | ||
| /// Get or set the command and arguments to replace the current pwsh process. | ||
| /// </summary> | ||
| [Parameter(Position = 0, Mandatory = false, ValueFromRemainingArguments = true)] | ||
| public string[] WithCommand { get; set; } = Array.Empty<string>(); | ||
|
|
||
| /// <summary> | ||
| /// Execute the command and arguments | ||
| /// </summary> | ||
| protected override void EndProcessing() | ||
| { | ||
| if (WithCommand.Length == 0) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| // execv requires command to be full path so resolve command to first match | ||
| var command = this.SessionState.InvokeCommand.GetCommand(WithCommand[0], CommandTypes.Application); | ||
SteveL-MSFT marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (command is null) | ||
| { | ||
| ThrowTerminatingError( | ||
| new ErrorRecord( | ||
| new CommandNotFoundException( | ||
| string.Format( | ||
| System.Globalization.CultureInfo.InvariantCulture, | ||
| CommandBaseStrings.NativeCommandNotFound, | ||
| command | ||
| ) | ||
| ), | ||
| "CommandNotFound", | ||
| ErrorCategory.InvalidArgument, | ||
| WithCommand | ||
| ) | ||
| ); | ||
| } | ||
|
|
||
| var execArgs = new string?[WithCommand.Length + 1]; | ||
|
|
||
| // execv convention is the first arg is the program name | ||
| execArgs[0] = command.Name; | ||
|
|
||
| for (int i = 1; i < WithCommand.Length; i++) | ||
| { | ||
| execArgs[i] = WithCommand[i]; | ||
| } | ||
|
|
||
| // need null terminator at end | ||
| execArgs[execArgs.Length - 1] = null; | ||
|
|
||
| int exitCode = Exec(command.Source, execArgs); | ||
|
|
||
| if (exitCode < 0) | ||
| { | ||
| ThrowTerminatingError( | ||
| new ErrorRecord( | ||
| new Exception( | ||
| string.Format( | ||
| System.Globalization.CultureInfo.InvariantCulture, | ||
| CommandBaseStrings.ExecFailed, | ||
| Marshal.GetLastPInvokeError(), | ||
| string.Join(" ", WithCommand) | ||
| ) | ||
| ), | ||
| "ExecutionFailed", | ||
| ErrorCategory.InvalidOperation, | ||
| WithCommand | ||
| ) | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// The `execv` POSIX syscall we use to exec /bin/sh. | ||
| /// </summary> | ||
| /// <param name="path">The path to the executable to exec.</param> | ||
| /// <param name="args"> | ||
| /// The arguments to send through to the executable. | ||
| /// Array must have its final element be null. | ||
| /// </param> | ||
| /// <returns> | ||
| /// An exit code if exec failed, but if successful the calling process will be overwritten. | ||
| /// </returns> | ||
| [DllImport("libc", | ||
| EntryPoint = "execv", | ||
| CallingConvention = CallingConvention.Cdecl, | ||
| CharSet = CharSet.Ansi, | ||
| SetLastError = true)] | ||
| private static extern int Exec(string path, string?[] args); | ||
| } | ||
| } | ||
|
|
||
| #endif | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 74 additions & 0 deletions
74
test/powershell/Modules/Microsoft.PowerShell.Core/Exec.Tests.ps1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| # Copyright (c) Microsoft Corporation. | ||
| # Licensed under the MIT License. | ||
|
|
||
| Describe 'Switch-Process tests for Unix' -Tags 'CI' { | ||
| BeforeAll { | ||
| $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() | ||
| if (-not [ExperimentalFeature]::IsEnabled('PSExec') -or $IsWindows) | ||
| { | ||
| $PSDefaultParameterValues['It:Skip'] = $true | ||
| return | ||
| } | ||
| } | ||
|
|
||
| AfterAll { | ||
| $global:PSDefaultParameterValues = $originalDefaultParameterValues | ||
| } | ||
|
|
||
| It 'Exec alias should map to Switch-Process' { | ||
| $alias = Get-Command exec | ||
| $alias | Should -BeOfType [System.Management.Automation.AliasInfo] | ||
| $alias.Definition | Should -BeExactly 'Switch-Process' | ||
| } | ||
|
|
||
| It 'Exec by itself does nothing' { | ||
| exec | Should -BeNullOrEmpty | ||
| } | ||
|
|
||
| It 'Exec given a cmdlet should fail' { | ||
| { exec Get-Command } | Should -Throw -ErrorId 'CommandNotFound,Microsoft.PowerShell.Commands.SwitchProcessCommand' | ||
| } | ||
|
|
||
| It 'Exec given an exe should work' { | ||
| $id, $uname = pwsh -noprofile -noexit -outputformat text -command { $pid; exec uname } | ||
| Get-Process -Id $id -ErrorAction Ignore| Should -BeNullOrEmpty | ||
| $uname | Should -BeExactly (uname) | ||
| } | ||
|
|
||
| It 'Exec given an exe and arguments should work' { | ||
| $id, $uname = pwsh -noprofile -noexit -outputformat text -command { $pid; exec uname -a } | ||
| Get-Process -Id $id -ErrorAction Ignore| Should -BeNullOrEmpty | ||
| $uname | Should -BeExactly (uname -a) | ||
| } | ||
|
|
||
| It 'Exec will replace the process' { | ||
| $sleep = Get-Command sleep -CommandType Application | Select-Object -First 1 | ||
| $p = Start-Process pwsh -ArgumentList "-noprofile -command exec $($sleep.Source) 90" -PassThru | ||
| Wait-UntilTrue { | ||
| ($p | Get-Process).Name -eq 'sleep' | ||
| } -timeout 60000 -interval 100 | Should -BeTrue | ||
iSazonov marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
|
|
||
| Describe 'Switch-Process for Windows' { | ||
| BeforeAll { | ||
| $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() | ||
| if (-not $IsWindows) | ||
| { | ||
| $PSDefaultParameterValues['It:Skip'] = $true | ||
| return | ||
| } | ||
| } | ||
|
|
||
| AfterAll { | ||
| $global:PSDefaultParameterValues = $originalDefaultParameterValues | ||
| } | ||
|
|
||
| It 'Switch-Process should not be available' { | ||
| Get-Command -Name Switch-Process -ErrorAction Ignore | Should -BeNullOrEmpty | ||
| } | ||
|
|
||
| It 'Exec alias should not be available' { | ||
| Get-Alias -Name exec -ErrorAction Ignore | Should -BeNullOrEmpty | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.