So let's go onto our PowerShell console,
and we'll look at how we investigate
failed jobs by reviewing the current
status of any jobs and then also examining
the reason of why the job failed. So what
I want to talk about now is retrieving the
status and the reason for a potential
failure of a job. Now, to do this, I first
need to create a job. So let me create a
variable, job = Start‑Job. I'll give it a
name. We'll call it FailedJob so we know
what we're looking at. And then in the
ScriptBlock here, I'm going to do
something weird. I'm basically just going
to say New‑Item, so Path, I'm going to use
a drive that doesn't exist, so that's
going to cause me a failure, name 'Failed'
‑ItemType Directory, and I'll set the
ErrorAction to just Stop. So I'm using two
bits of PowerShell here, one is to start
the job, the second is to try and create a
new items, such as a directory, in a drive
that doesn't exist, and then my
ErrorAction is to just Stop. So I'm going
to kick that off, and then I'm going to
click on my job here, and you'll see that
my background job failed, so we have a
specific FailedJob. Now, we can retrieve
the details about the job. We can also
retrieve the child jobs that initiated. So
you can see here, we've got the FailedJob
and then the job that was kicked off as
part of that process. We can also then get
the j+ob state, so I can say
ChildJobState. And notice, when it comes
back, you can't retrieve the specific
value because you actually have to pass
what it is you're looking for, which is
failed, or completed, or something else.
So just be aware, sometimes when you add
the properties, like IncludeChildJob
doesn't require a value, but ChildJobState
does, so I can retrieve basic information.
Now, what I can also do is obviously
receive the job kind of details of what
took place. So let me just create a
variable called error, and what I'll do is
we'll say, Receive‑Job, and I'm going to
call it job, and it'll come back and say,
New‑Item: Cannot find the drive. A drive
with the name Z does not exist. So we have
our standard message kind of response
back, so I can at least retrieve.
Remember, the Receive‑Job is all about
getting the values that would come back if
the job was successful. Now, what's
interesting here is that once we have
retrieved the job, then, of course, there
are other bits of information that are
available to us. So we have the error. So
if I say error and just do Enter, what it
does, as you can see, there's a whole
bunch of stuff that kind of comes back and
it says, Cannot override variable Error.
It's read‑only, comes back with the Z
error, then something else, something
else, and basically spits out a whole
bunch of information around not being able
to get information back from the specific
job. Now, what we can do is there are,
remember the child jobs option, so, for
example, if I say Get‑Job, it gives me the
list of jobs, and I can say
IncludeChildJobs, it gives me the list of
the jobs that are there. So if I want to
say Get‑Job ‑ID 16, for example, it's
going to come back with that job itself.
Now, what we can do with the child jobs is
actually go in and retrieve the values of
why the job failed, or at least from the
main job too. So if we just go back to
Get‑Job, job is 15 is my unique ID, so I'm
going to say, Get‑Job ‑ID 15, and I'm
going to do a Select statement here, and
I'm going to expand the property called
JobStateInfo. Now, JobStateInfo is a kind
of container field that contains State and
Reason. So what I could do at this point
is I could then nest it back down again
and say Select State, and that would give
me the Failed value. If I had a Reason
value, then I could also get the Reason
value, which at this point is actually
empty. So you can be aware that we can
retrieve information around that specific
type of message that's there. Now, what we
can also do is if I just create a new
variable called joberror, and I'm going to
say, well, my job, or my error job, or at
least, I think it was in lowercase, that
was my job, I can say ChildJobs and then
obviously pick a 0. What we could also do
is if I just create a new variable, and
we're going to populate it with the job
itself, if I actually say ChildJobs and
pick the first one, I can also get the
JobStateInfo. So joberror, and you'll see
it gives me this kind of state, and now I
get a value in the Reason field as well.
So what that means is that I can actually
say JobStateInfo.Reason.Message. And now
when I go to joberror, I get Cannot find a
drive. A drive with the name Z does not
exist. So there are a couple different
ways of retrieving the same information.
The first one, obviously, is to receive
the job, which will give you the results
back, which may or may not give you the
actual error. The second option is to,
obviously, just go and retrieve and use
the Select statement to expand the
property of Job State info, and then
you'll get State and Reason. But if Reason
is empty, then actually, what you'll need
to do is go and do it this way, which is
get the job, the child job, by the unique
Identify here and then go and get the
JobStateInfo, and then you'll get the
reason and the message. So a simple way of
being able to identify the reason why a
specific job failed. Now, of course, we
also have the ability, so if I just get
rid of my job here and just say,
job.ChildJobs and then just do Error, I
can do that same thing. So if there's an
Error on that first job, I get the
message. If I do a second one or a third
one, depending on the unique identifier, I
might get that message back also. So just
a couple of different ways of being able to retrieve that information.