4.6.7. Run and terminate PowerShell process

[Part 1: the following text is based on nppexec/issues/23 by LorneCash]

The problem #1: If you execute a PowerShell's script in NppExec's Console, the PowerShell process is not ended when the script is finished.

The solution #1: Use "cmd /c echo. | powershell" instead of "powershell" to emulate sending of the Enter key to PowerShell process.

The problem #2: PowerShell says: "File ... cannot be loaded because running scripts is disabled on this system".

The solution #2: Either use the command-line option "-ExecutionPolicy Unrestricted" (see the examples below) or set PowerShell's global ExecutionPolicy (see the second part of this article).

The problem #3: If a quoted file path is passed to the second instance of PowerShell, this second instance receives the file path without quotes.

The solution #3: Use escaped quotes \" \" instead of just " ".

Here is an example that illustrates this approach. Also it demonstrates how PowerShell's ExecutionPolicy can be applied to a single script. It is assumed that a .ps1 file is currently opened in Notepad++:

cmd /c echo. | PowerShell -ExecutionPolicy Unrestricted start-process PowerShell -ArgumentList '-ExecutionPolicy Unrestricted -File \"$(FULL_CURRENT_PATH)\"'

And here is an example of PowerShell's command executed in NppExec's Console:

cmd /c echo. | PowerShell -Command Write-Host 'Hello, World!'

Now let's consider the following scenario. When you are debugging PowerShell or batch scripts you usually run them a lot with pauses in them, so you end up with a lot of console windows that have to be closed manually. This can be automated by saving the PID (process id) of the last running process and then using this saved PID to close that process gracefully. Here is the corresponding NppExec's script that runs a PowerShell script file (.ps1) opened in Notepad++:

if "$(PS_ID)" != "" then
  // closing the previous running process by its id...
  cmd /C echo. | PowerShell -Command "get-process -Id $(PS_ID) -ErrorAction SilentlyContinue | ForEach-Object {$null = $_.CloseMainWindow()};"
  unset PS_ID
endif
// running a new process and saving its id...
npe_console local v+ --
cmd /C echo. | PowerShell -ExecutionPolicy Unrestricted -Command "(start-process -PassThru PowerShell -ArgumentList '-File ""$(FULL_CURRENT_PATH)""').Id"
set PS_ID = $(OUTPUT)

In case of a batch script file (.bat or .cmd), the NppExec's script will be slightly different:

if "$(PS_ID)" != "" then
  // closing the previous running process by its id...
  cmd /C echo. | PowerShell -Command "get-process -Id $(PS_ID) -ErrorAction SilentlyContinue | ForEach-Object {$null = $_.CloseMainWindow()};"
  unset PS_ID
endif
// running a new process and saving its id...
npe_console local v+ --
cmd /C echo. | PowerShell -Command "(start-process -PassThru cmd -ArgumentList '/c ""$(FULL_CURRENT_PATH)""').Id"
set PS_ID = $(OUTPUT)

Finally, we can merge these two NppExec's scripts into a new NppExec's script that will take care of both PowerShell and batch script files:

npp_console ?  // don't show the Console if it's hidden
npp_save       // save the current file
if "$(PS_ID)" != "" then
  // closing the previous running process by its id...
  cmd /C echo. | PowerShell -Command "get-process -Id $(PS_ID) -ErrorAction SilentlyContinue | ForEach-Object {$null = $_.CloseMainWindow()};"
  unset PS_ID
endif
// is it a batch file?..
set local IS_BATCH_FILE = false
if "$(EXT_PART)" ~= ".bat" then
  set local IS_BATCH_FILE = true
else if "$(EXT_PART)" ~= ".cmd" then
  set local IS_BATCH_FILE = true
endif
// running a new process and saving its id...
npe_console local v+ --
if "$(IS_BATCH_FILE)" == "true" then
  cmd /C echo. | PowerShell -Command "(start-process -PassThru cmd -ArgumentList '/c ""$(FULL_CURRENT_PATH)""').Id"
  set PS_ID = $(OUTPUT)
else if "$(EXT_PART)" ~= ".ps1" then
  cmd /C echo. | PowerShell -ExecutionPolicy Unrestricted -Command "(start-process -PassThru PowerShell -ArgumentList '-File ""$(FULL_CURRENT_PATH)""').Id"
  set PS_ID = $(OUTPUT)
else
  messagebox "File type has not been configured in NppExec's 'Run' script" : "NppExec: Run - Unknown File Type" : warn
endif
 

[Part 2: the text below was originally posted in NppExec's forum]

The problem: if you execute a PowerShell's script in NppExec's Console, the PowerShell process is not ended when the script is finished.

The solution: use "cmd /c echo. | powershell" instead of "powershell" to emulate sending of the Enter key to PowerShell process.

Here is an example of the full NppExec's script that uses the currently selected text as a PowerShell's program:

// path to PowerShell.exe
set local PS_EXE = C:\WINDOWS\system32\windowspowershell\v1.0\powershell.exe
// temporary file
set local TEMP_FILE = $(SYS.TEMP)\ps_sel.ps1
// save selected text from current file to a temporary ANSI file
SEL_SAVETO $(TEMP_FILE) :a
// execute the temporary file in PowerShell and exit
cmd /c echo. | "$(PS_EXE)" -nologo "$(TEMP_FILE)"

Note:

If PowerShell unexpectedly says something like

File "test.ps1" cannot be loaded because running scripts is disabled on this system

it could be related to the fact that there are 32-bit and 64-bit instances on 64-bit systems, and they can have different settings. According to https://stackoverflow.com/questions/4037939/powershell-says-execution-of-scripts-is-disabled-on-this-system , the following should help:

x86 (32 bit)
Open "C:\Windows\SysWOW64\cmd.exe"
Run the command: "powershell Set-ExecutionPolicy RemoteSigned"

x64 (64 bit)
Open "C:\Windows\system32\cmd.exe"
Run the command: "powershell Set-ExecutionPolicy RemoteSigned"

You can check the bitness using
- In CMD: echo %PROCESSOR_ARCHITECTURE%
- In Powershell: [Environment]::Is64BitProcess

See also: Using cmd.exe [4.4].