Detect if process executes inside a Windows Container - powershell

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.

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.

How to get the status of the service inside docker using 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.

How can start a service from PowerShell and pass start parameters to it?

I'm trying to start a service from PowerShell with start parameters similar to: -l "192.168.10.10".
Following the advice in this answer hasn't helped.
Here's my code:
#start service
$slave = Get-Service -Name "My Service"
if ($slave.status -eq "Stopped") {
$ip = Get-NetIPAddress -InterfaceAlias myInterface -AddressFamily IPv4
$args = #('-l ', "`"$($ip.IPAddress)`"")
echo $args
$slave.Start($args) # doesn't work
} else {
echo "My service is already running"
}
run results below, no useful error messages I'm afraid:
-l
"192.168.10.10"
I have verified that the service starts ok if I give it the parameters manually in service manager. It takes a couple of seconds.
I found a fix. It's quite subtle so worth sharing.
The service I was starting didn't like the trailing space after the -l.
$args = #('-l', $ip.IPAddress) # works great!

PowerShell Script to pop up at logoff

I have a basic understanding of PowerShell.
I would like to get my hands on a PowerShell script that will run at logoff.
This script needs to warn a user that their USB storage device is still plugged in before they sign out and they have to acknowledge the fact that it is and then select ok and then proceed to sign out
I know that the script needs to placed in an accessible location with the correct permissions and that a GPO can be used to enforce this. The script part is what I need help with..
If anyone out there in the interwebs please help?
Environment OS: Windows 10
AD not in use. Novell system used.
After you checked out what Franco stated, you can try something like the following. But still need to figure out how to make it work properly:
$usbs = GET-WMIOBJECT win32_diskdrive | Where { $_.InterfaceType –eq ‘USB’ }
$devices = #()
foreach($usb in $usbs){
$devices += $usb.Model + ". "
}
$input = [System.Windows.MessageBox]::Show("There are USB devices connected, $($devices | Out-String) Would you like to proceed logging off?","Warning","YesNoCancel","Error")
if($input -eq "Yes"){
shutdown -L
}elseif($input -eq "No"){
shutdown -A
}else{
break
}
You will need to find a way to make the user input visible before the logoff screen.

Determining when machine is in good state for Powershell Remoting?

Update - the original question claimed that I was able to successfully perform an Invoke-Command and then shortly after was unable to; I thought it was due to processes going on during login after a windows upgrade.
It turns out the PC was actually starting, running a quick batch/cmd file, and then restarting. This is what was leading to being able to do PS Remoting and then suddenly not. The restart was quick enough after first boot that I didn't realize it was happening. Sorry for the bad question.
For the curious, the machine was restarting because of a remnant of the Microsoft Deployment Toolkit in-place upgrade process. The way MDT completes its task-sequence post-upgrade is problematic for many reasons, and now I've got another to count.
Old details (no longer relevant, with incorrect assumption that machine was not restarting after first successful Invoke-Command):
I'm automating various things with VMs in Hyper-V using powershell and powershell remoting. I'll start up a VM and then want to run some commands on it via powershell.
I'm struggling with determining when I can safely start running the remote commands via things like Invoke-Command. I can't start immediately as I need to let the machine start up.
Right now I poll the VM with a one second sleep between calls until the following function returns $true:
function VMIsReady {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True)][object]$VM
)
$heartbeat = $vm.Heartbeat
Write-Host "vm heartbeat is $heartbeat"
if (($heartbeat -eq 'OkApplicationsHealthy') -or ($heartbeat -eq 'OkApplicationsUnknown'))
{
try
{
Invoke-Command -VMName $vm.Name -Credential $(GetVMCredentials) {$env:computername} | out-null
}
catch [System.Management.Automation.RuntimeException]
{
Write-Host 'Caught expected automation runtime exception'
return $false
}
Write-Host 'remoting ready'
return $true
}
}
This usually works well; however, after a windows upgrade has happened, there are issues. I'll get Hyper-V remoting errors of various sorts even after VMIsReady returns $true.
These errors are happening while the VM is in the process of first user login after upgrade (Windows going through "Hi;We've got some updates for your PC;This might take several minutes-Don't turn off your PC). VMIsReady returns true right as this sequence starts - I imagine I probably should be waiting until the sequence is done, but I've no idea how to know when that is.
Is there a better way of determining when the machine is in a state where I can expect remoting to work without issue? Perhaps a way to tell when a user is fully logged on?
You can use Test-WSMan.
Of run a script on the invoke that will receive a response from the server.
[bool]$Response | Out-Null
try{
$Response = Invoke-Command -ComputerName Test-Computer -ScriptBlock {return $true}
}catch{
return $false
}
if ($Response -ne $true){
return $false
}else{
return $true
}