Implementing AsJob

-AsJob is a common switch in all the official PowerShell cmdlets that allow them to run in the background. But how do you implement it?

You’ll have to restructure your module a little bit. There’s probably another way in which you don’t have to, but I haven’t figured that out.

Modify the C# module code

For the C# cmdlet module, do this - this is standard template code obtained from the official documentation (see resources below).

protected override void ProcessRecord() //or EndProcessing()
{
  if (AsJob)
  {
    // Add the job definition to the job repository,
    // return the job object, and then create the thread
    // used to run the job.
    JobRepository.Add(job); //the job instance comes later - scroll down to the last step to see how to instantiate it
    WriteObject(job);
    ThreadPool.QueueUserWorkItem(WorkItem);
  }
  else
  {
    //this is to process the 'job' synchronously (i.e. normally)
    job.ProcessJob();
    foreach (PSObject p in job.Output)
    {
      WriteObject(p);
    }
  }
}

Implement the Job class

I went and made my own JobImpl that’s different from the example in the offical docs. You have to make a new file PSJobImpl.cs:

public class PSJobImpl: Job
{
    //this is what will be executed in the background
	Action<PSDataCollection<PSObject>> _logicWithOutput;

	public PSJobImpl(string command, Action<PSDataCollection<PSObject>> logicWOutput) : base(command)
	{
		SetJobState(JobState.NotStarted);
		_logicWithOutput = logicWOutput;
	}
	public override string StatusMessage
	{
		get { return "Status"; }
	}

	public override bool HasMoreData
	{
		get
		{
			return hasMoreData;
		}
	}
	private bool hasMoreData = true;

	public override string Location
	{
		get { return "Location"; }
	}

	public override void StopJob()
	{
		throw new NotImplementedException();
	}

	public void ProcessJob()
	{
		SetJobState(JobState.Running);
		DoProcessLogic();
		SetJobState(JobState.Completed);
	}

	void DoProcessLogic()
	{
		if(_logicWithOutput != null)
		{
			_logicWithOutput(Output);
			Output.Complete();
		}
	}
}

Back to the C# module code

Here is how you instantiate the job that was used in the first step.

protected override void ProcessRecord() //or EndProcessing()
{
	PSJobImpl job = new PSJobImpl("CmdletName", (outputCollection) =>
	{
		//code to actually do stuff goes here
		
		//instead of calling WriteObject, call this:
		outputCollection.Add("[PSObject goes here]");
		//if other methods of your cmdlet need to add to the output collection, use a global variable
		//_outputCollection = outputCollection;
	});

	if (AsJob)
	...
}

References

Official docs: https://docs.microsoft.com/en-us/powershell/developer/cmdlet/how-to-support-jobs

get yourself on the email list

//Powered by MailChimp - low volume, no spam

comments powered by Disqus