Как остановить дочерний процесс с помощью Ctrl + C, не нарушая основной скрипт, и передать дочерний процесс в основной скрипт в PowerShell?

Я пишу сценарий PowerShell, работающий в Linux. Цель этого сценария - запустить MS SQL Server и показать его вывод, но когда пользователь нажимает Ctrl + C или происходит некоторая ошибка, сценарий принимает копию папку данных, а затем после этого закрывается.

[CmdletBinding()]
PARAM (
    [Parameter(ValueFromPipelineByPropertyName)]
    [string] $Command,

    [Parameter(ValueFromPipelineByPropertyName)]
    [string] $Args
)
BEGIN {
    Write-Output "started $PSScriptRoot"
    $currentErrorLevel = $ErrorActionPreference
    # [console]::TreatControlCAsInput = $true
}
PROCESS {

    try {
        $ErrorActionPreference = 'SilentlyContinue';
        $IsSqlRunning = Get-Process -name "sqlservr";

        if ($null -eq $IsSqlRunning) {
            start-process "/opt/mssql/bin/sqlservr" -wait -NoNewWindow
        }
    }
    catch {
        $ErrorActionPreference = $currentErrorLevel;
        Write-Error $_.Exception
    }

}
End {
    $ErrorActionPreference = $currentErrorLevel;
    #do backup
    Create-Backup "/opt/mssql/bin/data"
    Write-Output "finishd!"
}

У меня возникла пара проблем с этим скриптом:

  • Когда я нажимаю Ctrl + C, он прерывает основной скрипт и никогда не достигает раздела Create-Backup внизу скрипта.
  • Если я удалю -Wait, скрипт не будет отображать вывод журнала sql

Поэтому мое предпочтительное решение - запустить sql с параметром -Wait и предотвратить выход PowerShell из кода после того, как я нажму Ctrl + C, но вместо этого Ctrl + C закрыть экземпляр sql

Так что я ищу способ добиться и того, и другого.


person Mohammad Hossein Amri    schedule 13.05.2020    source источник
comment
Вы можете использовать Start-Process без параметра -NoNewWindow, использовать -RedirectStandardOutput для записи вывода во временный файл и оценки или печати содержимого файла после Start-Process завершения.   -  person stackprotector    schedule 13.05.2020
comment
@Thomas в этом случае проблема будет в размере файла, sql генерирует тонны журнала для вывода. также я должен писать и одновременно отслеживать вывод. это слишком много ввода-вывода для небольшого сервера sql   -  person Mohammad Hossein Amri    schedule 13.05.2020


Ответы (1)


Для простоты я предполагаю, что ваша функция должна поддерживать только единственный входной объект, поэтому я использую простое тело функции без блоков begin, process и end, что эквивалентно наличию просто блок end:

[CmdletBinding()]
PARAM (
    [Parameter(ValueFromPipelineByPropertyName)]
    [string] $Command,

    [Parameter(ValueFromPipelineByPropertyName)]
    [string] $Args
)
    Write-Output "started $PSScriptRoot"

    # No need to save the current value, because the modified
    # value is local to the function and goes out of scope on 
    # exiting the function.
    $ErrorActionPreference = 'SilentlyContinue';

    try {
        $IsSqlRunning = Get-Process -name "sqlservr";

        if ($null -eq $IsSqlRunning) {
            start-process "/opt/mssql/bin/sqlservr" -wait -NoNewWindow
        }
    }
    catch {
        Write-Error $_.Exception
    }
    finally {

      # This block is *always* called - even if Ctrl-C was used.

      Create-Backup "/opt/mssql/bin/data"
      # CAVEAT: If Ctrl-C was used to terminate the run, 
      #         you can no longer produce *pipeline* input at this point
      #         (it will be quietly ignored).
      #         However, you can still output to the *host*.
      Write-Host "finished!"

    }

Если вам действительно нужно поддерживать несколько объектов ввода, все становится сложнее.

person mklement0    schedule 14.05.2020
comment
Рад это слышать, @MoHradA; Не за что. - person mklement0; 01.06.2020