'In powershell spawn notepad++ when file to open has spaces in it
$npp = "C:\Program Files\Notepad++\notepad++.exe";
$myfiles = @(
"C:\bad boys\file1.txt",
"C:\bad boys\file2.txt",
"C:\bad boys\file3.txt"
)
foreach ($file in $myfiles) {
Start-Process -FilePath $npp -ArgumentList "$file" -PassThru -NoNewWindow | out-null
}
This almost works... except, It doesn't open in notepad++ because it sees the space in the file name and thinks this is where the file path ends... thus, i am unable to open my file list. Any Ideas how to fix? What i get instead is notepad++ asking many times if I want to create the file "C:\bad"
Solution 1:[1]
tl;dr
While Joel Coehoorn's helpful answer provides an effective solution to your Start-Process
problem (which stems from the bug detailed below), you can simplify your code to:
foreach ($file in $myfiles) {
# Note: | Out-Null is a trick that makes calling *GUI* applications
# *synchronous* (makes PowerShell wait for them to exit).
& $npp $file | Out-Null
}
You're seeing a long-standing bug in Start-Process
that causes it to blindly space-concatenate its -ArgumentList
(-Args
) arguments without using required embedded double-quoting for arguments with spaces when forming the single string encoding all arguments that is passed to the target executable behind the scenes.
- See GitHub issue #5576, which also discusses that a fix will require a new parameter so as not to break backward compatibility.
For that reason, the required embedded double-quoting must be performed manually as shown in Joel's answer.
When passing multiple arguments, it is ultimately easier to pass a single string to -ArgumentList
with embedded double-quoting as necessary - essentially by formulating a string similar to how you would pass multiple arguments from cmd.exe
:
E.g., if you were to pass two file paths with spaces to Notepad++ at once, you would do:
Start-Process -Wait -FilePath $npp -ArgumentList "`"C:\bad boys\file1.txt`" `"C:\bad boys\file2.txt`""
Also note the overall simplification of the Start-Process
call:
Use of
-Wait
to ensure synchronous execution (waiting for Notepad++ to exit before continuing).- It looks like this is what you tried to do by combining
-PassThru
with piping toOut-Null
, but that doesn't actually work, because that only waits forStart-Process
itself to exit (which itself - unlike the launched process - executes synchronously anyway).
- It looks like this is what you tried to do by combining
The omission of the unnecessary
-NoNewWindow
parameter, which only applies to starting console applications (in order to prevent opening a new console window); Notepad++ is a GUI application.
Note that the only good reason to use Start-Process
here - rather than direct invocation - is the need for synchronous execution: Start-Process -Wait
makes launching GUI applications synchronous (too), whereas with direct invocation only console applications execute synchronously.
If you didn't need to wait for Notepad++ to exit, direct invocation would make your quoting headaches would go away, as the required embedded quoting is then automatically performed behind the scenes:[1]
foreach ($file in $myfiles) {
& $npp $file # OK, even with values with spaces
}
However, the | Out-Null
trick can be used effectively in direct invocation to make calling GUI applications synchronous[2], which leads us to the solution at the top:
foreach ($file in $myfiles) {
& $npp $file | Out-Null # Wait for Notepad++ to exit.
}
[1] However, up to at least PowerShell 7.2.x, other quoting headaches can still arise, namely with empty-string arguments and arguments whose values contain "
chars. - see this answer.
[2] Out-Null
automatically makes PowerShell wait for the process in the previous pipeline segment to exit, so as to ensure that all input can be processed - and it does so irrespective of whether the process is a console-subsystem or GUI-subsystem application. Since GUI applications are normally detached from the calling console and therefore produce no output there, Out-Null
has no ill effects. In the rare event that a GUI application does explicitly attach to the calling console and produce output there, you can use | Write-Output
instead (which also works if there's no output, but is perhaps more confusing).
Solution 2:[2]
Try quotes around the file paths within the string data:
$myfiles = @(
"`"C:\bad boys\file.txt`"",
"`"C:\bad boys\file2.txt`"",
"`"C:\bad boys\file3.txt`""
)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Joel Coehoorn |