VMware Cloud Community
NikunjB
Contributor
Contributor

Checking the ESX Host's connection state in the background

Hi All,

I am trying to check the state of the EX host managed by VCenter server.

I wrote this snippet and I am using 'start-job' powershell cmdlet.

{{{

$backGroundJob = Start-Job -Name "ping" -ScriptBlock {
    while(1)
    {
        $ret = Get-VMHost -Name $esxServer
        if($ret.ConnectionState -ne "Connected")
        {
            Write-Log "ERROR" "The ESX server $esxServer is not reachable..."
            break
        }
        else
        {
            Write-Log "DEBUG" "The ESX server $esxServer is reachable..."
            continue
        }
    }
    }

}}}

Write-Log is auser defined fucntion which will write messages on console and as well as in file.

When I try to run this, I did not get any messages in the file. Which means this does not seem to work. !

Any ideas??

Thanks

Nikunj

0 Kudos
14 Replies
LucD
Leadership
Leadership

PS background jobs run in their own runspace.

Have a look at PowerCLI – Using PowerShell Jobs  to see how this could be done.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

NikunjB
Contributor
Contributor

Hi LucD,

I wrote the folowing function. It is supposed to be looping continuously checking for ESX server's state. But when I do 'get-job', I  get that the job is completed.

{{{

Function checkESXReachability($viServer, $esxServer)
{
    $jobcmd = {
        $in = $input.'<>2__this'.read();
        Add-PSSnapin VMware.VimAutomation.Core -EA silentlycontinue -EV Err;
        Connect-viServer -Server $in[1];
        while(1)
        {
            $ret = Get-VMHost -Name $in[2];
            if($ret.ConnectionState -ne "Connected")
            {
                Write-Log "ERROR" "The ESX server $esxServer is not reachable...";
                break;
            }
            else
            {
                Write-Log "DEBUG" "The ESX server $esxServer is reachable...";
                continue;
            }
        }
        }
    $jobargs = @()
    $jobargs += $jobcmd
    $jobargs += $viServer
    $jobargs += $esxServer
   
    $backGroundJob = Start-Job -Name "ping" -InputObject $jobargs -ScriptBlock $jobargs[0]
}

}}}

Please help me find out the error.

How to make Write-Log function visible to this background job ?

Thanks

Nikunj

0 Kudos
LucD
Leadership
Leadership

Try adding  Start-Transcript and Stop-Transcript cmdlets to your code block.That could perhaps show you what goes wrong.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
NikunjB
Contributor
Contributor

Hi LucD,

Thanks for the inputs.

On the powershell interpreter prompt. I did :

PS C:\> start-transcript -path C:transcripts\transcripts0.txt -noclobber

and then line by line I pasted my code snippet in the interpreter.

Even now, its not showing anything.!

Any pointers ?

Thanks

Nikunj

0 Kudos
LucD
Leadership
Leadership

Are you running this on a XP machine ?

There is a known problem when adding a pssnapin from within a background job.

See Adding a snapin (add-pssnapin) from within a job (start-job) causes job to hang indefinitely


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
NikunjB
Contributor
Contributor

Hi

I am running it on Windows server 2008.

I checked that link. The bug seems to be not present for Windows server 2008.

Any other pointers ?

Thanks

Nikunj

0 Kudos
SimonStrutt
Enthusiast
Enthusiast

I don't think you can write to a transcript file from a background job (or at least I've never managed to do it directly).  You can get the console output from a job by using the Receive-Job cmdlet, so something like this once your job has completed...

Start-Transcript -Path "BackgroundJob.log"
Receive-Job -Id $backGroundJob.Id
Stop-Transcript

I tried to do something similar with background jobs a while back and gave up, it was far simpler to have a PowerCLI script that runs in a continuous loop.

One thing to be aware of is that you can't run PowerCLI jobs on a 64 bit environment, so if you're running on a 64 bit machine, you'll run the x86 version of Powershell and PowerCLI.

"The greatest challenge to any thinker is stating the problem in a way that will allow a solution." - Bertrand Russell
0 Kudos
LucD
Leadership
Leadership

You are right SImon, the ServerRemoteHost engine, which is what runs the background jobs, doesn't support Transcripts Smiley Sad

You can force the 32-bit PS by calling it explictely.

For example the following CMD file calls the PS 32-bit (on a 64-bit machine) and start a script

C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -c "C:\Temp\Test-job.ps1" 

This Test-job.ps1 script looks like this

$job = {
    Add-PSSnapin VMware.VimAutomation.Core -EA silentlycontinue -EV Err
   
Connect-viServer -Server MyVC   
   
$esx = Get-VMHost -Name MyEsx

    $esx.ConnectionState } Start-Transcript "C:\Temp\transcript.txt" $job = Start-Job -Name "Test" -ScriptBlock $job
while
((Get-Job -Id $job.Id).State -eq "running"){     sleep 5
} Receive-Job -Id $job.Id Stop-Transcript


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

NikunjB
Contributor
Contributor

Hi All,

Thanks for the inputs. I will take care of various points with regard to adding snapins in background jobs.

I am trying to 'dot source' few of my scripts which has various functions and variable declarations. I will do that by using 'initializationscript' argument of start-job cmdlet.

1. How do I put multiple 'initializationscript' in 'start-job' commandlet. ? i.e If I have 2 or more scripts for dot sourcing.? I tried with passing an array variable (initarray) but it seems to be not working. it gives me this error.

{

Unexpected token 'initarray' in expression or statement.

}

Here are my commands.

{

PS C:\> $initarray

. C:\scripts\bgtask.PS1
. C:\scripts\logger.PS1

PS C:\> $ret = start-job -scriptblock {checkESXReachability $viserverip $esxserverip } -initializationscript { $initarray[0] $initarray[1] }

}

The function checkESXReachability is defined in file bgtask.PS1. The function also uses 'Write-Log' function which is defined in logger.PS1 file.

2. How do I generate a PSCredential object by using 'connect-viserver'  cmdlet.? I have made connect-viserver to always ask for login credentials at the beginnig of the script. So that once user has given it, I can generate a PSCredential object and then I can pass this object in my background job during the later stages of the script. !

Please help !

Thanks

Nikunj

0 Kudos
LucD
Leadership
Leadership

1) You can have multiple statements in the InitializationScript block. Just put all your dot-source lines in the block

$ret = start-job -scriptblock {checkESXReachability $viserverip  $esxserverip } -initializationscript {

   . C:\scripts\bgtask.PS1
   . C:\scripts\logger.PS1

}

2) You can prompt for the user and password with Read-Host cmdlets at the beginning of the script.

Then use these for all Connect-VIServer lines


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
NikunjB
Contributor
Contributor

Regarding 1)

My bad !! It was easy !

Regarding 2)

If I am using connect-viserver with -savecredential parameter in the first time then now It shouldnt ask me again for credentials for  doing connect-viserver again in the background job right ?

0 Kudos
LucD
Leadership
Leadership

That is correct, if you do your first Connect-VIserver as follows

Connect-VIServer -Server MyVC -Credential (Get-Credential) -SaveCredentials

you can do later on in the script

$cred = Get-VICredentialStoreItem -Server MyVC

Connect-VIServer -Server MyVC -Credential $cred

Just watch out that there aren't multiple entries in the local credential store for that server.

If there are, you could eventually use the User property to filter out the Credential you want


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
NikunjB
Contributor
Contributor

Okay, Thanks.!

Just one more thing. I am not able to use relative paths or full paths taken in a variable, in '-initializationscript' or in '-scriptblock' ?

Ex.

$bg = Start-Job -Name "ping" -scriptblock { C:\scripts\bgtask.PS1 `
    $args[0] $args[1] $args[2] } -ArgumentList @($viserver, $esxserver, $logfile) `
    -initializationscript { . C:\scripts\logger.PS1 ; }

Will work fine, but if I change directory to scripts\ and then run the same..

$bg = Start-Job -Name "ping" -scriptblock { .\bgtask.PS1 `
    $args[0] $args[1] $args[2] } -ArgumentList @($viserver, $esxserver, $logfile) `
    -initializationscript { . .\logger.PS1 ; }

This will not work !.

Even if I take full paths in a variable and then use that variable ( ex. $fulllfilepath = C:\scripts\bgtask.PS1 ) this also wont work.?

0 Kudos
LucD
Leadership
Leadership

The background jobs run in a new PS engine and with a new PS environment.

So the 'Set-Location' you do before you do the Start-Job, this directory will not be reflected inside the background job.

You could do the 'Set-Location'  in the InitializationScript block before you do your dot-source statements.

Did you set the variable $fulllfilepath before the Start-Job ?

If yes, that variable is not known in the new PS engine


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos