patch 9.2.0006: powershell commands wrongly wrapped when executed
Commit:
https://github.com/vim/vim/commit/20b2365c5f382a4c61cd6b082c37019e789d7cd4
Author: Peter Lustig <
tiam...@gmail.com>
Date: Sun Feb 15 16:14:11 2026 +0000
patch 9.2.0006: powershell commands wrongly wrapped when executed
Problem: powershell commands wrongly wrapped when executed
Solution: Use &{ ... } to wrap commands when powershell/pwsh is in use
(Peter Lustig).
Allow compound commands with 'system()' when 'shell' is 'pwsh'
When the 'shell' option was set to 'powershell' or 'pwsh' and the
'system()' vimscript function was called with an argument containing two
or more shell commands (delimited by ';' or '&'), the function would
always fail with 'E282'.
The cause of the error was that VIM would wrap the shell command string
with parentheses (to allow the entire output to be redirected to a
temporary file for capturing) before actually passing it to the
PowerShell process for execution.
Unlike the typical shell that uses parentheses to group commands (and
possibly spawn a subshell), PowerShell uses them to resolve a single
command (pipeline) to an expression. To group multiple commands with
PowerShell, you must instead wrap them with either the subexpression
operator '$(...)' or an immediately evaluated script block '& { ... }'.
The latter option may be more efficient since it does not buffer its
output like for the former one does.
closes: #19401
Signed-off-by: Peter Lustig <
tiam...@gmail.com>
Signed-off-by: Christian Brabandt <
c...@256bit.org>
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
index bd31de6d1..b56ee268b 100644
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -1810,14 +1810,17 @@ make_filter_cmd(
|| fnamecmp(shell_name, "powershell.exe") == 0
|| fnamecmp(shell_name, "pwsh") == 0
|| fnamecmp(shell_name, "pwsh.exe") == 0);
- len = (long_u)STRLEN(cmd) + 3; // "()" + NUL
+ if (is_powershell)
+ len = (long_u)STRLEN(cmd) + 7; // "& { " + " }" + NUL
+ else
+ len = (long_u)STRLEN(cmd) + 3; // "()" + NUL
}
if (itmp != NULL)
{
if (is_powershell)
- // "& { Get-Content " + " | & " + " }"
- len += (long_u)STRLEN(itmp) + 24;
+ // "Get-Content " + " | & "
+ len += (long_u)STRLEN(itmp) + 17;
else
len += (long_u)STRLEN(itmp) + 9; // " { < " + " } "
}
@@ -1836,7 +1839,7 @@ make_filter_cmd(
vim_snprintf((char *)buf, len, "& { Get-Content %s | & %s }",
itmp, cmd);
else
- vim_snprintf((char *)buf, len, "(%s)", cmd);
+ vim_snprintf((char *)buf, len, "& { %s }", cmd);
}
else
{
diff --git a/src/testdir/test_system.vim b/src/testdir/test_system.vim
index b4f5e688b..3eb950860 100644
--- a/src/testdir/test_system.vim
+++ b/src/testdir/test_system.vim
@@ -178,4 +178,36 @@ func Test_windows_external_cmd_in_cwd()
set guioptions&
endfunc
+func Test_system_with_powershell()
+ CheckPowerShell
+
+ let shell_save = &shell
+ let shellcmdflag_save = &shellcmdflag
+ let shellxquote_save = &shellxquote
+ let shellpipe_save = &shellpipe
+ let shellredir_save = &shellredir
+ try
+ if executable('powershell')
+ let &shell = 'powershell'
+ let &shellcmdflag = '-Command'
+ let &shellredir = '2>&1 | Out-File -Encoding default'
+ else
+ let &shell = 'pwsh'
+ let &shellcmdflag = '-c'
+ let &shellredir = '>%s 2>&1'
+ endif
+ let &shellxquote = has('win32') ? '"' : ''
+ let &shellpipe = &shellredir
+
+ " Make sure compound commands are handled properly.
+ call assert_equal("123
456
", system('echo 123; echo 456'))
+ finally
+ let &shell = shell_save
+ let &shellcmdflag = shellcmdflag_save
+ let &shellxquote = shellxquote_save
+ let &shellpipe = shellpipe_save
+ let &shellredir = shellredir_save
+ endtry
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/util/check.vim b/src/testdir/util/check.vim
index 717101607..8df985091 100644
--- a/src/testdir/util/check.vim
+++ b/src/testdir/util/check.vim
@@ -142,6 +142,14 @@ func CheckNotMacM1()
endif
endfunc
+" Command to check whether PowerShell is available
+command CheckPowerShell call CheckPowerShell()
+func CheckPowerShell()
+ if !executable('powershell') && !executable('pwsh')
+ throw 'Skipped: requires Powershell to be installed'
+ endif
+endfunc
+
func SetupWindowSizeToForVisualDumps()
" The dumps used as reference in these tests were created with a terminal
" width of 75 columns. The vim window that uses the remainder of the GUI
diff --git a/src/version.c b/src/version.c
index 2c6404fb0..8c18d1c3e 100644
--- a/src/version.c
+++ b/src/version.c
@@ -734,6 +734,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 6,
/**/
5,
/**/