1

I'm writing a script that should run two python apps and then cycle through solution files, searching for new and updated files with py and json extensions and restarting these apps every time any condition is fulfilled. I hit a wall at the point where I get file names. At this point (line 6), the second ps window just closes instantly even though two different commands should pause it and two more after, it just exits if there is where part on line 6, doing nothing.

$bot = start python .\source\run.py -WorkingDirectory .\bot -WindowStyle Hidden -PassThru # start bot app and save info about it
$web = start python .\source\run.py -WorkingDirectory .\web -WindowStyle Hidden -PassThru # start web app and save info about it
$cycle = start powershell { # start new ps window which will check if any file was changed 
    cmd /c pause # does nothing ???
    Read-Host # does nothing ???
    $fs = dir .\ -recurse | where { $_.extension -in ".py",".json" };
    cmd /c pause # does nothing ???
    Read-Host # does nothing ???
} -PassThru
echo Stop? # indicate script is ready to stop
Read-Host # wait for input before stopping
Stop-Process -Id $bot.Id # stop bot app
Stop-Process -Id $web.Id # stop web app
Stop-Process -Id $cycle.Id # stop second ps window
DeNice
  • 107
  • 10
  • Have you tried `where { $_.extension -in @(".py",".json") };` – Robert Cotterman May 02 '22 at 04:29
  • Another problem could be memory limits? Maybe dir (get child item) is using a lot of memory? I'm not sure how big your folder is. – Robert Cotterman May 02 '22 at 04:33
  • And finally you could try the method instead of piping it. `(dir .\ -recurse).where({ $_.extension -in @('.py','.json') })` – Robert Cotterman May 02 '22 at 04:34
  • I guess one other option to try is -eq and -or ... `dir .\ -recurse | where { $_.extension -eq ".py" -or $_.extension -eq ".json" }` – Robert Cotterman May 02 '22 at 04:36
  • Why not move read-host before the start PowerShell commands? I'm guessing because you're using passthru it might be breaking those commands? I am thinking you're not crashing. But rather finishing the script? And that's why it closes? $fs isn't saved because it's inside the passthru block and not exceeding it's scope? Maybe using global:fs as a variable there? I'm rather confused with the fs part? Unless you have more script you're not sharing. I bet a start sleep 60 would work. I think you need a different pause option for the second window. – Robert Cotterman May 02 '22 at 04:52
  • @RobertCotterman, the only problem was the lack of escaping of the embedded `"` chars. Your suggested variations wouldn't make any difference in PowerShell code, but the second one _would_ solve the problem in a CLI call, because there you're using `'` instead of `"`, but that same solution can be applied to the original filtering command. – mklement0 May 07 '22 at 13:00

1 Answers1

1

Your call to the Windows PowerShell CLI, powershell.exe, implicitly uses the -Command
(-c) parameter
.

In order for embedded " characters in a command string to be recognized as such in a
-Command argument, you must escape them as \"
(sic) - otherwise, they effectively get removed during initial command-line parsing - see the bottom section of this answer for background information.
Alternatively, you could use embedded '...' quoting, which requires no escaping.

  • Since you neglected to perform this escaping, the command became syntactically invalid, resulting in the new PowerShell window auto-closing almost instantaneously (after printing an error).
  • As a general troubleshooting tip, precede the command argument with -NoExit, which keeps the PowerShell session and therefore the window open, which allows you to see what error occurred.

Also, while using a script block literal ({ ... }) is syntactically convenient, it can be be conceptually confusing, given that the positionally implied -ArgumentList (-Args) parameter of the Start-Process (start) you're passing the script block to is [string[]]-typed and therefore invariably converts arguments to strings. Therefore, consider using a (verbatim) here string instead.

To put it all together (note that I'm using PowerShell's built-in pause function for simplicity, which is simply a Read-Host wrapper with the following code: $null = Read-Host 'Press Enter to continue...'):

$bot = start python .\source\run.py -WorkingDirectory .\bot -WindowStyle Hidden -PassThru # start bot app and save info about it
$web = start python .\source\run.py -WorkingDirectory .\web -WindowStyle Hidden -PassThru # start web app and save info about it

# Note how " is escaped as \" 
# Alternatively, use ' (while equivalent here, it isn't always)
$cycle = start -PassThru powershell @'
    pause
    dir .\ -recurse | where { $_.extension -in \".py\", \".json\" }
    pause
'@

Read-Host Stop? # wait for input before stopping
Stop-Process -Id $bot.Id, $web.Id, $cycle.Id

Also note:

  • String Stop? is passed directly to Read-Host (where it implicitly binds to the -Prompt parameter), to make Read-Host itself print that string; however, note that : is invariably appended to the specified string.

  • A single Stop-Process call is sufficient, given that its -Id parameter accepts an array of PIDs (process IDs).

mklement0
  • 382,024
  • 64
  • 607
  • 775