using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml.Serialization;
namespace Microsoft.Win32.TaskScheduler
{
///
/// Collection that contains the actions that are performed by the task.
///
/// A Task Scheduler 1.0 task can only contain a single .
[XmlRoot("Actions", Namespace = TaskDefinition.tns, IsNullable = false)]
public sealed class ActionCollection : IList, IDisposable, IXmlSerializable
{
private V1Interop.ITask v1Task;
private V2Interop.ITaskDefinition v2Def;
private V2Interop.IActionCollection v2Coll;
internal ActionCollection(V1Interop.ITask task)
{
v1Task = task;
}
internal ActionCollection(V2Interop.ITaskDefinition iTaskDef)
{
v2Def = iTaskDef;
v2Coll = iTaskDef.Actions;
if (TaskService.LibraryVersion.Minor > 3)
UnconvertUnsupportedActions();
}
///
/// Releases all resources used by this class.
///
public void Dispose()
{
v1Task = null;
v2Def = null;
v2Coll = null;
}
///
/// Adds an action to the task.
///
/// A derived class.
/// The bound that was added to the collection.
public Action Add(Action action)
{
if (v2Def != null)
action.Bind(v2Def);
else
action.Bind(v1Task);
return action;
}
///
/// Adds an to the task.
///
/// Path to an executable file.
/// Arguments associated with the command-line operation. This value can be null.
/// Directory that contains either the executable file or the files that are used by the executable file. This value can be null.
/// The bound that was added to the collection.
public ExecAction Add(string path, string arguments = null, string workingDirectory = null)
{
return (ExecAction)this.Add(new ExecAction(path, arguments, workingDirectory));
}
///
/// Adds a new instance to the task.
///
/// Type of task to be created
/// Specialized instance.
public Action AddNew(TaskActionType actionType)
{
if (v1Task != null)
return new ExecAction(v1Task);
return Action.CreateAction(v2Coll.Create(actionType));
}
///
/// Clears all actions from the task.
///
public void Clear()
{
if (v2Coll != null)
v2Coll.Clear();
else
Add(new ExecAction());
}
///
/// Determines whether the contains a specific value.
///
/// The object to locate in the .
///
/// true if is found in the ; otherwise, false.
///
public bool Contains(Action item)
{
return IndexOf(item) >= 0;
}
///
/// Determines whether the specified action type is contained in this collection.
///
/// Type of the action.
///
/// true if the specified action type is contained in this collection; otherwise, false.
///
public bool ContainsType(Type actionType)
{
foreach (Action a in this)
if (a.GetType() == actionType)
return true;
return false;
}
///
/// Copies the elements of the to an , starting at a particular index.
///
/// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing.
/// The zero-based index in at which copying begins.
/// is null.
/// is less than 0.
/// The number of elements in the source is greater than the available space from to the end of the destination .
public void CopyTo(Action[] array, int arrayIndex)
{
if (array == null)
throw new ArgumentNullException();
if (arrayIndex < 0)
throw new ArgumentOutOfRangeException();
if (this.Count > (array.Length - arrayIndex))
throw new ArgumentException();
for (int i = 0; i < this.Count; i++)
array[arrayIndex + i] = (Action)this[i].Clone();
}
private const string ScriptIdentifer = "TSML_20140424";
internal void ConvertUnsupportedActions()
{
#if DEBUG
const string PowerShellArgFormat = "-NoExit -Command \"& {{<# {0}:{1} #> {2}}}\"";
#else
const string PowerShellArgFormat = "-NoLogo -NonInteractive -WindowStyle Hidden -Command \"& {{<# {0}:{1} #> {2}}}\"";
#endif
const string PowerShellPath = "powershell";
for (int i = 0; i < this.Count; i++)
{
Action action = this[i];
if (action is IBindAsExecAction)
{
string args = string.Format(PowerShellArgFormat, ScriptIdentifer, action.ActionType, ((IBindAsExecAction)action).GetPowerShellCommand());
ExecAction newAction = new ExecAction(PowerShellPath, args);
this[i] = newAction;
}
}
}
internal void UnconvertUnsupportedActions()
{
for (int i = 0; i < this.Count; i++)
{
ExecAction action = this[i] as ExecAction;
if (action != null && action.Arguments != null && action.Arguments.Contains(ScriptIdentifer))
{
var match = System.Text.RegularExpressions.Regex.Match(action.Arguments, @"<# " + ScriptIdentifer + ":(?\\w+) #> (?.+)}\"$");
if (match.Success)
{
Action newAction = null;
if (match.Groups["type"].Value == "SendEmail")
newAction = EmailAction.FromPowerShellCommand(match.Groups["cmd"].Value);
else if (match.Groups["type"].Value == "ShowMessage")
newAction = ShowMessageAction.FromPowerShellCommand(match.Groups["cmd"].Value);
if (newAction != null)
this[i] = newAction;
}
}
}
}
///
/// Determines the index of a specific item in the .
///
/// The object to locate in the .
///
/// The index of if found in the list; otherwise, -1.
///
public int IndexOf(Action item)
{
for (int i = 0; i < this.Count; i++)
{
if (this[i].Equals(item))
return i;
}
return -1;
}
///
/// Determines the index of a specific item in the .
///
/// The id () of the action to be retrieved.
///
/// The index of if found in the list; otherwise, -1.
///
public int IndexOf(string actionId)
{
if (string.IsNullOrEmpty(actionId))
throw new ArgumentNullException(actionId);
for (int i = 0; i < this.Count; i++)
{
if (string.Equals(this[i].Id, actionId))
return i;
}
return -1;
}
///
/// Inserts an action at the specified index.
///
/// The zero-based index at which action should be inserted.
/// The action to insert into the list.
public void Insert(int index, Action action)
{
if (v2Coll == null && this.Count > 0)
throw new NotV1SupportedException("Only a single action is allowed.");
Action[] pushItems = new Action[this.Count - index];
for (int i = index; i < this.Count; i++)
pushItems[i - index] = (Action)this[i].Clone();
for (int j = this.Count - 1; j >= index; j--)
RemoveAt(j);
Add(action);
for (int k = 0; k < pushItems.Length; k++)
Add(pushItems[k]);
}
///
/// Removes the first occurrence of a specific object from the .
///
/// The object to remove from the .
///
/// true if was successfully removed from the ; otherwise, false. This method also returns false if is not found in the original .
///
public bool Remove(Action item)
{
int idx = IndexOf(item);
if (idx != -1)
{
try
{
RemoveAt(idx);
return true;
}
catch { }
}
return false;
}
///
/// Removes the action at a specified index.
///
/// Index of action to remove.
/// Index out of range.
public void RemoveAt(int index)
{
if (index >= this.Count)
throw new ArgumentOutOfRangeException("index", index, "Failed to remove action. Index out of range.");
if (v2Coll != null)
v2Coll.Remove(++index);
else if (index == 0)
Add(new ExecAction());
else
throw new NotV1SupportedException("There can be only a single action and it cannot be removed.");
}
///
/// Returns a that represents the actions in this collection.
///
///
/// A that represents the actions in this collection.
///
public override string ToString()
{
if (this.Count == 1)
return this[0].ToString();
if (this.Count > 1)
return Properties.Resources.MultipleActions;
return string.Empty;
}
///
/// Gets or sets a an action at the specified index.
///
/// The zero-based index of the action to get or set.
public Action this[int index]
{
get
{
if (v2Coll != null)
return Action.CreateAction(v2Coll[++index]);
if (index == 0)
return new ExecAction(v1Task.GetApplicationName(), v1Task.GetParameters(), v1Task.GetWorkingDirectory());
throw new ArgumentOutOfRangeException();
}
set
{
if (this.Count <= index)
throw new ArgumentOutOfRangeException("index", index, "Index is not a valid index in the ActionCollection");
RemoveAt(index);
Insert(index, value);
}
}
///
/// Gets or sets a specified action from the collection.
///
///
/// The .
///
/// The id () of the action to be retrieved.
///
/// Specialized instance.
///
///
///
///
/// Mismatching Id for action and lookup.
public Action this[string actionId]
{
get
{
if (string.IsNullOrEmpty(actionId))
throw new ArgumentNullException(actionId);
foreach (Action t in this)
if (string.Equals(t.Id, actionId))
return t;
throw new ArgumentOutOfRangeException(actionId);
}
set
{
if (value == null)
throw new NullReferenceException();
if (string.IsNullOrEmpty(actionId))
throw new ArgumentNullException(actionId);
if (actionId != value.Id)
throw new InvalidOperationException("Mismatching Id for action and lookup.");
int index = IndexOf(actionId);
if (index >= 0)
{
RemoveAt(index);
Insert(index, value);
}
else
Add(value);
}
}
///
/// Gets or sets the identifier of the principal for the task.
///
/// Not supported under Task Scheduler 1.0.
[System.Xml.Serialization.XmlAttribute(AttributeName = "Context", DataType = "IDREF")]
public string Context
{
get
{
if (v2Coll != null)
return v2Coll.Context;
return string.Empty;
}
set
{
if (v2Coll != null)
v2Coll.Context = value;
else
throw new NotV1SupportedException();
}
}
///
/// Gets the number of actions in the collection.
///
public int Count
{
get
{
if (v2Coll != null)
return v2Coll.Count;
return ((string)v1Task.GetApplicationName()).Length == 0 ? 0 : 1;
}
}
///
/// Gets or sets an XML-formatted version of the collection.
///
public string XmlText
{
get
{
if (v2Coll != null)
return v2Coll.XmlText;
return XmlSerializationHelper.WriteObjectToXmlText(this);
}
set
{
if (v2Coll != null)
v2Coll.XmlText = value;
else
XmlSerializationHelper.ReadObjectFromXmlText(value, this);
}
}
///
/// Retrieves an enumeration of each of the actions.
///
/// Returns an object that implements the interface and that can iterate through the objects within the .
public IEnumerator GetEnumerator()
{
if (v2Coll != null)
return new Enumerator(this);
return new Enumerator(this.v1Task);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
internal class Enumerator : IEnumerator
{
private V1Interop.ITask v1Task;
private int v1Pos = -1;
private IEnumerator v2Enum;
private ActionCollection parent;
internal Enumerator(V1Interop.ITask task)
{
v1Task = task;
}
internal Enumerator(ActionCollection iColl)
{
parent = iColl;
if (iColl.v2Coll != null)
v2Enum = iColl.v2Coll.GetEnumerator();
}
public Action Current
{
get
{
if (v2Enum != null)
{
V2Interop.IAction iAction = v2Enum.Current as V2Interop.IAction;
if (iAction != null)
return Action.CreateAction(iAction);
}
if (v1Pos == 0)
return new ExecAction(v1Task.GetApplicationName(), v1Task.GetParameters(), v1Task.GetWorkingDirectory());
throw new InvalidOperationException();
}
}
///
/// Releases all resources used by this class.
///
public void Dispose()
{
v1Task = null;
v2Enum = null;
}
object System.Collections.IEnumerator.Current
{
get { return this.Current; }
}
public bool MoveNext()
{
if (v2Enum != null)
return v2Enum.MoveNext();
return ++v1Pos == 0;
}
public void Reset()
{
if (v2Enum != null)
v2Enum.Reset();
v1Pos = -1;
}
}
System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
{
return null;
}
void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
{
reader.ReadStartElement("Actions", TaskDefinition.tns);
while (reader.MoveToContent() == System.Xml.XmlNodeType.Element)
{
Action newAction = null;
switch (reader.LocalName)
{
case "Exec":
newAction = this.AddNew(TaskActionType.Execute);
break;
default:
reader.Skip();
break;
}
if (newAction != null)
XmlSerializationHelper.ReadObject(reader, newAction);
}
reader.ReadEndElement();
}
void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)
{
if (this.Count > 0)
{
XmlSerializationHelper.WriteObject(writer, this[0] as ExecAction);
}
}
void ICollection.Add(Action item)
{
this.Add(item);
}
bool ICollection.IsReadOnly
{
get { return false; }
}
}
}