How to get the status of the service inside docker using powershell - powershell

I want to fetch the status of service inside docker container using powershell
$fetchService = docker exec -ti 33 powershell -c "get-service servicename"
If ($fetchService.Status -eq 'Running') {
Write-Host "True"
}
Else{
Write-Host $fetchService.Name
Write-Host "False"
}
Actual result is False but expected is true, also object fetch service is not avaliable in log.

You will have to check what $fetchService ultimately contains. Whenever it's a string, an array of strings or something else. If it is a single string you could use -like or -match which support multiple options. One of them is a regular expression. It all depends on your input as to how it has to look.
Check about_comparison_operators and about_regular_expressions. It should give you an idea.

Related

How can I tell if Docker Desktop is running in a Powershell script?

I have a Powershell script in which I need to know if Docker Desktop is currently running.
I have read that one way to do it is to use docker ps and see if I get back a container list or an error message. But I'm struggling to make use of this in an actual script. I haven't worked out how to capture and act on the result correctly.
Here's what I have so far:
function IsDockerDesktopRunning()
{
$dockerPsResult = docker ps | Out-String
Write-Host "Result is:"
Write-Host $dockerPsResult
if (($dockerPsResult).StartsWith("error"))
{
return $false
}
return $true
}
$isRunning = IsDockerDesktopRunning
Write-Host $isRunning
When when it's not running, the result looks like this:
error during connect: This error may indicate that the docker daemon is not running.: Get "http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.24/containers/json": open //./pipe/docker_engine: The system cannot find the file specified.
Result is:
True
As you can see, it looks the output from the docker ps command gets output as it's executed and the variable isn't populated.
Is there a way to correctly capture the output?
Or, should I tackle the problem a different way?
To capture the error output as well, redirect stderr to stdout like this.
$docker = docker ps 2>&1
You can use this to determine if docker desktop is running.
if((docker ps 2>&1) -match '^(?!error)'){
Write-Host "Docker is running"
}
Since it doesn't seem possible to capture the error message in a variable, I've decided to switch the logic around and rely on the variable being empty.
function IsDockerDesktopRunning()
{
$dockerPsResult = docker ps
if ($dockerPsResult)
{
return $true
}
return $false
}
$isRunning = IsDockerDesktopRunning
Write-Host $isRunning
The unfortunate side effect is that the error message is still printed to the screen and makes things look a bit messy. But the logic works, so I'll live with it.
EDIT: Since adding this not so great answer, Doug has updated his answer, which is now correct. Thanks Doug.

Using PowerShell to identify a machine as a server or PC

I'm trying to write a PowerShell script that will give me a list if of roles and features if run on a server but if run on a client machine will say "Only able to execute command on a server."
I've played around with this script a lot and can get it to run on either a client machine or server (depending on what I've tweaked) but not both. Here's the latest iteration:
$MyOS="wmic os get Caption"
if("$MyOS -contains *Server*") {
Get-WindowsFeature | Where-Object {$_. installstate -eq "installed"
}}else{
echo "Only able to execute command on a server."}
What am I doing wrong?
The quotes around your wmic command will create the $MyOS variable with a String and not execute the command. Still, I would recommend you use native PowerShell commands such as Get-CimInstance. Like the $MyOS variable your if statement condition will always equal true as the quotes will make it a String.
$MyOS = Get-CimInstance Win32_OperatingSystem
if ($MyOS.Caption -like "*Server*") {
Get-WindowsFeature | Where-Object { $_. installstate -eq "installed" }
}
else {
Write-Output "Only able to execute command on a server."
}
You can also use the ProductType property. This is a (UInt32) number with the following values:
1 - Work Station
2 - Domain Controller
3 - Server
$MyOS = (Get-CimInstance Win32_OperatingSystem).ProductType
if ($MyOS -gt 1) {
Get-WindowsFeature | Where-Object { $_. InstallState -eq "installed" }
}
else {
Write-Output "Only able to execute command on a server."
}
Try to use '-like' instead of 'contains', it should work
Generally, I try to avoid pre-checks like this that make assumptions about functionality that may not be true forever. There's no guarantee that Get-WindowsFeature won't start working on client OSes in a future update.
I prefer to just trap errors and proceed accordingly. Unfortunately, this particular command produces a generic Exception rather than a more specifically typed exception. So you can't really do much other than string matching on the error message to verify specifically what happened. But there's very little that can go wrong with this command other than the client OS error. So it's pretty safe to just assume what went wrong if it throws the exception.
try {
Get-WindowsFeature | Where-Object { $_. InstallState -eq "installed" }
} catch {
Write-Warning "Only able to execute command on a server."
}
If you don't want to accidentally hide an error that's not the client OS one, change the warning message to just use the actual text from the error. This also gets you free localization if you happen to be running this code in a location with a different language than your own.
Write-Warning $_.Exception.Message

How to fix: Starting services stored in variables

I'm currently trying to make a script which does the following:
Get the services which are running
Get all services with startup type automatic, which arent running
Start all services which aren't running, but got startup type automatic.
The script will be run on different windows servers. I already tried to compare the services which should run ($servicestorun), to the one actually running ($servicesrunning), and then start the ones who aren't running but should.
Can someone here point me to the right direction or provide me with code needed to fix it?
$servicesrunning = Get-Service | Where {
$_.StartUpType –eq 'automatic' -and $_.Status –eq 'running'
} # gets running services
$servicestorun = Get-Service | Where {
$_.StartUpType –eq 'automatic' -and
$_.Status –eq 'stopped'
} # gets services with startup type automatic and status stopped
# checks if all services which should run, actually run
if ($servicestorun -eq $servicesrunning) {
echo "all good" # if positive, message all good then exit
exit
} else {
Start-Service $servicestorun # starts all services with startup type automatic and status stopped
}
And the error I'm getting:
Start-Service : Das Argument für den Parameter "InputObject" kann nicht überprüft werden.
Your comparison will always evaluate to "false" for 2 reasons:
PowerShell arrays are objects, and the -eq operator tests for identity of the objects, not if both array objects contain the same elements.
The two lists you're comparing are mutually exclusive, so even if you could compare the arrays using the -eq operator (which, again, you can't) the result would still be "false".
Because of that your code will always jump to the else branch, even if there are no services to start. In that situation you'll pass an empty variable to Start-Service, which results in the error you observed.
Since you want to start all services that are configured for automatic start, but aren't currently running, simply use the pipeline:
Get-Service | Where-Object {
$_.StartUpType –eq 'automatic' -and
$_.Status –ne 'running'
} | Start-Service

Execute a different command depending on the output of the previous

I am trying out something which is quite simple, yet I can't find an answer or rather can't figure out how to ask the question on Google.
So I thought it would be better to just show what I'm doing with pictures, here.
Here is the script I'm working on:
What it does is simple: get all virtual machines depending on their state (running, saved or off) and then starting them or stopping them. That is where I am having trouble.
I tried to pipe it with different commands, but it keeps giving an error which is
The input object cannot be bound to any parameters for the command either
because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
So what I want is if the machine are running then save them. Is there a way to do so?
Use a ForEach-Object loop and a switch statement:
Get-VM -VMName $name | ForEach-Object {
switch ($_.State) {
'running' {
# do some
}
'saved' {
# do other
}
'off' {
# do something else
}
default {
throw ('Unrecognized state: {0}' -f $_.State)
}
}
}
I think the actual issue here (shown by the error message) is that start-vm doesn't accept pipeline input. I'm guessing this is the Hyper-V Start-VM cmdlet, by the way.
You could do this to get around the lack of pipeline-aware parameters:
Get-VM -VMName $name | where {$_.State -eq $state} | foreach-object {Start-VM -VM $_}

Detect if process executes inside a Windows Container

It's simple.
I would like to detect with code if my process is running inside a windows container. There are examples but they are all for linux based containers.
I'm looking for something unique and explicit to docker that can be used to make a safe conclusion whether a process is executing inside a container hosted windows operating system and not otherwise.
My preferred language is PowerShell but if someone points out the how to detect, I'll port it to PowerShell.
New readers can skip ahead to the part marked with "Update" which contains the accepted solution.
A quick check with whoami on the command prompt showed that the combination of domain and username that is used inside a container seems to be rather unusual. So I used this code to solve the problem:
function Test-IsInsideContainer {
if( ($env:UserName -eq "ContainerAdministrator") -and ($env:UserDomain -eq "User Manager") ) {
$true
}
else {
$false
}
}
Update: Another option is to check if the service cexecsvc exist. An internet search did not yield much information about this service, but its name (Container Execution Agent) suggests that it only exists inside of containers (which I verified with some quick test on Win10 and a Server2016 Docker-host).
So maybe this code meets your requirements (I am a newbie in Powershell):
function Test-IsInsideContainer {
$foundService = Get-Service -Name cexecsvc -ErrorAction SilentlyContinue
if( $foundService -eq $null ) {
$false
}
else {
$true
}
}
There's a "ContainerType" registry value under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control.
So:
function Test-IsInsideContainer {
$containerType = (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control").ContainerType
$containerType -ne $null
}
Will below work?
PS C:\> (Get-NetAdapter).Name -match "container"
True
As of Docker 17.06 onward you could use the DNS entry docker.for.mac.localhost and docker.for.mac.localhost to determine if the container runs on a mac or windows host. if none of these host names can be pinged you might safely assume its a linux host. This will probably not work for Swarms.
I am not an expert in Bash but an example could look like this.
#!/bin/bash
ping -c 1 docker.for.mac.localhost &>/dev/null
if [ $? -eq 0 ]; then
echo "Mac Host"
fi
ping -c 1 docker.for.win.localhost &>/dev/null
if [ $? -eq 0 ]; then
echo "Windows Host"
fi;
I hope this helps you writing the script in PowerShell and please do share for whenever I need something like this in Windows.