0

Can I use Start-Job inside a ScheduledJob at all?

Here's the story: I'm using PowerShell Remoting from inside of my app using .Net classes from System.Management.Automation, Remoting, and Runspaces. I run a script that creates a ScheduledJob on the remote host that does some basic stuff with Hyper-V, let's say, Restart-Vm. The action itself performs as expected, just as though I had run it in the console on this remote host.

Although there is one difference - if I did put it to the console I would get the results of the operation immediately. For example, if the VM is Disabled I would receive 'The operation cannot be performed while the virtual machine is in its current state'. In case with SJs, when some SJ trigger gets activated and the SJ runs, I have no possibility to get the results of my Restart-Vm command immediately after it has been received. Instead, I have to check up on the corresponding BackgroundJob that is created when the SJ gets triggered and check its state and receive its results. It's not OK because my application must write events of this kind to EventLog on the remote machine. Even if the Restart-Vm operation does not succeed no exception gets thrown, and I can't obviously write to the EventLog in the body of my scheduled job.

I thought the solution could be something like this: create a new job inside the scheduled job, make this job perform the target action and bind a handler to the state change event of this job which would write to EventLog.

However, when I implement this

Start-Job -ScriptBlock { params($guid) Get-Vm $guid | Restart-Vm -Force; } -ArgumentList $id;

it fails. Here's how it happens: the SJ gets fired, the corresponding Job is created, I check its state - it is Completed and it HasMoreData. When I do Receive-Job I get this error

Receive-Job : Parameter set cannot be resolved using the specified named parameters.
At line:1 char:8
+ $res | receive-job
+        ~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (System.Manageme...n.PSRemotingJob:PSObject) [Receive-Job], ParameterBindingEx 
   ception
    + FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.PowerShell.Commands.ReceiveJobCommand

I've tried running the Restart-Vm action with -AsJob switch, passing credentials, but nothing works.

UPDATE 5 June, 2015

In fact, this problem has arisen from my need to catch exceptions thrown by Restart-Vm. The fact I did not realize until recently was that I must specify either -ErrorAction Stop or -ErrorVariable parameters when calling Restart-Vm, so that I can get a control over its execution. So there's no need in any hacks like nesting jobs anymore.

Varvara Kalinina
  • 2,043
  • 19
  • 29
  • 2
    How do you obtain `$res`? – Mathias R. Jessen May 28 '15 at 06:42
  • $res is data received from the job initiated by my scheduled job, and it's also a job. Its state is 'Running'. I retrieve it so: $res = Get-Job | Receive-Job. And I make sure there's only one job returned by Get-Job - the one that has just started. – Varvara Kalinina May 28 '15 at 07:56
  • 1
    I don't think you can `Receive-Job` twice – Mathias R. Jessen May 28 '15 at 08:04
  • Hmm, why can I not? These are 2 different jobs, with different IDs and names and states, one is the result of the other which seems alright. Is there any reasonable explanation why it is impossible? I mean I've googled a lot for it and still haven' found any detailed info on this case. – Varvara Kalinina May 28 '15 at 08:19
  • http://stackoverflow.com/a/11973942/712649 – Mathias R. Jessen May 28 '15 at 08:25
  • Please, correct me if I'm wrong but I'm afraid that's not the case. Even if I use -Keep switch it doesn't make any difference because I'm saving the results of Receive-Job cmdlet to the $res variable. The results happen to be another job (not child job). And then I call Receive-Job for that - different - object. – Varvara Kalinina May 28 '15 at 08:32

1 Answers1

2

After executing the statement $res = Get-Job | Receive-Job The value of $res is the output received from the job. That output is not a job that could be fed into Receive-Job again.

Demonstration:

PS C:\> Start-Job -ScriptBlock { 'foo' }

Id  Name  PSJobTypeName  State    HasMoreData  Location   Command
--  ----  -------------  -----    -----------  --------   -------
6   Job6  BackgroundJob  Running  True         localhost  'foo'

PS C:\> $res = Get-Job | Receive-Job
PS C:\> $res
foo
PS C:\> $res | Receive-Job
Receive-Job : 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.
At line:1 char:8
+ $res | Receive-Job
+        ~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (foo:PSObject) [Receive-Job], ...
    + FullyQualifiedErrorId : InputObjectNotBound,Microsoft.PowerShell.Comman...

You need to keep the job object (or its ID) if you want to receive multiple times:

PS C:\> $job = Start-Job -ScriptBlock { 'foo' }
PS C:\> $job | Receive-Job
foo
PS C:\> $job | Receive-Job
PS C:\> Get-Job -Id $job.Id | Receive-Job
PS C:\> _
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328