2

I am writing a powershell script that is running on Linux. The purpose of this script is to run the MS SQL Server and show its output, but when the user presses Ctrl+C or some error happens, the script takes a copy of the data folder and then after that exits.

[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!"
}

I got a couple of problems with this script:

  • When I press Ctrl+C it breaks the main script and it never reaches to the Create-Backup section at the bottom of the script.
  • If I remove -Wait then the script won't show the sql log output

So my prefered solution is to run the sql with -Wait parameter and prevent the powershell to exit the code after I press Ctrl+C, but instead Ctrl+C close the sql instance

So I'm looking for a way to achieve both.

stackprotector
  • 10,498
  • 4
  • 35
  • 64
Mohammad Hossein Amri
  • 1,842
  • 2
  • 23
  • 43
  • 1
    You could use `Start-Process` without the `-NoNewWindow` parameter, use `-RedirectStandardOutput` to write its output to a temporary file and evaluate or print the content of the file after `Start-Process` finished. – stackprotector May 13 '20 at 19:21
  • @Thomas in that case the problem would be the file size, the sql generates tons of log to the output. also I should write and also tail the output at same time. it's too much of I/O for a small sql server – Mohammad Hossein Amri May 13 '20 at 19:30

1 Answers1

1

For simplicity I'll assume that your function only needs to support a single input object, so I'm using a simple function body without begin, process and end blocks, which is equivalent to having just an end block:

[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!"

    }

If you really need to support multiple input objects, it gets more complicated.

mklement0
  • 382,024
  • 64
  • 607
  • 775