2025-11-28 00:35:46 +09:00

554 lines
16 KiB
C#

// <copyright file="JobSourceAdapterSample.cs" company="Microsoft Corporation">
// Copyright (c) 2012 Microsoft Corporation. All rights reserved.
// </copyright>
// DISCLAIMER OF WARRANTY: The software is licensed “as-is.” You
// bear the risk of using it. Microsoft gives no express warranties,
// guarantees or conditions. You may have additional consumer rights
// under your local laws which this agreement cannot change. To the extent
// permitted under your local laws, Microsoft excludes the implied warranties
// of merchantability, fitness for a particular purpose and non-infringement.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.IO;
using System.Threading;
namespace JobSourceAdapterSample
{
/// <summary>
/// Simple cmdlet to create a FileCopyJob.
/// </summary>
[Cmdlet(VerbsCommon.Get, "FileCopyJob")]
[OutputType(typeof(Job2))]
public sealed class StartFileCopyJobCommand : PSCmdlet
{
#region Parameters
[Parameter(Position = 0, Mandatory = true)]
[ValidateNotNullOrEmpty]
public string Name { get; set; }
[Parameter(Position = 1, Mandatory = true)]
[ValidateNotNullOrEmpty]
public string SourcePath { get; set; }
[Parameter(Position = 2, Mandatory = true)]
[ValidateNotNullOrEmpty]
public string DestinationPath { get; set; }
#endregion
#region Overrides
protected override void ProcessRecord()
{
// Get full path to source.
ProviderInfo provider;
string fullSourcePath = GetResolvedProviderPathFromPSPath(SourcePath, out provider).FirstOrDefault();
if (string.IsNullOrEmpty(fullSourcePath))
{
throw new ArgumentException(SourcePath);
}
// Get full path for destination file (which may not exist).
string fullDestPath = null;
string destFile = Path.GetFileName(DestinationPath);
string path = GetResolvedProviderPathFromPSPath(
Path.GetDirectoryName(DestinationPath), out provider).FirstOrDefault();
if (path != null)
{
fullDestPath = Path.Combine(path, destFile);
}
if (string.IsNullOrEmpty(fullDestPath))
{
throw new ArgumentException(DestinationPath);
}
// Create job source adapter.
FileCopyJobSourceAdapter jobSourceAdapter = new FileCopyJobSourceAdapter();
// Create FileCopyJob parameters (source and destination paths).
Dictionary<string, object> copyJobParameters = new Dictionary<string, object>();
copyJobParameters.Add(FileCopyJobSourceAdapter.SourcePathProperty, fullSourcePath);
copyJobParameters.Add(FileCopyJobSourceAdapter.DestinationPathProperty, fullDestPath);
// Create job specification.
JobInvocationInfo copyJobSpecification = new JobInvocationInfo(
new JobDefinition(typeof(FileCopyJobSourceAdapter), string.Empty, Name),
copyJobParameters);
copyJobSpecification.Name = Name;
// Create file copy job from job source adapter and start it.
Job2 fileCopyJob = jobSourceAdapter.NewJob(copyJobSpecification);
fileCopyJob.StartJob();
WriteObject(fileCopyJob);
}
#endregion
}
/// <summary>
/// Sample FileCopyJob class derived from Job2.
/// This sample job runs until stopped and monitors the provided
/// source file for changes and copies it to the destination path
/// on change.
/// </summary>
public sealed class FileCopyJob : Job2
{
#region Private members
private const string FileCopyJobTypeName = "FileCopyJob";
private FileSystemWatcher _fileWatcher;
private string _sourcePath;
private string _destinationPath;
#endregion
#region Constructor
private FileCopyJob()
{ }
/// <summary>
/// Constructor
/// </summary>
/// <param name="jobName">Job name</param>
/// <param name="sourcePath">Source file path</param>
/// <param name="destinationPath">Copy to destination file path</param>
public FileCopyJob(
string jobName,
string sourcePath,
string destinationPath)
{
if (string.IsNullOrEmpty(sourcePath))
{
throw new ArgumentException("sourcePath");
}
if (string.IsNullOrEmpty(destinationPath))
{
throw new ArgumentException("destPath");
}
_sourcePath = sourcePath;
_destinationPath = destinationPath;
this.Name = !string.IsNullOrEmpty(jobName) ? jobName : "FileCopyJob";
this.PSJobTypeName = FileCopyJobTypeName;
// File watcher.
_fileWatcher = new FileSystemWatcher(Path.GetDirectoryName(_sourcePath));
_fileWatcher.Filter = Path.GetFileName(_sourcePath);
_fileWatcher.EnableRaisingEvents = false;
_fileWatcher.NotifyFilter = NotifyFilters.LastWrite;
_fileWatcher.Changed += new FileSystemEventHandler(HandleFileWatcherChanged);
// Job state changed callback.
this.StateChanged += new EventHandler<JobStateEventArgs>(HandleJobStateChanged);
}
#endregion
#region Public properties
public string SourcePath
{
get { return _sourcePath; }
}
public string DestinationPath
{
get { return _destinationPath; }
}
#endregion
#region Public methods
public override void StartJob()
{
if (this.JobStateInfo.State != JobState.NotStarted)
{
throw new InvalidOperationException("Cannot start job.");
}
SetJobState(JobState.Running);
_fileWatcher.EnableRaisingEvents = true;
}
public override void StartJobAsync()
{
StartJob();
OnStartJobCompleted(new System.ComponentModel.AsyncCompletedEventArgs(null, false, null));
}
public override void StopJob()
{
if (!IsFinishedState(this.JobStateInfo.State))
{
SetJobState(JobState.Stopped);
}
}
public override void StopJobAsync()
{
StopJob();
OnStopJobCompleted(new System.ComponentModel.AsyncCompletedEventArgs(null, false, null));
}
public override void StopJob(bool force, string reason)
{
StopJob();
}
public override void StopJobAsync(bool force, string reason)
{
StopJobAsync();
}
public override void SuspendJob()
{
switch (this.JobStateInfo.State)
{
case JobState.Suspended:
break;
case JobState.Running:
_fileWatcher.EnableRaisingEvents = false;
SetJobState(JobState.Suspended);
break;
default:
throw new InvalidOperationException("Cannot suspend job.");
}
}
public override void SuspendJobAsync()
{
SuspendJob();
OnSuspendJobCompleted(new System.ComponentModel.AsyncCompletedEventArgs(null, false, null));
}
public override void SuspendJob(bool force, string reason)
{
SuspendJob();
}
public override void SuspendJobAsync(bool force, string reason)
{
SuspendJobAsync();
}
public override void ResumeJob()
{
switch (this.JobStateInfo.State)
{
case JobState.Running:
break;
case JobState.Suspended:
SetJobState(JobState.Running);
_fileWatcher.EnableRaisingEvents = true;
break;
default:
throw new InvalidOperationException("Cannot resume job.");
}
}
public override void ResumeJobAsync()
{
ResumeJob();
OnResumeJobCompleted(new System.ComponentModel.AsyncCompletedEventArgs(null, false, null));
}
public override void UnblockJob()
{
throw new NotImplementedException();
}
public override void UnblockJobAsync()
{
throw new NotImplementedException();
}
public override bool HasMoreData
{
get
{
return (Output.Count > 0 ||
Error.Count > 0);
}
}
public override string Location
{
get { return "localhost"; }
}
public override string StatusMessage
{
get { return string.Empty; }
}
#endregion
#region IDispose
protected override void Dispose(bool disposing)
{
if (!IsFinishedState(this.JobStateInfo.State))
{
SetJobState(JobState.Stopped);
}
base.Dispose(disposing);
}
#endregion
#region Private methods
private void HandleFileWatcherChanged(object sender, FileSystemEventArgs e)
{
if (IsFinishedState(this.JobStateInfo.State))
{
return;
}
Exception failed = null;
try
{
File.Copy(_sourcePath, _destinationPath, true);
}
catch (IOException ex)
{
failed = ex;
}
catch (UnauthorizedAccessException ex)
{
failed = ex;
}
if (failed != null && Error.IsOpen)
{
try
{
Error.Add(new ErrorRecord(failed, "FileCopyFailed", ErrorCategory.WriteError, this));
}
catch (PSInvalidOperationException)
{
// Can't write to closed buffer.
}
}
}
private void HandleJobStateChanged(object sender, JobStateEventArgs e)
{
if (IsFinishedState(e.JobStateInfo.State))
{
// Job transitioned to finished state.
this.StateChanged -= new EventHandler<JobStateEventArgs>(HandleJobStateChanged);
DisposeFileWatcher();
}
}
private void DisposeFileWatcher()
{
if (_fileWatcher != null)
{
_fileWatcher.Changed -= new FileSystemEventHandler(HandleFileWatcherChanged);
_fileWatcher.Dispose();
_fileWatcher = null;
}
}
private bool IsFinishedState(JobState state)
{
return (state == JobState.Completed ||
state == JobState.Stopped ||
state == JobState.Failed);
}
#endregion
}
/// <summary>
/// Sample JobSourceAdapter for a file copy job.
/// Creates new CopyFileJob jobs.
/// Maintains repository for CopyFileJobs.
/// </summary>
public sealed class FileCopyJobSourceAdapter : JobSourceAdapter
{
#region Private members
private const string AdapterTypeName = "FileCopyJobSourceAdapter";
private static List<Job2> JobRepository = new List<Job2>();
#endregion
#region Public strings
// FileCopy job properties.
public const string SourcePathProperty = "SourcePath";
public const string DestinationPathProperty = "DestinationPath";
#endregion
#region Constructor
public FileCopyJobSourceAdapter()
{
this.Name = AdapterTypeName;
}
#endregion
#region Public methods
public override Job2 NewJob(JobInvocationInfo specification)
{
if (specification == null)
{
throw new NullReferenceException("specification");
}
if (specification.Parameters.Count != 1)
{
throw new ArgumentException("JobInvocationInfo specification parameters not specified.");
}
// Retrieve source and destination path information from specification
// parameters.
string sourcePath = null;
string destinationPath = null;
CommandParameterCollection parameters = specification.Parameters[0];
foreach (var item in parameters)
{
if (item.Name.Equals(SourcePathProperty, StringComparison.OrdinalIgnoreCase))
{
sourcePath = item.Value as string;
}
else if (item.Name.Equals(DestinationPathProperty, StringComparison.OrdinalIgnoreCase))
{
destinationPath = item.Value as string;
}
}
// Create FileCopyJob
FileCopyJob rtnJob = new FileCopyJob(specification.Name, sourcePath, destinationPath);
lock (JobRepository)
{
JobRepository.Add(rtnJob);
}
return rtnJob;
}
public override void RemoveJob(Job2 job)
{
lock (JobRepository)
{
if (JobRepository.Contains(job))
{
JobRepository.Remove(job);
}
}
job.Dispose();
}
public override IList<Job2> GetJobs()
{
lock (JobRepository)
{
return JobRepository.ToArray<Job2>();
}
}
public override Job2 GetJobByInstanceId(Guid instanceId, bool recurse)
{
lock (JobRepository)
{
foreach (var job in JobRepository)
{
if (job.InstanceId == instanceId)
{
return job;
}
}
}
return null;
}
public override Job2 GetJobBySessionId(int id, bool recurse)
{
lock (JobRepository)
{
foreach (var job in JobRepository)
{
if (job.Id == id)
{
return job;
}
}
}
return null;
}
public override IList<Job2> GetJobsByName(string name, bool recurse)
{
List<Job2> rtnJobs = new List<Job2>();
WildcardPattern namePattern = new WildcardPattern(name, WildcardOptions.IgnoreCase);
lock (JobRepository)
{
foreach (var job in JobRepository)
{
if (namePattern.IsMatch(job.Name))
{
rtnJobs.Add(job);
}
}
}
return rtnJobs;
}
public override IList<Job2> GetJobsByState(JobState state, bool recurse)
{
List<Job2> rtnJobs = new List<Job2>();
lock (JobRepository)
{
foreach (var job in JobRepository)
{
if (job.JobStateInfo.State == state)
{
rtnJobs.Add(job);
}
}
}
return rtnJobs;
}
public override IList<Job2> GetJobsByCommand(string command, bool recurse)
{
throw new NotImplementedException();
}
public override IList<Job2> GetJobsByFilter(Dictionary<string, object> filter, bool recurse)
{
throw new NotImplementedException();
}
#endregion
}
}