Modules/businessdev.ALbuild.Containers/Private/Wait-BcServiceStatus.ps1

function Wait-BcServiceStatus {
    <#
    .SYNOPSIS
        Waits for a Windows service to reach a status, by polling.
 
    .DESCRIPTION
        Polling Get-Service rather than calling ServiceController.WaitForStatus, for two reasons. It
        reports a timeout as a return value instead of an exception, so the caller decides what a
        timeout means - here it means "roll back", not "crash". And it goes through a cmdlet, which a
        test can mock; WaitForStatus is a method on a live ServiceController and cannot be stood in for.
 
    .PARAMETER Name
        The service name.
 
    .PARAMETER Status
        The status to wait for.
 
    .PARAMETER TimeoutSeconds
        How long to keep polling. Default 180.
 
    .PARAMETER IntervalSeconds
        Delay between polls. Default 2.
 
    .OUTPUTS
        System.Boolean - $true once the status was seen, $false if the timeout expired.
    #>

    [CmdletBinding()]
    [OutputType([bool])]
    param(
        [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Name,
        [Parameter(Mandatory)] [ValidateSet('Running', 'Stopped', 'Paused')] [string] $Status,
        [ValidateRange(1, 3600)] [int] $TimeoutSeconds = 180,
        [ValidateRange(1, 60)] [int] $IntervalSeconds = 2
    )

    $deadline = (Get-Date).AddSeconds($TimeoutSeconds)
    while ($true) {
        $svc = Get-Service -Name $Name -ErrorAction SilentlyContinue
        if ($svc -and "$($svc.Status)" -eq $Status) { return $true }
        if ((Get-Date) -ge $deadline) { return $false }
        Write-Verbose "Service '$Name' is '$(if ($svc) { $svc.Status } else { 'absent' })', waiting for '$Status'."
        Start-Sleep -Seconds $IntervalSeconds
    }
}