How to write a script to start a Docker container and stop WSL safely when the container stops?

Copper Contributor

I’m writing a PowerShell script to start a container and stop WSL safely when the container stops. Here is my attempt:

$ContainerName = 'tranky'
$DockerDesktopPath = "C:\Program Files\Docker\Docker\Docker Desktop.exe"

Start-Process $DockerDesktopPath
$id = (Get-Process 'Docker Desktop').id
Wait-Process -id $id

docker start $ContainerName
docker wait $ContainerName

$IsContainerRunning = docker container inspect -f '{{.State.Running}}' $ContainerName
$IsDockerDesktopRunning = Get-Process "Docker Desktop" -ErrorAction SilentlyContinue

while ($IsContainerRunning -eq $true) {
    Start-Sleep -Seconds 5
    $IsContainerRunning = docker container inspect -f '{{.State.Running}}' $ContainerName
}

if ($IsDockerDesktopRunning && $IsContainerRunning) {
    $IsDockerDesktopRunning.CloseMainWindow()
    $IsDockerDesktopRunning | Stop-Process -Force
}

wsl --shutdown

Currently, I’m stuck at this part:

Start-Process $DockerDesktopPath
$id = (Get-Process 'Docker Desktop').id
Wait-Process -id $id

If I don’t wait for the process to finish, then I can’t call docker start. However, if I do that, then it won’t finish even though Docker Desktop has already popped up and is doing nothing. I also want to have the log of the container to be displayed in the host’s terminal. Any suggestion?

9 Replies

@ooker 

 

I don't know anything about Docker, but I can try and help with your first question (though not the second question about logging).

 

When you say that docker start fails, what does that look like? Is it just that nothing happens, or do you get a detailed error message?

 

If you put a large delay after the Start-Process (i.e. Start-Sleep -Seconds 20) and before the docker start, does the the docker start work then?

 

Do you know if the Docker desktop process spawns any child processes you can monitor for?

 

Knowing some of this may help us help you with the first question.

 

Cheers,

Lain

well, technically I can use sleep, but to learn more about scripting, is there a way to detect it when an event from a program happens? Say I open Word, is there a way to trigger a script when it finishes the startup?

@ooker 

 

There's no single, generic way to know that.

 

At best, there might be a way that's specific to the exact application/service you're working with, but for another application/service, it might require a completely different approach - or there may be no way at all. It's not like Windows prescribes a standard that client processes have to confirm to/integrate with.

 

Take Docker, for example. If the "Docker Desktop" you're launching were to in turn launch (or stop) child processes of its own, then you could leverage that behaviour. But let's say it doesn't, then you may have no visibility into how it's going with its start-up routine at which point all you can do is wait an arbitrary interval (or variations of that such as polling, but this isn't always materially any better).

 

Cheers,

Lain

I see. So if an app wants to implement this, what would be the way for it to do so? What teens should I look for?

@ooker 

 

I don't quite understand the question. What are teens? (Excluding rambunctious kids.)

 

Cheers,

Lain

oh it's autocorrect :xd:. I was asking "what terms should I look for?"

@ooker 

 

I can't tell you what to look for with Docker, as I don't use it.

 

The best I can do is provide you with a hypothetical example for a scenario where the first program you start with Start-Process (in your case, this is Docker Desktop) then starts another child process of its own, indicating it's operational.

 

Because I don't use Docker, I have to use other programs in the example. Here's a table that translates what I'm using for illustrative purposes to what you would use.

 

StageMy exampleYour scenario
Start-Processcmd.exeDocker Desktop
Child processnotepad.exe<something Docker launches>

 

Example

# Launch the "main" process.
$Process = Start-Process -FilePath "cmd.exe" -PassThru -ErrorAction:Stop;

# Monitor for a specific child process being launched by the main process.
$CheckAgain = $true;
$Retries = 10;

while ($CheckAgain -and ($Retries -gt 0))
{
    if (Get-CimInstance -ClassName "Win32_Process" -Filter "ParentProcessID=$($Process.Id) AND Name='notepad.exe'")
    {
        $CheckAgain = $false;
    }
    else
    {
        $Retries--;
        Start-Sleep -Seconds 2;
    }
}

 

Here, we're checking for a maximum of 20 seconds ([10 retries] x [two second sleep] to see if the child process has started. If it starts earlier, then the loop will exit earlier.

 

But again, this is hypothetical and may not be useful for your Docker scenario at all. You'd have to do some investigating to see how Docker behaves before you can solve your challenge.

 

Cheers,

Lain

Actually I was broadening my topic and not talking about Docker specifically. Like, if I'm writing a program and want to register my program's events to the OS so that users can take it from there, what should I do? Only signalling via child process seems limited to me. I guess the only way to communicate with the OS is to pack all the information in the process title. I see that the Task Scheduler is something in the right way.

 

ooker_0-1694159099016.png

 

 

@ooker 

 

Okay, so setting Docker aside, there's no mandated standard.

 

The closest thing to a standard would be making use of the Windows event logs, where your application would write key events to either the Application log (most common as it's the oldest and therefore the most well-known log) or the Application and Services Logs node (newer, uses and different implementation and isn't widely used by vendors outside of Microsoft - though it is growing.)

 

Ultimately it's entirely up to the developer how they wish to inform of key events - or even to not inform at all. Again, there is no mandated standard for this.

 

But this is a discussion for another forum as it is entirely unrelated to PowerShell.

 

Cheers,

Lain