Src/EntityObjects.cs
using System;
using System.Linq; using System.IO; using System.Xml; using System.Text; using System.Globalization; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Management.Automation; using Microsoft.EnterpriseManagement; using Microsoft.EnterpriseManagement.Common; using Microsoft.EnterpriseManagement.Configuration; using Microsoft.EnterpriseManagement.Configuration.IO; using Microsoft.EnterpriseManagement.ConnectorFramework; using System.Text.RegularExpressions; namespace SMLets { public class ObjectCmdletHelper : SMCmdletBase { // For the Object cmdlets, they all pretty much can use ObjectQueryOptions, so // we'll just make it part of the base class private ObjectQueryOptions _queryOption = ObjectQueryOptions.Default; [Parameter] public ObjectQueryOptions QueryOption { get { return _queryOption; } set { _queryOption = value; } } public void AssignNewValues(EnterpriseManagementObject o, Hashtable ht) { foreach(string s in ht.Keys) { bool found = false; WriteDebug("Attempting to find property " + s); foreach(ManagementPackProperty p in o.GetProperties()) { int CompareResult = String.Compare(p.Name,s,ic); WriteDebug("PROPERTY " + p.Name + " == " + s + " Result: " + CompareResult); if ( CompareResult == 0 ) { found = true; WriteDebug("Assigning " + ht[s] + " to " + p.Name ); try { AssignNewValue(p, o[p], ht[s]); } catch (Exception e ) { string errmsg = "Assigning " + ht[s] + " to " + p.Name; WriteError(new ErrorRecord(e, errmsg, ErrorCategory.InvalidOperation, ht[s])); } break; } } if ( ! found ) { WriteDebug("Could not find property " + s + " on object"); } } } // in PowerShell, string comparisons are done with case ignored public StringComparison ic = StringComparison.OrdinalIgnoreCase; // Assign a value to a managementpack property // This code is clever enough to handle nearly all of the types that // a management pack property can be // if you attempt to assign something which is an enum type // we'll go looking for the appropriate enumeration and use that // TODO: handle the binary property type (it should take a stream) public void AssignNewValue(ManagementPackProperty p, EnterpriseManagementSimpleObject so, object newValue) { string PropertyType = p.Type.ToString(); WriteVerbose("Want to set " + p.Name + "(" + PropertyType + ") to " + newValue); // so, if new value is null, set and return immediately if (newValue == null) { try { so.Value = null; } catch (Exception e) { WriteError(new ErrorRecord(e, "Could not assign " + p.Name + " to null", ErrorCategory.InvalidOperation, newValue)); } return; } switch (PropertyType) { case "richtext" : case "string" : try { so.Value = newValue; } catch (InvalidSimpleObjectValueException) { WriteWarning("Converting new value ('" + newValue.GetType().ToString() + ":" + newValue.ToString() + "') to string"); so.Value = newValue.ToString(); } break; case "double": case "int": case "bool": so.Value = newValue; break; case "guid": // This should be done in a try/catch // otherwise it will fail poorly try { so.Value = new Guid(newValue.ToString()); } catch ( Exception e ) { WriteError(new ErrorRecord(e, "Could not assign guid", ErrorCategory.InvalidOperation, newValue)); } break; case "enum": WriteDebug("Looking for Enumeration: " + newValue); ManagementPackEnumeration mpe; // We might have gotten an enum, try the assignment if ( newValue is ManagementPackEnumeration ) { WriteVerbose("Actually an enumeration"); try { mpe = (ManagementPackEnumeration)newValue; so.Value = mpe; } catch ( Exception e ) { WriteError(new ErrorRecord(e, "Could not assign enum", ErrorCategory.InvalidOperation, newValue)); } } else { WriteVerbose("Looking Enum via string " + newValue.ToString() + " in " + p.EnumType.GetElement()); try { mpe = SMHelpers.GetEnum(newValue.ToString(), p.EnumType.GetElement()); WriteVerbose("found enum: " + mpe.ToString()); so.Value = mpe; WriteVerbose("set the value"); } catch ( Exception e ) { WriteError(new ErrorRecord(e, "Could not assign enum ", ErrorCategory.ObjectNotFound, newValue)); } } break; case "datetime": // TODO: handle failure gracefully try { so.Value = DateTime.Parse(newValue.ToString(), CultureInfo.CurrentCulture).ToString(); } catch ( Exception e ) { WriteError(new ErrorRecord(e, "Could not assign date ", ErrorCategory.ObjectNotFound, newValue)); } break; case "binary": // TODO: HANDLE filename FileStream myStream = null; // Deal with the case that we got a PSObject if ( newValue is PSObject ) { myStream = ((PSObject)newValue).BaseObject as FileStream; } else { // see if we get lucky myStream = newValue as FileStream; } if (myStream != null) { so.Value = myStream; } else { WriteError(new ErrorRecord(new ArgumentException(newValue.ToString()), String.Format("Property must be a file stream, received a {0}", newValue.GetType().FullName), ErrorCategory.InvalidArgument, newValue)); } break; default: WriteVerbose("Could not find type setter for " + PropertyType); WriteError(new ErrorRecord(new ItemNotFoundException("PropertySetterNotFound"), "No such property setter", ErrorCategory.ObjectNotFound, PropertyType)); break; } } // All this does is convert the PowerShell filter language to the criteria syntax public string ConvertFilterToGenericCriteria(string filter) { Dictionary<string,string> OpToOp = new Dictionary<string,string>(); Regex re; // "-gt","-ge","-lt","-le","-eq","-ne","-like","-notlike","-match","-notmatch" // Add -isnull and -isnotnull, even though they aren't PowerShell operators OpToOp.Add("-and", "and"); OpToOp.Add("-or", "or"); OpToOp.Add("-eq","="); OpToOp.Add("-ne","!="); OpToOp.Add("-lt","<"); OpToOp.Add("-gt",">"); OpToOp.Add("-le","<="); OpToOp.Add("-ge",">="); OpToOp.Add("-like","like"); OpToOp.Add("-notlike","! like"); OpToOp.Add("-isnull", "is null"); OpToOp.Add("-isnotnull", "is not null"); re = new Regex("\\*"); filter = re.Replace(filter, "%"); re = new Regex("\\?"); filter = re.Replace(filter,"_"); re = new Regex("\""); filter = re.Replace(filter, "'"); foreach(string k in OpToOp.Keys) { re = new Regex(k, RegexOptions.CultureInvariant|RegexOptions.IgnoreCase); filter = re.Replace(filter, OpToOp[k]); } return filter; } public string FixUpPropertyNames(string filter, ManagementPackClass mpClass) { Dictionary<string,string> propertyFixes = new Dictionary<string,string>(); Regex re; foreach (ManagementPackProperty p in mpClass.GetProperties(BaseClassTraversalDepth.Recursive)) { re = new Regex(p.Name, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); filter = re.Replace(filter, p.Name); } WriteDebug("returning: " + filter); return filter; } public string ConvertFilterToCriteriaString( ManagementPackClass mpClass, string filter, bool isProjection ) { WriteVerbose("ConvertFilterToCriteriaString: " + filter); StringBuilder sb = new StringBuilder(); List<PropertyOperatorValue> POVs = new List<PropertyOperatorValue>(); foreach (string subFilter in Regex.Split(filter, "-or", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase)) { WriteVerbose("SubFilter => " + subFilter); try { POVs.Add(new PropertyOperatorValue(subFilter)); } catch { WriteError(new ErrorRecord(new ObjectNotFoundException("criteria"), "Bad Filter", ErrorCategory.NotSpecified, filter)); return null; } } // Construct the Criteria XML // This should really be done with an XML DOM methods sb.Append("<Criteria xmlns='http://Microsoft.EnterpriseManagement.Core.Criteria/'>"); sb.Append("<Reference Id='"); sb.Append(mpClass.GetManagementPack().Name); sb.Append("' Version='"); sb.Append(mpClass.GetManagementPack().Version.ToString()); sb.Append("'"); if ( mpClass.GetManagementPack().KeyToken != null) { sb.Append(" PublicKeyToken='"); sb.Append(mpClass.GetManagementPack().KeyToken); sb.Append("'"); } sb.Append(" Alias='myMP' />"); // JWT START OF EXPRESSION // CHECK FOR AND/OR HERE if (POVs.Count > 1) { sb.Append("<Expression>"); sb.Append("<Or>"); } foreach (PropertyOperatorValue POV in POVs) { sb.Append("<Expression>"); sb.Append("<SimpleExpression>"); // check to be sure the property exists on the class // do this with a creatable EMO as *all* the properties are presented // If the class is abstract, you can't create it. This means you have // to use the properties on the class as you get it. List<ManagementPackProperty> proplist = new List<ManagementPackProperty>(); if (mpClass.Abstract) { foreach (ManagementPackProperty p in mpClass.PropertyCollection) { proplist.Add(p); } } else { // The proper way to get at the properties of a class foreach (ManagementPackProperty p in mpClass.GetProperties(BaseClassTraversalDepth.Recursive, PropertyExtensionMode.All)) { proplist.Add(p); } } bool foundproperty = false; foreach (ManagementPackProperty p in proplist) { if (String.Compare(POV.Property, p.Name, StringComparison.InvariantCultureIgnoreCase) == 0) { sb.Append("<ValueExpressionLeft>"); if (isProjection) { // projection not quite supported sb.Append("<Property>$Target/Property[Type='myMP!" + mpClass.Name + "']/" + p.Name + "$</Property>"); } else { sb.Append("<Property>$Target/Property[Type='myMP!" + mpClass.Name + "']/" + p.Name + "$</Property>"); } sb.Append("</ValueExpressionLeft>"); foundproperty = true; break; } } // perhaps the provided property is a generic property if (!foundproperty) { foreach (GenericProperty p in GenericProperty.GetGenericProperties()) { if (String.Compare(POV.Property, p.PropertyName, StringComparison.InvariantCultureIgnoreCase) == 0) { sb.Append("<ValueExpressionLeft>"); // sb.Append("<GenericProperty>$Target/Property[Type='myMP!" + mpClass.Name + "']/" + p.PropertyName + "$</GenericProperty>"); sb.Append("<GenericProperty>" + p.PropertyName + "</GenericProperty>"); sb.Append("</ValueExpressionLeft>"); foundproperty = true; } } } if (!foundproperty) { WriteError(new ErrorRecord(new ObjectNotFoundException("property"), "Property Not Found", ErrorCategory.NotSpecified, filter)); return null; } // Now add the operator sb.Append("<Operator>" + POV.Operator + "</Operator>"); // Finally, the value - no checking here, just add it sb.Append("<ValueExpressionRight><Value>"); // TODO: HANDLE ENUMS sb.Append(POV.Value); sb.Append("</Value></ValueExpressionRight>"); sb.Append("</SimpleExpression>"); sb.Append("</Expression>"); } if (POVs.Count > 1) { sb.Append("</Or>"); sb.Append("</Expression>"); } // JWT END OF EXPRESSION sb.Append("</Criteria>"); WriteVerbose(sb.ToString()); return sb.ToString(); } // This doesn't completely work yet // TODO: handle generic property queries // I think it will look like: // PROPERTY OPERATOR VALUE // so, you could do: // DISPLAYNAME -EQ 'Boo ya!' // and you'll get the filter back // Also need to support Enumeration values, so user can provide a string rather than a guid for an enum // value public EnterpriseManagementObjectCriteria ConvertFilterToObjectCriteria ( ManagementPackClass mpClass, string filter) { EnterpriseManagementObjectCriteria myCriteria = null; string filterString = null; // First attempt to use the simple constructor for the ObjectCriteria, just the filter and the class // First replace all the PowerShell operators // this will return a criteria if we have success try { WriteVerbose("Original Filter: " + filter); filterString = ConvertFilterToGenericCriteria(filter); filterString = FixUpPropertyNames(filterString, mpClass); WriteVerbose("Fixed Filter: " + filterString); myCriteria = new EnterpriseManagementObjectCriteria(filterString, mpClass); WriteVerbose("Using " + filterString + " as criteria"); return myCriteria; } catch // This is non-catastrophic - it's our first attempt { WriteDebug("failed: " + filter); } try { filterString = ConvertFilterToCriteriaString(mpClass, filter, false); myCriteria = new EnterpriseManagementObjectCriteria(filterString, mpClass, _mg); } catch (InvalidCriteriaException e) { ThrowTerminatingError(new ErrorRecord(e, "Bad Filter", ErrorCategory.InvalidOperation, filterString)); } catch (Exception e) { ThrowTerminatingError(new ErrorRecord(e, "Bad Filter", ErrorCategory.InvalidOperation, filter)); } return myCriteria; } public ObjectProjectionCriteria ConvertFilterToProjectionCriteria ( ManagementPackTypeProjection projection, string filter ) { XmlDocument x = new XmlDocument(); try { // if you can create an ObjectProjectionCriteria because you got some XML, groovy x.LoadXml(filter); // if we get to here, then we know we at least have some well formed XML // now try to create an ObjectProjectionCriteria WriteVerbose(filter); ObjectProjectionCriteria opc = new ObjectProjectionCriteria(filter, projection, _mg); return opc; } // don't do anything here, just keep going as an XML exception // means that we probably got a real filter rather than some XML Criteria catch (XmlException) { ; } // OK, we got valid XML but a bad criteria, notify and bail catch (InvalidCriteriaException e) { ThrowTerminatingError( new ErrorRecord(e, "InvalidCriteria", ErrorCategory.InvalidData, filter)); } string filterString = ConvertFilterToCriteriaString ( projection.TargetType, filter, true ); ObjectProjectionCriteria myCriteria = new ObjectProjectionCriteria(filterString, projection, _mg); return myCriteria; } } public class FilterCmdletBase : ObjectCmdletHelper { protected string _filter = null; [Parameter] public string Filter { get { return _filter; } set { _filter = value; } } private Int32 _maxCount = Int32.MaxValue; [Parameter] public Int32 MaxCount { get { return _maxCount; } set { _maxCount = value; } } // By default, we'll collect the projections base on // when they were created private string _sortBy = "TimeAdded"; [Parameter] public string SortBy { get { return _sortBy; } set { _sortBy = value; } } internal const string xmlns = "xmlns=\"http://Microsoft.EnterpriseManagement.Core.Sorting\""; internal const string ascending = "Ascending"; internal const string descending = "Descending"; internal string Order = ascending; internal void addSortProperty(ObjectQueryOptions options, string sortProperty, ManagementPackClass c) { SortingOrder sOrder = SortingOrder.Ascending; if (sortProperty == null || c == null || options == null) { return; } if (sortProperty[0] == '-') { sOrder = SortingOrder.Descending; sortProperty = SortBy.Substring(1); } WriteVerbose("look for instance properties first"); foreach (ManagementPackProperty mpp in c.GetProperties(BaseClassTraversalDepth.Recursive)) { if (string.Compare(mpp.Name, sortProperty, true) == 0) { options.AddSortProperty(mpp, sOrder); return; } } WriteVerbose("now look for generic properties"); foreach (GenericProperty gp in GenericProperty.GetGenericProperties()) { if (string.Compare(gp.PropertyName, sortProperty, true) == 0) { Type t = typeof(EnterpriseManagementObjectGenericPropertyName); EnterpriseManagementObjectGenericPropertyName pn = (EnterpriseManagementObjectGenericPropertyName)Enum.Parse(t, gp.PropertyName); EnterpriseManagementObjectGenericProperty gProperty = new EnterpriseManagementObjectGenericProperty(pn); options.AddSortProperty(gProperty, sOrder); return; } } } internal string makeSortCriteriaString(string sortProperty, ManagementPackClass c) { WriteDebug("makeSortCriteriaString with MP Class"); Order = ascending; // Now that we have a projection, create the sort order if (sortProperty[0] == '-') { Order = descending; sortProperty = SortBy.Substring(1); } WriteVerbose("checking for targettype property"); foreach (ManagementPackProperty mpp in c.GetProperties(BaseClassTraversalDepth.Recursive)) { WriteVerbose("Checking TargetType properties: " + mpp.Name + " - " + sortProperty); if (string.Compare(mpp.Name, sortProperty, true) == 0) { WriteVerbose("Sort Property: " + mpp.Name); return String.Format( "<Sorting {0}><SortProperty SortOrder=\"{1}\">$Target/Property[Type='{2}']/{3}$</SortProperty></Sorting>", xmlns, Order, c.Id, mpp.Name ); } } // OK, we'll check targettype properties first foreach (GenericProperty gp in GenericProperty.GetGenericProperties()) { if (string.Compare(gp.PropertyName, sortProperty, true) == 0) { WriteVerbose("Sort property: " + gp.PropertyName); return String.Format( "<Sorting {0}><GenericSortProperty SortOrder=\"{1}\">{2}</GenericSortProperty></Sorting>", xmlns, Order, gp.PropertyName ); } } return null; } internal string makeSortCriteriaString(string sortProperty, ManagementPackTypeProjection p) { WriteDebug("start makeSortCriteriaString"); Order = ascending; // Now that we have a projection, create the sort order if (SortBy[0] == '-') { Order = descending; sortProperty = SortBy.Substring(1); } // OK, we'll check generic properties first WriteVerbose("makeSortCriteriaString"); foreach (GenericProperty gp in GenericProperty.GetGenericProperties()) { if (string.Compare(gp.PropertyName, sortProperty, true) == 0) { WriteVerbose("Sort property: " + gp.PropertyName); return String.Format( "<Sorting {0}><GenericSortProperty SortOrder=\"{1}\">{2}</GenericSortProperty></Sorting>", xmlns, Order, gp.PropertyName ); } } WriteVerbose("checking further"); foreach (ManagementPackProperty mpp in p.TargetType.GetProperties(BaseClassTraversalDepth.Recursive)) { WriteVerbose("Checking TargetType properties: " + mpp.Name + " - " + sortProperty); if (string.Compare(mpp.Name, sortProperty, true) == 0) { WriteVerbose("Sort Property: " + mpp.Name); return String.Format( "<Sorting {0}><SortProperty SortOrder=\"{1}\">$Target/Property[Type='{2}']/{3}$</SortProperty></Sorting>", xmlns, Order, p.TargetType.Id, mpp.Name ); } } return null; } } public sealed class ServiceManagerObjectHelper { // a helper class to read a stream and adapt an EMO // We handle the retrival of binary types // if it's a binary property type, we'll return an array of // bytes private static Byte[] GetBytes(Stream s) { // Why SM binary fields don't have a valid length property is a mystery if ( s == null ) { return null; } byte[] buffer = new byte[4096]; Collection<Byte[]> balist = new Collection<Byte[]>(); int count; int totalLength = 0; while ( (count = s.Read(buffer,0,4096)) != 0 ) { totalLength += count; byte[] tbyte = new byte[count]; Array.Copy(buffer, tbyte, count); balist.Add(tbyte); } byte[] ReturnBytes = new byte[totalLength]; int offset = 0; foreach(byte[]b in balist) { b.CopyTo(ReturnBytes,offset); offset += b.Length; } return ReturnBytes; } public static PSObject AdaptProjection(Cmdlet myCmdlet, EnterpriseManagementObjectProjection p, string projectionName) { myCmdlet.WriteVerbose("Adapting " + p); /* * We can't just wrap a type projection because it is Enumerable. This means that we would only see the * components of the projection in the output so we have to construct this artificial wrapper. It would be easier if * projections weren't Enumerable, which means that PowerShell wouldn't treat a projection as a collection, or if * PowerShell understood that certain collections shouldn't be unspooled, but that's not how PowerShell works. * Neither of those two options are available, so we adapt the object and present a PSObject with all the component * parts. */ PSObject o = new PSObject(); o.Members.Add(new PSNoteProperty("__base", p)); o.Members.Add(new PSScriptMethod("GetAsXml", ScriptBlock.Create("[xml]($this.__base.CreateNavigator().OuterXml)"))); o.Members.Add(new PSNoteProperty("Object", AdaptManagementObject(myCmdlet, p.Object))); // Now promote all the properties on Object foreach (EnterpriseManagementSimpleObject so in p.Object.Values) { try { o.Members.Add(new PSNoteProperty(so.Type.Name, so.Value)); } catch { myCmdlet.WriteWarning("could not promote: " + so.Type.Name); } } o.TypeNames[0] = String.Format(CultureInfo.CurrentCulture, "EnterpriseManagementObjectProjection#{0}", projectionName); o.TypeNames.Insert(1, "EnterpriseManagementObjectProjection"); o.Members.Add(new PSNoteProperty("__ProjectionType", projectionName)); foreach (KeyValuePair<ManagementPackRelationshipEndpoint, IComposableProjection> helper in p) { // EnterpriseManagementObject myEMO = (EnterpriseManagementObject)helper.Value.Object; myCmdlet.WriteVerbose("Adapting related objects: " + helper.Key.Name); String myName = helper.Key.Name; PSObject adaptedEMO = AdaptManagementObject(myCmdlet, helper.Value.Object); // If the MaxCardinality is greater than one, it's definitely a collection // so start out that way if (helper.Key.MaxCardinality > 1) { // OK, this is a collection, so add the critter // This is so much easier in PowerShell if (o.Properties[myName] == null) { o.Members.Add(new PSNoteProperty(myName, new ArrayList())); } ((ArrayList)o.Properties[myName].Value).Add(adaptedEMO); } else { try { o.Members.Add(new PSNoteProperty(helper.Key.Name, adaptedEMO)); } catch (ExtendedTypeSystemException e) { myCmdlet.WriteVerbose("Readapting relationship object -> collection :" + e.Message); // We should really only get this exception if we // try to add a create a new property which already exists Object currentPropertyValue = o.Properties[myName].Value; ArrayList newValue = new ArrayList(); newValue.Add(currentPropertyValue); newValue.Add(adaptedEMO); o.Properties[myName].Value = newValue; // TODO // If this already exists, it should be converted to a collection } } } return o; } // Adapt the EnterpriseManagementObject // We need to do this because the interest bits of the EMO (from our perspective) // are in the values collection, we promote them to NoteProperties so displaying // the contents work better. This should really be done with a Type adapter, but // this is ok. public static PSObject AdaptManagementObject(Cmdlet myCmdlet, EnterpriseManagementObject managementObject) { PSObject PromotedObject = new PSObject(managementObject); PromotedObject.TypeNames.Insert(1, managementObject.GetType().FullName); PromotedObject.TypeNames[0] = String.Format(CultureInfo.CurrentCulture, "EnterpriseManagementObject#{0}",managementObject.GetLeastDerivedNonAbstractClass().Name); // loop through the properties and promote them into the PSObject we're going to return foreach ( ManagementPackProperty p in managementObject.GetProperties()) { try { if ( p.SystemType.ToString() == "System.IO.Stream" ) { if ( managementObject[p].Value != null ) { PSObject StreamObject = new PSObject(managementObject[p].Value); Byte[] Data = GetBytes(managementObject[p].Value as Stream); StreamObject.Members.Add(new PSNoteProperty("Data", Data)); PromotedObject.Members.Add(new PSNoteProperty(p.Name, StreamObject)); } else { PromotedObject.Members.Add(new PSNoteProperty(p.Name, new Byte[0])); } } else { PromotedObject.Members.Add(new PSNoteProperty(p.Name, managementObject[p].Value)); } } catch ( ExtendedTypeSystemException ets) { myCmdlet.WriteWarning(String.Format("The property '{0}' already exists, skipping.\nException: {1}", p.Name,ets.Message)); } catch ( Exception e ) { myCmdlet.WriteError(new ErrorRecord(e, "Property", ErrorCategory.NotSpecified, p.Name)); } } return PromotedObject; } // This overload is so we can call the adapter from the script layer // where we may not have a cmdlet reference. In the case of errors, we'll // just let it get thrown public static PSObject AdaptManagementObject(EnterpriseManagementObject managementObject) { PSObject PromotedObject = new PSObject(managementObject); PromotedObject.TypeNames.Insert(1, managementObject.GetType().FullName); PromotedObject.TypeNames[0] = String.Format(CultureInfo.CurrentCulture, "EnterpriseManagementObject#{0}",managementObject.GetLeastDerivedNonAbstractClass().Name); // loop through the properties and promote them into the PSObject we're going to return foreach ( ManagementPackProperty p in managementObject.GetProperties()) { try { if ( p.SystemType.ToString() == "System.IO.Stream" ) { if ( managementObject[p].Value != null ) { PSObject StreamObject = new PSObject(managementObject[p].Value); Byte[] Data = GetBytes(managementObject[p].Value as Stream); StreamObject.Members.Add(new PSNoteProperty("Data", Data)); PromotedObject.Members.Add(new PSNoteProperty(p.Name, StreamObject)); } else { PromotedObject.Members.Add(new PSNoteProperty(p.Name, new Byte[0])); } } else { PromotedObject.Members.Add(new PSNoteProperty(p.Name, managementObject[p].Value)); } } catch ( ExtendedTypeSystemException ets) { throw(new InvalidOperationException(String.Format("The property '{0}' already exists, skipping.\nException: {1}", p.Name,ets.Message))); } catch ( Exception e ) { throw(e); } } return PromotedObject; } private ServiceManagerObjectHelper() { ; } } #region SCSMObject cmdlets [Cmdlet(VerbsCommon.New, "SCSMObject", SupportsShouldProcess = true, DefaultParameterSetName = "name")] public class NewSMObjectCommand : ObjectCmdletHelper { private ManagementPackClass _class = null; [Parameter(Position = 0, Mandatory = true, ParameterSetName = "class")] public ManagementPackClass Class { get { return _class; } set { _class = value; } } private Hashtable _property; [Parameter(Position = 1, Mandatory = true, ValueFromPipeline = true)] public Hashtable PropertyHashtable { get { return _property; } set { _property = value; } } private ManagementPackObjectTemplate _template = null; [Parameter] public ManagementPackObjectTemplate Template { get { return _template; } set { _template = value; } } private SwitchParameter _passthru; [Parameter] public SwitchParameter PassThru { get { return _passthru; } set { _passthru = value; } } // On NoCommit, don't commit, just return // the created object. This is needed for those // operations that require that an instance not // already exist private SwitchParameter _noCommit; [Parameter] public SwitchParameter NoCommit { get { return _noCommit; } set { _noCommit = value; } } private IncrementalDiscoveryData pendingChanges; private int batchSize = 200; private int toCommit = 0; private SwitchParameter _bulk; [Parameter] public SwitchParameter Bulk { get { return _bulk; } set { _bulk = value; } } protected override void BeginProcessing() { base.BeginProcessing(); if (Bulk) { pendingChanges = new IncrementalDiscoveryData(); } if (Class == null) { ThrowTerminatingError(new ErrorRecord(new ArgumentNullException("Class"), "Class Not Found", ErrorCategory.ObjectNotFound, "Class")); } } // We're going to call commit for each object passed to us // TODO: Create an array of objects and commit them in // one operation protected override void ProcessRecord() { // Create an object CreatableEnterpriseManagementObject o = new CreatableEnterpriseManagementObject(_mg, Class); // Apply the template if needed if (Template != null) { o.ApplyTemplate(Template); } // Just to make things easier to deal with, we'll create a hash table of // the properties in the object. // // TODO: ADD GENERIC PROPERTIES // Create a hashtable of the properties, ignore case so if we find one // we can grab the property and assign the new value! Hashtable ht = new Hashtable(StringComparer.OrdinalIgnoreCase); foreach (ManagementPackProperty prop in o.GetProperties()) { try { ht.Add(prop.Name, prop); } catch ( Exception e ) { WriteError(new ErrorRecord(e, "property '" + prop.Name + "' has already been added to collection", ErrorCategory.InvalidOperation, prop)); } } // now go through the hashtable that has the values we we want to use and // assigned them into the new values foreach (string s in PropertyHashtable.Keys) { if (!ht.ContainsKey(s)) { WriteError(new ErrorRecord(new ObjectNotFoundException(s), "property not found on object", ErrorCategory.NotSpecified, o)); } else { ManagementPackProperty p = ht[s] as ManagementPackProperty; AssignNewValue(p, o[p], PropertyHashtable[s]); } } // Now that we're done, we can commit it // TODO: if we get an exception indicating we're disconnected // Reconnect and try again. if (ShouldProcess(Class.Name)) { try { if (Bulk) { toCommit++; pendingChanges.Add(o); if (toCommit >= batchSize) { toCommit = 0; pendingChanges.Commit(_mg); pendingChanges = new IncrementalDiscoveryData(); } } else { if (NoCommit) { WriteObject(o); } else { o.Commit(); // on PassThru get the ID and call GetObject // we don't want to hand back the CreatableEnterpriseObject, but rather the thing // that was saved. if (_passthru) { WriteObject( ServiceManagerObjectHelper.AdaptManagementObject( this, _mg.EntityObjects.GetObject<EnterpriseManagementObject>(o.Id, ObjectQueryOptions.Default) ) ); } } } } catch (Exception e) { WriteError(new ErrorRecord(e, "Could not save new object", ErrorCategory.InvalidOperation, o)); } } } protected override void EndProcessing() { base.EndProcessing(); if (Bulk) { try { pendingChanges.Commit(_mg); } catch (Exception e) { WriteWarning("Commit failed, trying Overwrite: " + e.Message); try { pendingChanges.Overwrite(_mg); } catch (Exception x) { WriteError(new ErrorRecord(x, "Could not save new object with commit or overwrite", ErrorCategory.InvalidOperation, pendingChanges)); } } } } } [Cmdlet(VerbsCommon.Get, "SCSMObject", DefaultParameterSetName = "Class")] public class GetSMObjectCommand : FilterCmdletBase { // Note: Four parameter sets so you can retrieve by class, guid or criteria private ManagementPackClass _class = null; [Parameter(ParameterSetName = "Class", Position = 0, Mandatory = true, ValueFromPipeline = true)] [Parameter(ParameterSetName = "Statistic", Mandatory = true, ValueFromPipeline = true)] public ManagementPackClass Class { get { return _class; } set { _class = value; } } private Guid _id = Guid.Empty; [Parameter(ParameterSetName = "Guid", Position = 0, Mandatory = true)] public Guid Id { get { return _id; } set { _id = value; } } private EnterpriseManagementObjectCriteria _criteria; [Parameter(ParameterSetName = "Criteria", Mandatory = true)] public EnterpriseManagementObjectCriteria Criteria { get { return _criteria; } set { _criteria = value; } } // If set, don't wrap the EMO private SwitchParameter _noAdapt; [Parameter] public SwitchParameter NoAdapt { get { return _noAdapt; } set { _noAdapt = value; } } // Only retrieve statistics private SwitchParameter _statistic; [Parameter(ParameterSetName = "Statistic")] public SwitchParameter Statistic { get { return _statistic; } set { _statistic = value; } } protected override void BeginProcessing() { base.BeginProcessing(); if (Statistic) { QueryOption = new ObjectQueryOptions(); QueryOption.DefaultPropertyRetrievalBehavior = ObjectPropertyRetrievalBehavior.None; QueryOption.ObjectRetrievalMode = ObjectRetrievalOptions.NonBuffered; return; } else { QueryOption = new ObjectQueryOptions(); QueryOption.DefaultPropertyRetrievalBehavior = ObjectPropertyRetrievalBehavior.All; if (MaxCount != Int32.MaxValue) { QueryOption.MaxResultCount = MaxCount; QueryOption.ObjectRetrievalMode = ObjectRetrievalOptions.NonBuffered; } } string sortProperty = SortBy; } protected override void ProcessRecord() { if (Id != Guid.Empty) { WriteObject(ServiceManagerObjectHelper.AdaptManagementObject(this, _mg.EntityObjects.GetObject<EnterpriseManagementObject>(Id, ObjectQueryOptions.Default))); return; } // If someone provides us a filter, we'll use that instead of a criteria if (Filter != null) { Criteria = ConvertFilterToObjectCriteria(Class, Filter); } if (Class == null && Criteria != null) { Class = Criteria.ManagementPackClass; } try { addSortProperty(QueryOption, SortBy, Class); } catch { ; } int count = 0; if (Criteria == null) // no criteria and no filter, get all the instances of the class { // If getting statistics, don't do anything if (Statistic) { WriteObject(new ItemStatistics(Class, Class.Name, _mg.EntityObjects.GetObjectReader<EnterpriseManagementObject>(Class, QueryOption).Count)); return; } else { foreach (EnterpriseManagementObject o in _mg.EntityObjects.GetObjectReader<EnterpriseManagementObject>(Class, QueryOption)) { count++; if (NoAdapt) { WriteObject(o); } else { WriteObject(ServiceManagerObjectHelper.AdaptManagementObject(this, o)); } if (count >= MaxCount) { break; } } } } else // OK, we got a criteria - we'll use that { if (Statistic) { WriteObject(new ItemStatistics(Class, Class.Name, _mg.EntityObjects.GetObjectReader<EnterpriseManagementObject>(Criteria, QueryOption).Count)); return; } foreach (EnterpriseManagementObject o in _mg.EntityObjects.GetObjectReader<EnterpriseManagementObject>(Criteria, QueryOption)) { count++; if (NoAdapt) { WriteObject(o); } else { WriteObject(ServiceManagerObjectHelper.AdaptManagementObject(this, o)); } if (count >= MaxCount) { break; } } } } } public enum Change { Property, Relationship, Instance }; public enum ChangeType { Modify, Insert, Delete }; public class PropertyChange { public Change WhatChanged; public ChangeType TypeOfChange; public string Name; public object OldValue; public object NewValue; public PropertyChange() { ; } public PropertyChange(Change type,ChangeType operation, string name, object oldval, object newval) { WhatChanged = type; TypeOfChange = operation; Name = name; OldValue = oldval; NewValue = newval; } } public class ObjectChange { public List<PropertyChange> Changes; public DateTime LastModified; public string UserName; public string Connector; public ObjectChange() { Changes = new List<PropertyChange>(); } } public class SCSMHistory { public EnterpriseManagementObject Instance; public List<ObjectChange> History; private List<EnterpriseManagementObjectHistoryTransaction> __HistoryData; public List<EnterpriseManagementObjectHistoryTransaction> get_RawHistoryData() { return this.__HistoryData; } private SCSMHistory() { History = new List<ObjectChange>(); __HistoryData = new List<EnterpriseManagementObjectHistoryTransaction>(); } public SCSMHistory(EnterpriseManagementObject emo) { History = new List<ObjectChange>(); __HistoryData = new List<EnterpriseManagementObjectHistoryTransaction>(); Instance = emo; foreach (EnterpriseManagementObjectHistoryTransaction ht in emo.ManagementGroup.EntityObjects.GetObjectHistoryTransactions(emo)) { __HistoryData.Add(ht); ObjectChange pc = new ObjectChange(); pc.LastModified = ht.DateOccurred.ToLocalTime(); pc.UserName = ht.UserName; pc.Connector = ht.ConnectorDisplayName; bool addToHistory = false; foreach (KeyValuePair<Guid, EnterpriseManagementObjectHistory> h in ht.ObjectHistory) { foreach (EnterpriseManagementObjectClassHistory ch in h.Value.ClassHistory) { foreach (KeyValuePair<ManagementPackProperty, Pair<EnterpriseManagementSimpleObject, EnterpriseManagementSimpleObject>> hpc in ch.PropertyChanges) { addToHistory = true; pc.Changes.Add(new PropertyChange(Change.Property, ChangeType.Modify, hpc.Key.DisplayName, hpc.Value.First, hpc.Value.Second)); } } foreach (EnterpriseManagementObjectRelationshipHistory rh in h.Value.RelationshipHistory) { addToHistory = true; ManagementPackRelationship mpr = emo.ManagementGroup.EntityTypes.GetRelationshipClass(rh.ManagementPackRelationshipTypeId); pc.Changes.Add(new PropertyChange(Change.Relationship, ChangeType.Modify, mpr.DisplayName, rh.SourceObjectId, rh.TargetObjectId)); } } if (addToHistory) { History.Add(pc); } } } } [Cmdlet(VerbsCommon.Get, "SCSMObjectHistory")] public class GetSCSMObjectHistoryCommand : ObjectCmdletHelper { private EnterpriseManagementObject[] _object; [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true)] public EnterpriseManagementObject[] Object { get { return _object; } set { _object = value; } } protected override void ProcessRecord() { foreach (EnterpriseManagementObject emo in Object) { WriteObject(new SCSMHistory(emo)); } } } [Cmdlet(VerbsCommon.Set,"SCSMObject", SupportsShouldProcess=true)] public class SetSMObjectCommand : ObjectCmdletHelper { // Set properties on an EMO // this takes a hashtable where the // KEY => PropertyName // VALUE => new value for the property // The adapted EMO private PSObject _smobject; [Parameter(Position=0,Mandatory=true,ValueFromPipeline=true)] public PSObject SMObject { set { _smobject = value; } get { return _smobject; } } // the property/value pairs private Hashtable _propertyValueHashTable; [Parameter(ParameterSetName="hashtable",Position=1,Mandatory=true)] [Alias("PH")] public Hashtable PropertyHashtable { get { return _propertyValueHashTable; } set { _propertyValueHashTable = value; } } // The following two parameters are a short-cut, // if you only want to set a single property // You don't need the hashtable private string _property; [Parameter(ParameterSetName="pair",Position=1,Mandatory=true)] public string Property { set { _property = value; } get { return _property; } } private List<Guid> objectList; private SwitchParameter _passThru; [Parameter] public SwitchParameter PassThru { get { return _passThru; } set { _passThru = value; } } private string _value; [Parameter(ParameterSetName="pair",Position=2,Mandatory=true)] [AllowEmptyString] [AllowNull] public string Value { set { _value = value; } get { return _value; } } // By default, we use IncrementalDiscoveryData to reduce the round // trips to the CMDB private SwitchParameter _noBulkOperation; [Parameter] public SwitchParameter NoBulkOperation { get { return _noBulkOperation; } set { _noBulkOperation = value; } } private IncrementalDiscoveryData pendingChanges; private Hashtable ht; protected override void BeginProcessing() { base.BeginProcessing(); objectList = new List<Guid>(); if ( ParameterSetName == "pair" ) { ht = new Hashtable(); ht.Add(Property,Value); } else { ht = new Hashtable(PropertyHashtable); } // if we're doing bulk operations, we'll need this if ( ! NoBulkOperation ) { pendingChanges = new IncrementalDiscoveryData(); } } protected override void ProcessRecord() { // EnterpriseManagementObject o = (EnterpriseManagementObject)SMObject.Members["__base"].Value; // Coerce the EnterpriseManagementObject o = (EnterpriseManagementObject)SMObject.BaseObject; AssignNewValues ( o, ht ); // If we're not doing bulk operations, we'll need to call this for each object if ( NoBulkOperation ) { if ( ShouldProcess("Commit Change for " + o.Id)) { o.Overwrite(); if ( PassThru ) { WriteObject(ServiceManagerObjectHelper.AdaptManagementObject(this, _mg.EntityObjects.GetObject<EnterpriseManagementObject>(o.Id, ObjectQueryOptions.Default))); } } } else { // One could argue that ShouldProcess is called here, // but to reduce verbosity, I do it below WriteVerbose("Adding " + o.Id + " to change list"); objectList.Add(o.Id); pendingChanges.Add(o); } } protected override void EndProcessing() { // If we're doing bulk operations if ( ! NoBulkOperation ) { if(ShouldProcess("SMObjects")) { pendingChanges.Overwrite(_mg); if(PassThru) { foreach(EnterpriseManagementObject emo in _mg.EntityObjects.GetObjectReader<EnterpriseManagementObject>(objectList, ObjectQueryOptions.Default)) { WriteObject(ServiceManagerObjectHelper.AdaptManagementObject(this, emo)); } } } } } } [Cmdlet(VerbsCommon.Remove, "SCSMObject", SupportsShouldProcess = true)] public class RemoveSMObjectCommand : ObjectCmdletHelper { // The adapted EMO private PSObject _smobject; [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true)] public PSObject SMObject { set { _smobject = value; } get { return _smobject; } } private SwitchParameter _force; [Parameter] public SwitchParameter Force { set { _force = value; } get { return _force; } } private SwitchParameter _progress; [Parameter] public SwitchParameter Progress { get { return _progress; } set { _progress = value; } } private ManagementPackEnumeration pendingDelete = null; // Remove is done via IncrementalDiscoveryData private IncrementalDiscoveryData idd; protected override void BeginProcessing() { base.BeginProcessing(); pendingDelete = _mg.ManagementPacks.GetManagementPack(SystemManagementPack.System).GetEnumeration("System.ConfigItem.ObjectStatusEnum.PendingDelete"); idd = new IncrementalDiscoveryData(); } protected override void ProcessRecord() { EnterpriseManagementObject orig = (EnterpriseManagementObject)SMObject.BaseObject; if (ShouldProcess(orig.Name)) { try { if (Progress) { WriteProgress(new ProgressRecord(0, "Remove Instance", orig.Name)); } if (Force) { idd.Remove(orig); } else { try { orig[null, "ObjectStatus"].Value = pendingDelete; idd.Add(orig); } catch (NullReferenceException e) { ErrorRecord er = new ErrorRecord(e, "ObjectStatus Property", ErrorCategory.ObjectNotFound, orig); ErrorDetails ed = new ErrorDetails("This object cannot be marked for deletion because it is not derived from System.ConfigItem"); ed.RecommendedAction = "Use the -Force parameter to remove this object"; er.ErrorDetails = ed; WriteError(er); } } } catch (Exception e) { WriteError(new ErrorRecord(e, "Object", ErrorCategory.NotSpecified, orig.Name)); } } } // after you've added all the instances to the incrementaldiscoverydata // commit the changes protected override void EndProcessing() { if (ShouldProcess("Commit")) { try { if (Progress) { WriteProgress(new ProgressRecord(0, "Remove Instance", "Committing Removal")); } idd.Commit(_mg); } catch (Exception e) { WriteError(new ErrorRecord(e, "Object", ErrorCategory.NotSpecified, "Commit")); } } } } #endregion #region SCSMRelationshipObject cmdlets [Cmdlet(VerbsCommon.Remove,"SCSMRelationshipObject", SupportsShouldProcess=true)] public class RemoveSMRelationshipObjectCommand : ObjectCmdletHelper { // The adapted EMO private PSObject _smobject; [Parameter(Position=0,Mandatory=true,ValueFromPipeline=true)] public PSObject SMObject { set { _smobject = value; } get { return _smobject; } } // Remove is done via IncrementalDiscoveryData private IncrementalDiscoveryData idd; protected override void BeginProcessing() { base.BeginProcessing(); // pendingDelete = _mg.ManagementPacks.GetManagementPack(SystemManagementPack.System).GetEnumeration("System.ConfigItem.ObjectStatusEnum.PendingDelete"); idd = new IncrementalDiscoveryData(); } protected override void ProcessRecord() { EnterpriseManagementRelationshipObject<EnterpriseManagementObject> orig = (EnterpriseManagementRelationshipObject<EnterpriseManagementObject>)SMObject.BaseObject; if ( ShouldProcess(orig.Id.ToString())) { try { idd.Remove(orig); } catch ( Exception e ) { WriteError(new ErrorRecord(e, "Object", ErrorCategory.NotSpecified, orig.Id)); } } } // after you've added all the instances to the incrementaldiscoverydata // commit the changes protected override void EndProcessing() { if ( ShouldProcess("Commit")) { try { idd.Commit(_mg); } catch ( Exception e ) { WriteError(new ErrorRecord(e, "Object", ErrorCategory.NotSpecified, "Commit")); } } } } [Cmdlet(VerbsCommon.New, "SCSMRelationshipObject", SupportsShouldProcess = true)] public class NewSCSMRelationshipObject : ObjectCmdletHelper { private ManagementPackRelationship _relationship; [Parameter(Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true)] public ManagementPackRelationship Relationship { get { return _relationship; } set { _relationship = value; } } private Hashtable _properties; [Parameter(Position = 3, ValueFromPipelineByPropertyName = true)] public Hashtable Properties { get { return _properties; } set { _properties = value; } } private SwitchParameter _passThru; [Parameter] public SwitchParameter PassThru { get { return _passThru; } set { _passThru = value; } } private EnterpriseManagementObject _source; [Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true)] public EnterpriseManagementObject Source { get { return _source; } set { _source = value; } } private EnterpriseManagementObject _target; [Parameter(Position = 2, Mandatory = true, ValueFromPipelineByPropertyName = true)] public EnterpriseManagementObject Target { get { return _target; } set { _target = value; } } private SwitchParameter _bulk; [Parameter(ParameterSetName = "bulk")] public SwitchParameter Bulk { get { return _bulk; } set { _bulk = value; } } private IncrementalDiscoveryData idd = null; private SwitchParameter _noCommit; [Parameter(ParameterSetName = "NoCommit")] public SwitchParameter NoCommit { get { return _noCommit; } set { _noCommit = value; } } private SwitchParameter _progress; [Parameter(ParameterSetName = "bulk")] public SwitchParameter Progress { get { return _progress; } set { _progress = value; } } protected override void BeginProcessing() { base.BeginProcessing(); if (Bulk) { idd = new IncrementalDiscoveryData(); } } private int count = 0; protected override void ProcessRecord() { CreatableEnterpriseManagementRelationshipObject ro = new Microsoft.EnterpriseManagement.Common.CreatableEnterpriseManagementRelationshipObject(_mg, Relationship); try { ro.SetSource(Source); } catch (Exception e) { ThrowTerminatingError(new ErrorRecord(e, "SourceError", ErrorCategory.InvalidOperation, ro)); } try { ro.SetTarget(Target); } catch (Exception e) { ThrowTerminatingError(new ErrorRecord(e, "TargetError", ErrorCategory.InvalidOperation, ro)); } IList<ManagementPackProperty> props = ro.GetProperties(); if (Properties != null) { foreach (string s in Properties.Keys) { try { WriteVerbose("looking for property " + s); foreach (ManagementPackProperty p in props) { if (String.Compare(p.Name, s, true) == 0) { WriteVerbose("Setting " + s + " to " + Properties[s]); AssignNewValue(p, ro[p], Properties[s]); // ro[p].Value = Properties[s]; break; } } } catch { WriteError(new ErrorRecord(new ItemNotFoundException(s), "Value " + s + " is null", ErrorCategory.ObjectNotFound, Properties)); } } } if (ShouldProcess("Commit changes")) { try { if (Bulk) { WriteVerbose("Adding " + ro.RelationshipId.ToString() + " to IDD"); if (Progress) { count++; WriteProgress(new ProgressRecord(1, "Adding to incremental discovery data", ro.TargetObject.DisplayName)); } idd.Add(ro); } else if (NoCommit) { WriteObject(ro); } else { ro.Commit(); } } catch (Exception e) { WriteError(new ErrorRecord(e, "Relationshipship Error", ErrorCategory.InvalidOperation, ro)); } } if (PassThru && !NoCommit) { WriteObject(ro); } // WriteObject(ro); } protected override void EndProcessing() { base.EndProcessing(); if (Bulk) { if (ShouldProcess("Commit Relationship Object")) { if (Progress) { WriteProgress(new ProgressRecord(1, "Committing Relationships", count + " instances")); } idd.Commit(_mg); } } } } #endregion #region SCSMObjectProjection cmdlets [Cmdlet(VerbsCommon.New, "SCSMObjectProjection", SupportsShouldProcess = true)] public class NewSCSMObjectProjectionCommand : ObjectCmdletHelper { private string _type = null; [Parameter(Mandatory = true, Position = 0)] public String Type { get { return _type; } set { _type = value; } } /* ** A projection is represented as a complicated hashtable which has the following layout ** @{ ** __CLASS = <classname of seed object> ** __OBJECT = @{ ** <property value pairs of seed object> ** } ** # ALIASNAME is the RELATIONSHIP alias as known by the projection ** ALIASNAME = @{ ** __CLASS = <classname of the object in the relationship> ** # this could be an array, but unlike the case of the seed object, ** # this object may already exist, so we have to support a combination ** # of EMOs or HashTables (for example, in an incident we may want to associate ** # a number of comment logs with the incident, but there's no reason that we shouldn't ** # create the comments in real time ** __OBJECT = EMO1,EMO2,@{ ** __CLASS = <classname of target> ** __OBJECT = @{ ** <property value pairs of target object ** } ** },EMO3,etc ** } ** } */ private Hashtable _projection = null; [Parameter(Mandatory = true, Position = 1, ValueFromPipeline = true)] public Hashtable Projection { get { return _projection; } set { _projection = value; } } private ManagementPackObjectTemplate _template; [Parameter] public ManagementPackObjectTemplate Template { get { return _template; } set { _template = value; } } private SwitchParameter _passThru; [Parameter] public SwitchParameter PassThru { get { return _passThru; } set { _passThru = value; } } private SwitchParameter _bulk; [Parameter] public SwitchParameter Bulk { get { return _bulk; } set { _bulk = value; } } private SwitchParameter _noCommit; [Parameter] public SwitchParameter NoCommit { get { return _noCommit; } set { _noCommit = value; } } private ManagementPackTypeProjection emop = null; private List<string> aliasCollection = null; private Hashtable aliasHT; private int count = 0; private int batchSize = 200; private IncrementalDiscoveryData pendingChanges; protected override void BeginProcessing() { base.BeginProcessing(); if (Bulk && !NoCommit) { pendingChanges = new IncrementalDiscoveryData(); } if (NoCommit) { Bulk = false; } // Find the projection we need Regex r = new Regex(Type, RegexOptions.IgnoreCase); foreach (ManagementPackTypeProjection p in _mg.EntityTypes.GetTypeProjections()) { if (r.Match(p.Name).Success) { emop = p; } } if (emop == null) { ThrowTerminatingError(new ErrorRecord(new ItemNotFoundException("Projection"), "No such projection", ErrorCategory.ObjectNotFound, Type)); } aliasHT = new Hashtable(); aliasCollection = new List<string>(); foreach (ManagementPackTypeProjectionComponent pc in emop.ComponentCollection) { aliasCollection.Add(pc.Alias); // Is there a way to handle SeedRole='Target' here? aliasHT.Add(pc.Alias, pc.TargetEndpoint); // WriteVerbose("Adding Alias: " + pc.Alias); } // WriteObject(aliasHT); } // emop guaranteed to be a valid projection type private EnterpriseManagementObjectProjection p = null; protected override void ProcessRecord() { if (Projection.ContainsKey("__SEED")) { // WriteVerbose("SEED"); if (Projection["__SEED"] is PSObject) { WriteVerbose("Seed is PSObject"); PSObject o = (PSObject)Projection["__SEED"]; WriteVerbose("Type of seed: " + o.GetType()); if (o.ImmediateBaseObject is EnterpriseManagementObject) { WriteVerbose("Attempting to cast"); EnterpriseManagementObject seed = (EnterpriseManagementObject)o.ImmediateBaseObject; WriteVerbose("Attempting to create projection"); WriteVerbose("Seed is a " + seed.GetType()); p = new EnterpriseManagementObjectProjection(seed); WriteVerbose("Created Projection"); } else { ThrowTerminatingError(new ErrorRecord(new NullReferenceException("Projection"), "Bad Projection", ErrorCategory.InvalidArgument, o)); } } else if (Projection["__SEED"] is EnterpriseManagementObject) { WriteVerbose("Seed is EMO"); EnterpriseManagementObject seed = (EnterpriseManagementObject)Projection["__SEED"]; p = new EnterpriseManagementObjectProjection(seed); } else { ThrowTerminatingError(new ErrorRecord(new NullReferenceException("Projection"), "Bad Projection", ErrorCategory.InvalidArgument, Projection["__SEED"])); } } else { // Construct the projection seed if (!Projection.ContainsKey("__CLASS")) { ThrowTerminatingError(new ErrorRecord(new ArgumentException("__CLASS"), "Hashtable Failure", ErrorCategory.InvalidArgument, Projection)); } // WriteVerbose("Seed Class is " + (string)Projection["__CLASS"]); ManagementPackClass c = getClassFromName((string)Projection["__CLASS"]); if (c == null) { ThrowTerminatingError(new ErrorRecord(new ItemNotFoundException("CLASS"), "No such class", ErrorCategory.ObjectNotFound, Projection["__CLASS"])); } if (!Projection.ContainsKey("__OBJECT")) { // WriteObject(Projection); // ThrowTerminatingError( new ErrorRecord(new ArgumentException("__OBJECT"), "Hashtable Failure", ErrorCategory.InvalidArgument, Projection)); WriteError(new ErrorRecord(new ArgumentException("__OBJECT"), "Hashtable Failure", ErrorCategory.InvalidArgument, Projection)); } // CreatableEnterpriseManagementObject cemo = new CreatableEnterpriseManagementObject(c.ManagementGroup,c); Hashtable seedHash = (Hashtable)Projection["__OBJECT"]; // WriteVerbose("__OBJECT is " + seedHash); p = new EnterpriseManagementObjectProjection(_mg, c); AssignNewValues(p.Object, seedHash); } WriteVerbose("Null Projection? " + (p == null).ToString()); // OK - the seed is now complete - so work on the rest of the projection. // go through the projection again - since hash tables are // TODO:: HANDLE CASE INSENSITIVE COMPARISON foreach (string k in Projection.Keys) { // skip the __CLASS (we did it above) if ( String.Compare(k, "__CLASS", true) == 0 || String.Compare(k, "__OBJECT", true) == 0 || String.Compare(k, "__SEED", true) == 0) { continue; } WriteVerbose("Hunting for key: " + k); if (aliasCollection.Contains(k)) { // WriteVerbose(">>>> setting up alias " + k); // TODO: Check the endpoint take the source or target endpoint where needed. ManagementPackRelationshipEndpoint endpoint = (ManagementPackRelationshipEndpoint)aliasHT[k]; // ok - we've got something that is pointed to by an alias if (Projection[k] is Array) { // WriteVerbose("**** inspecting array ****"); foreach (Object o in (Array)Projection[k]) { if (o is PSObject) { PSObject hashValue = (PSObject)o; // WriteVerbose(" PSObject is of type: " + ((PSObject)o).ImmediateBaseObject.GetType()); if (hashValue.ImmediateBaseObject is EnterpriseManagementObject) { try { // WriteVerbose(" Adding EMO to projection"); EnterpriseManagementObject target = (EnterpriseManagementObject)hashValue.ImmediateBaseObject; p.Add(target, endpoint); } catch (Exception e) { WriteError(new ErrorRecord(e, "Could not add EMO to projection", ErrorCategory.InvalidOperation, Projection[k])); } } else if (hashValue.ImmediateBaseObject is EnterpriseManagementObjectProjection) { try { // WriteVerbose(" Adding EMOP to projection"); EnterpriseManagementObjectProjection target = (EnterpriseManagementObjectProjection)hashValue.ImmediateBaseObject; p.Add(target, endpoint); } catch (Exception e) { WriteError(new ErrorRecord(e, "Could not add EMOP to projection", ErrorCategory.InvalidOperation, Projection[k])); } } } else if (o is Hashtable) { // WriteVerbose(" Subelement is hash, creating CEMO"); Hashtable v = (Hashtable)o; // WriteObject(v); CreatableEnterpriseManagementObject cEMO = MakecEMOFromHash(v); // WriteVerbose(" Adding cEMO to projection for " + k); p.Add(cEMO, endpoint); } else { // WriteVerbose(" Object is of type: " + o.GetType() + " IGNORING THIS OBJECT"); } } // WriteVerbose("**** Done inspecting array ****"); } else if (Projection[k] is EnterpriseManagementObject) { // WriteVerbose("Object is an EMO: " + Projection[k]); try { // WriteVerbose("Adding to projection"); p.Add((EnterpriseManagementObject)Projection[k], (ManagementPackRelationshipEndpoint)aliasHT[k]); } catch (Exception e) { WriteError(new ErrorRecord(e, "foo", ErrorCategory.InvalidOperation, Projection[k])); } } else if (Projection[k] is PSObject) { PSObject pso = (PSObject)Projection[k]; // WriteVerbose("PSObject ImmediateBase: " + pso.ImmediateBaseObject.GetType()); if (pso.ImmediateBaseObject is EnterpriseManagementObject) { EnterpriseManagementObject target = (EnterpriseManagementObject)pso.ImmediateBaseObject; try { // WriteVerbose("Adding " + target + " to projection as " + target); p.Add(target, endpoint); } catch (Exception e) { WriteError(new ErrorRecord(e, "foo", ErrorCategory.InvalidOperation, Projection[k])); } } } else if (Projection[k] is EnterpriseManagementObjectProjection) { // WriteVerbose("Object is an EMOP: " + Projection[k]); try { EnterpriseManagementObjectProjection target = (EnterpriseManagementObjectProjection)Projection[k]; p.Add(target, endpoint); } catch (Exception e) { WriteError(new ErrorRecord(e, "foo", ErrorCategory.InvalidOperation, Projection[k])); } } else if (Projection[k] is Hashtable) { // WriteVerbose("got a hashtable - will need to build EMO"); try { Hashtable relHash = (Hashtable)Projection[k]; CreatableEnterpriseManagementObject cEMO = MakecEMOFromHash(relHash); p.Add(cEMO, endpoint); } catch (Exception e) { WriteError(new ErrorRecord(e, "foo", ErrorCategory.InvalidOperation, Projection[k])); } // new CreatableEnterpriseManagementObject(_mg,mpc); } else if (Projection[k] == null) { WriteWarning("!!!! " + k + " value is null, ignoring"); } else { WriteVerbose("Got something strange : " + Projection[k].GetType()); } // WriteObject(emop[k]); // WriteObject(cEMO); // emop[k]; // now attach the object to the projection // p.Add(cEMO, k); // foreach(ManagementPackRelationship o in _mg.EntityTypes.GetRelationshipClasses()) // { // ok, we've got a match, so let's add the build and add the object // if ( String.Compare(o.Alias, k, true)) { p.Add(cEMO, o.Target); } // } } else { WriteError(new ErrorRecord(new ObjectNotFoundException(k), "Alias not found on projection", ErrorCategory.NotSpecified, k)); } } if (Template != null) { p.ApplyTemplate(Template); } // WriteObject(p); // WriteObject(emop); // WriteVerbose("So far so good!"); // WriteObject(p); // NoCommit is used in those cases where you need a projection // as an element of another projection if (ShouldProcess("projection batch")) { if (NoCommit) { WriteObject(p); } else if (Bulk) { WriteVerbose("!!!! Adding projection to IDD"); pendingChanges.Add(p); count++; if (count >= batchSize) { WriteVerbose("!!!! committing " + count + " projections"); pendingChanges.Commit(_mg); pendingChanges = new IncrementalDiscoveryData(); count = 0; } } else { try { p.Commit(); } catch (Exception e) { WriteError(new ErrorRecord(e, "projection commit failure", ErrorCategory.InvalidOperation, p)); } } } if (PassThru) { WriteObject(p); } } protected override void EndProcessing() { base.EndProcessing(); if (ShouldProcess("!!!! Commit last batch of " + count + " projections")) { if (Bulk && count > 0) { WriteVerbose("!!!! Committing last batch of " + count + " incidents"); pendingChanges.Commit(_mg); } } } private CreatableEnterpriseManagementObject MakecEMOFromHash(Hashtable ht) { ManagementPackClass mpc = getClassFromName((string)ht["__CLASS"]); WriteDebug("type of __OBJECT: " + ht["__OBJECT"].GetType().FullName); Hashtable relValues = (Hashtable)ht["__OBJECT"]; CreatableEnterpriseManagementObject cEMO = new CreatableEnterpriseManagementObject(_mg, mpc); WriteDebug("Created new cEMO based on " + mpc.Name); AssignNewValues(cEMO, relValues); return cEMO; } private ManagementPackClass getClassFromName(string name) { foreach (ManagementPackClass c in _mg.EntityTypes.GetClasses()) { if (String.Compare(name, c.Name, true) == 0) { return c; } } return null; } } [Cmdlet(VerbsCommon.Get, "SCSMObjectProjection", DefaultParameterSetName = "Wrapped")] public class GetSMObjectProjectionCommand : FilterCmdletBase { private PSObject _projectionObject; [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ParameterSetName = "Wrapped")] [Parameter(ParameterSetName = "Statistics", ValueFromPipeline = true, Mandatory = true)] public PSObject ProjectionObject { get { return _projectionObject; } set { _projectionObject = value; } } private ManagementPackTypeProjection _projection; [Parameter(Position = 0, Mandatory = true, ParameterSetName = "Raw", ValueFromPipeline = true)] public ManagementPackTypeProjection Projection { get { return _projection; } set { _projection = value; } } private string _projectionName = null; [Parameter(Position = 0, Mandatory = true, ParameterSetName = "Name")] public string ProjectionName { get { return _projectionName; } set { _projectionName = value; } } private ObjectProjectionCriteria _criteria = null; [Parameter(ParameterSetName = "Criteria", Mandatory = true)] public ObjectProjectionCriteria Criteria { get { return _criteria; } set { _criteria = value; } } private SwitchParameter _noSort; [Parameter] public SwitchParameter NoSort { get { return _noSort; } set { _noSort = value; } } private SwitchParameter _statistic; [Parameter(ParameterSetName = "Statistics", Mandatory = true)] public SwitchParameter Statistic { get { return _statistic; } set { _statistic = value; } } // This is used for instream projection // creation. needed for those projections whose // alias targets are themselves a projection // (such as ResolutionAndBillableLog // alias BillableLogs while requires a billabletime // and workeduponbyuser private SwitchParameter _noCommit; [Parameter] public SwitchParameter NoCommit { get { return _noCommit; } set { _noCommit = value; } } protected override void BeginProcessing() { base.BeginProcessing(); if (Statistic) { WriteDebug("Getting Statistics"); QueryOption = new ObjectQueryOptions(); QueryOption.DefaultPropertyRetrievalBehavior = ObjectPropertyRetrievalBehavior.None; QueryOption.ObjectRetrievalMode = ObjectRetrievalOptions.Buffered; return; } string sortProperty = SortBy; QueryOption = new ObjectQueryOptions(); QueryOption.DefaultPropertyRetrievalBehavior = ObjectPropertyRetrievalBehavior.All; QueryOption.ObjectRetrievalMode = ObjectRetrievalOptions.NonBuffered; if (MaxCount != Int32.MaxValue) { QueryOption.MaxResultCount = MaxCount; QueryOption.ObjectRetrievalMode = ObjectRetrievalOptions.NonBuffered; } if (ProjectionName != null) { foreach (ManagementPackTypeProjection p in _mg.EntityTypes.GetTypeProjections()) { if (String.Compare(p.Name, ProjectionName, StringComparison.CurrentCultureIgnoreCase) == 0) { Projection = p; break; } } if (Projection == null) { ThrowTerminatingError(new ErrorRecord(new ArgumentNullException("No Projection found"), "Need Projection", ErrorCategory.InvalidOperation, "projection")); } } // Only build the sortCriteria if the Projection is not null // Current architecture means that we can't sort if we pipe a TypeProjection // TODO: AddSortProperty to QueryOptions for each projection seen on the pipeline if (Projection != null && !NoSort) { WriteVerbose("Sort property is: " + sortProperty); // sort the results // string sortCriteria = String.Format("<Sorting {0}><GenericSortProperty SortOrder=\"{1}\">{2}</GenericSortProperty></Sorting>", xmlns, Order, pName); string sortCriteria = null; try { sortCriteria = makeSortCriteriaString(sortProperty, Projection.TargetType); WriteDebug("sorting criteria : " + sortCriteria); QueryOption.AddSortProperty(sortCriteria, Projection, _mg); } catch (Exception e) // It's not a failure { WriteError(new ErrorRecord(e, "Sort Failure", ErrorCategory.InvalidArgument, sortCriteria)); } } else { WriteDebug("Not Sorting"); } } private int count = 0; protected override void ProcessRecord() { ObjectProjectionCriteria myCriteria = null; // If we got a wrapped object, unwrap it if (ProjectionObject != null) { WriteDebug("unwrapping PSObject to get projection"); Projection = (ManagementPackTypeProjection)ProjectionObject.Properties["__base"].Value; } if (Statistic) { // Should this just be a call to get the seed? WriteVerbose("Getting Statistics"); WriteDebug("Before Criteria: " + DateTime.Now.ToString()); ObjectProjectionCriteria StatisticCriteria = new ObjectProjectionCriteria(Projection); WriteDebug("Before Reader: " + DateTime.Now.ToString()); IObjectProjectionReader<EnterpriseManagementObject> reader = _mg.EntityObjects.GetObjectProjectionReader<EnterpriseManagementObject>(StatisticCriteria, QueryOption); WriteDebug("After Reader: " + DateTime.Now.ToString()); WriteObject(new ItemStatistics(Projection, Projection.Name, reader.Count)); WriteDebug("After Reader.Count: " + DateTime.Now.ToString()); return; } // Create the criteria // first, by checking whether there's a filter (and no criteria) // This has to be created for each object in the pipeline because we may have gotten a // heterogenous collection of projections if (Criteria != null) { myCriteria = Criteria; } if (Filter != null && Criteria == null) { WriteDebug("converting filter to criteria"); myCriteria = ConvertFilterToProjectionCriteria(Projection, Filter); } // ok - neither criteria, nor filter was provided, build a criteria from the projection if (myCriteria == null) { WriteDebug("null criteria"); myCriteria = new ObjectProjectionCriteria(Projection); } QueryOption.ObjectRetrievalMode = ObjectRetrievalOptions.Buffered; // QueryOption.DefaultPropertyRetrievalBehavior = ObjectPropertyRetrievalBehavior.None; WriteDebug("Retrieval Mode: " + QueryOption.ObjectRetrievalMode.ToString()); WriteDebug("Before projectionReader: " + DateTime.Now.ToString()); IObjectProjectionReader<EnterpriseManagementObject> projectionReader = _mg.EntityObjects.GetObjectProjectionReader<EnterpriseManagementObject>(myCriteria, QueryOption); WriteDebug("After projectionReader: " + DateTime.Now.ToString() + " Count is :" + projectionReader.Count); // Set the page size to a small number to decrease initial time to results projectionReader.PageSize = 1; WriteDebug("MaxCount = " + projectionReader.MaxCount); WriteDebug("Enter foreach: " + DateTime.Now.ToString()); // while(projectionReader. // EnterpriseManagementObjectProjection p = projectionReader.First<EnterpriseManagementObjectProjection>(); // for(int i=0;i < 1; i++) foreach (EnterpriseManagementObjectProjection p in projectionReader) { count++; WriteDebug("Current count: " + count + " at " + DateTime.Now.ToString()); if (count > MaxCount) { break; } WriteVerbose("Adapting " + p); /* * We can't just wrap a type projection because it is Enumerable. This means that we would only see the * components of the projection in the output so we have to construct this artificial wrapper. It would be easier if * projections weren't Enumerable, which means that PowerShell wouldn't treat a projection as a collection, or if * PowerShell understood that certain collections shouldn't be unspooled, but that's not how PowerShell works. * Neither of those two options are available, so we adapt the object and present a PSObject with all the component * parts. */ PSObject o = new PSObject(); o.Members.Add(new PSNoteProperty("__base", p)); o.Members.Add(new PSScriptMethod("GetAsXml", ScriptBlock.Create("[xml]($this.__base.CreateNavigator().OuterXml)"))); o.Members.Add(new PSNoteProperty("Object", ServiceManagerObjectHelper.AdaptManagementObject(this, p.Object))); // Now promote all the properties on Object foreach (EnterpriseManagementSimpleObject so in p.Object.Values) { try { o.Members.Add(new PSNoteProperty(so.Type.Name, so.Value)); } catch { WriteWarning("could not promote: " + so.Type.Name); } } o.TypeNames[0] = String.Format(CultureInfo.CurrentCulture, "EnterpriseManagementObjectProjection#{0}", myCriteria.Projection.Name); o.TypeNames.Insert(1, "EnterpriseManagementObjectProjection"); o.Members.Add(new PSNoteProperty("__ProjectionType", myCriteria.Projection.Name)); foreach (KeyValuePair<ManagementPackRelationshipEndpoint, IComposableProjection> helper in p) { // EnterpriseManagementObject myEMO = (EnterpriseManagementObject)helper.Value.Object; WriteVerbose("Adapting related objects: " + helper.Key.Name); String myName = helper.Key.Name; PSObject adaptedEMO = ServiceManagerObjectHelper.AdaptManagementObject(this, helper.Value.Object); // If the MaxCardinality is greater than one, it's definitely a collection // so start out that way if (helper.Key.MaxCardinality > 1) { // OK, this is a collection, so add the critter // This is so much easier in PowerShell if (o.Properties[myName] == null) { o.Members.Add(new PSNoteProperty(myName, new ArrayList())); } ((ArrayList)o.Properties[myName].Value).Add(adaptedEMO); } else { try { o.Members.Add(new PSNoteProperty(helper.Key.Name, adaptedEMO)); } catch (ExtendedTypeSystemException e) { WriteVerbose("Readapting relationship object -> collection :" + e.Message); // We should really only get this exception if we // try to add a create a new property which already exists Object currentPropertyValue = o.Properties[myName].Value; ArrayList newValue = new ArrayList(); newValue.Add(currentPropertyValue); newValue.Add(adaptedEMO); o.Properties[myName].Value = newValue; // TODO // If this already exists, it should be converted to a collection } } } WriteObject(o); } } } [Cmdlet(VerbsCommon.Set, "SCSMObjectProjection", SupportsShouldProcess = true)] public class SetSCSMObjectProjectionCommand : ObjectCmdletHelper { private PSObject _projection = null; [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true)] public PSObject Projection { get { return _projection; } set { _projection = value; } } private Hashtable _propertyValues = null; [Parameter(Mandatory = true, Position = 1)] [Alias("ph")] public Hashtable PropertyValues { get { return _propertyValues; } set { _propertyValues = value; } } private SwitchParameter _passThru; [Parameter] public SwitchParameter PassThru { get { return _passThru; } set { _passThru = value; } } protected override void ProcessRecord() { EnterpriseManagementObjectProjection p = Projection.Members["__base"].Value as EnterpriseManagementObjectProjection; // EnterpriseManagementObject o = (EnterpriseManagementObject)SMObject.Members["__base"].Value; if (p != null) { EnterpriseManagementObject o = p.Object; // create a hashtable of management pack properties Hashtable ht = new Hashtable(StringComparer.OrdinalIgnoreCase); Hashtable valuesToUse = new Hashtable(StringComparer.OrdinalIgnoreCase); foreach (ManagementPackProperty prop in o.GetProperties()) { ht.Add(prop.Name, prop); } // TODO: Add support for relationships foreach (string s in PropertyValues.Keys) { if (!ht.ContainsKey(s)) { WriteError(new ErrorRecord(new ObjectNotFoundException(s), "property not found on object", ErrorCategory.NotSpecified, o)); } else { valuesToUse.Add(s, PropertyValues[s]); } } AssignNewValues(o, valuesToUse); if (ShouldProcess("Save changes to projection")) { p.Commit(); } if (PassThru) { WriteObject(p); } } else { WriteError(new ErrorRecord(new ArgumentException("SetProjection"), "object was not a projection", ErrorCategory.InvalidOperation, Projection)); } } } #endregion [Cmdlet(VerbsCommon.Get,"SCSMRelatedObject", DefaultParameterSetName="Wrapped")] public class GetSMRelatedObjectCommand : ObjectCmdletHelper { private EnterpriseManagementObject _smobject; [Parameter(Position=0,Mandatory=true,ValueFromPipeline=true,ParameterSetName="Wrapped")] public EnterpriseManagementObject SMObject { get { return _smobject; } set { _smobject = value; } } private ManagementPackRelationship _relationship; [Parameter] public ManagementPackRelationship Relationship { get { return _relationship; } set { _relationship = value; } } private TraversalDepth _depth = TraversalDepth.OneLevel; [Parameter] public TraversalDepth Depth { get { return _depth; } set { _depth = value; } } protected override void ProcessRecord() { if ( Relationship != null) { foreach(EnterpriseManagementObject o in _mg.EntityObjects.GetRelatedObjects<EnterpriseManagementObject>(SMObject.Id, Relationship, Depth, QueryOption)) { WriteObject(ServiceManagerObjectHelper.AdaptManagementObject(this, o)); } } else { foreach(EnterpriseManagementObject o in _mg.EntityObjects.GetRelatedObjects<EnterpriseManagementObject>(SMObject.Id, Depth, QueryOption)) { WriteObject(ServiceManagerObjectHelper.AdaptManagementObject(this, o)); } } } } [Cmdlet(VerbsCommon.Get, "SCSMRelationshipObject", DefaultParameterSetName="ID")] public class GetSCSMRelationshipObjectCommand : ObjectCmdletHelper { private Guid _id = Guid.Empty; [Parameter(Position = 0, ParameterSetName="ID", Mandatory = true)] public Guid Id { get { return _id; } set { _id = value; } } private ManagementPackRelationship[] _relationship = null; [Parameter(ParameterSetName="RELATIONSHIP",Mandatory=true,ValueFromPipeline=true,Position=0)] public ManagementPackRelationship[] Relationship { get { return _relationship; } set { _relationship = value; } } private ManagementPackRelationship _trelationship; [Parameter(ParameterSetName = "TARGETANDRELATIONSHIP", Mandatory = true)] public ManagementPackRelationship TargetRelationship { get { return _trelationship; } set { _trelationship = value; } } private ManagementPackClass _target = null; [Parameter(ParameterSetName="TARGET",Mandatory=true)] public ManagementPackClass Target { get { return _target; } set { _target = value; } } private ManagementPackClass _source = null; [Parameter(ParameterSetName="SOURCE",Mandatory=true)] public ManagementPackClass Source { get { return _source; } set { _source = value; } } private EnterpriseManagementObject _byTarget; [Parameter(ParameterSetName="TARGETOBJECT",Mandatory=true)] public EnterpriseManagementObject ByTarget { get { return _byTarget; } set { _byTarget = value; } } [Parameter(ParameterSetName = "TARGETANDRELATIONSHIP", Mandatory = true)] public EnterpriseManagementObject TargetObject { get { return _byTarget; } set { _byTarget = value; } } private EnterpriseManagementObject _bySource; [Parameter(ParameterSetName="SOURCEOBJECT",Mandatory=true)] public EnterpriseManagementObject BySource { get { return _bySource; } set { _bySource = value; } } private string _filter = null; [Parameter(ParameterSetName = "SOURCEOBJECT")] [Parameter(ParameterSetName = "TARGET")] [Parameter(ParameterSetName = "SOURCE")] [Parameter(ParameterSetName = "RELATIONSHIP")] [Parameter(ParameterSetName = "FILTER", Mandatory=true)] public string Filter { get { return _filter; } set { _filter = value; } } private enum QueryBy { TargetClass, SourceClass, Target, Source, Relationship, TargetAndRelationship }; #region GetRelationshipsHelper private IList<EnterpriseManagementRelationshipObject<EnterpriseManagementObject>> GetRelationshipObjects(ManagementPackRelationship r) { return GetRelationshipObjects(null, null, r, QueryBy.Relationship, null); } private IList<EnterpriseManagementRelationshipObject<EnterpriseManagementObject>> GetRelationshipObjects(ManagementPackRelationship r, string filter) { return GetRelationshipObjects(null, null, r, QueryBy.Relationship, filter); } private IList<EnterpriseManagementRelationshipObject<EnterpriseManagementObject>> GetRelationshipObjects(string filter) { return GetRelationshipObjects(null, null, null, QueryBy.Relationship, filter); } private IList<EnterpriseManagementRelationshipObject<EnterpriseManagementObject>> GetRelationshipObjects(ManagementPackClass c, QueryBy q) { return GetRelationshipObjects(c, null, null, q, null); } private IList<EnterpriseManagementRelationshipObject<EnterpriseManagementObject>> GetRelationshipObjects(ManagementPackClass c, QueryBy q, string filter) { return GetRelationshipObjects(c, null, null, q, filter); } private IList<EnterpriseManagementRelationshipObject<EnterpriseManagementObject>> GetRelationshipObjects(EnterpriseManagementObject emo, QueryBy q) { return GetRelationshipObjects(null, emo, null, q, null); } private IList<EnterpriseManagementRelationshipObject<EnterpriseManagementObject>> GetRelationshipObjects(EnterpriseManagementObject emo, QueryBy q, string filter) { return GetRelationshipObjects(null, emo, null, q, filter); } private IList<EnterpriseManagementRelationshipObject<EnterpriseManagementObject>> GetRelationshipObjects(EnterpriseManagementObject emo, ManagementPackRelationship r) { return GetRelationshipObjects(null, emo, r, QueryBy.TargetAndRelationship, null); } private IList<EnterpriseManagementRelationshipObject<EnterpriseManagementObject>> GetRelationshipObjects(ManagementPackClass classType, EnterpriseManagementObject emo, ManagementPackRelationship r, QueryBy q, string filter) { EnterpriseManagementRelationshipObjectGenericCriteria criteria = null; IList<EnterpriseManagementRelationshipObject<EnterpriseManagementObject>> Results = null; WriteVerbose("Retrieving Relationship Objects. QueryBy is:" + q.ToString() ); if (filter != null) { WriteVerbose(" Using Filter: " + filter); Regex re; foreach (string s in EnterpriseManagementRelationshipObjectGenericCriteria.GetValidPropertyNames()) { re = new Regex(s, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); filter = re.Replace(filter, s); } WriteVerbose(" After property name substitution: " + filter); try { string convertedFilter = ConvertFilterToGenericCriteria(filter); WriteVerbose(" Converted filter is: " + convertedFilter); criteria = new EnterpriseManagementRelationshipObjectGenericCriteria(convertedFilter); } catch (Exception e) { ThrowTerminatingError(new ErrorRecord(e, "CreateRelationshipCriteria", ErrorCategory.InvalidOperation, filter)); } } try { switch (q) { case QueryBy.TargetClass: { if (criteria != null) { Results = _mg.EntityObjects.GetRelationshipObjectsByTargetClass<EnterpriseManagementObject>(criteria, classType, ObjectQueryOptions.Default); } else { Results = _mg.EntityObjects.GetRelationshipObjectsByTargetClass<EnterpriseManagementObject>(classType, ObjectQueryOptions.Default); } break; } case QueryBy.SourceClass: { if (criteria != null) { Results = _mg.EntityObjects.GetRelationshipObjectsBySourceClass<EnterpriseManagementObject>(criteria, classType, ObjectQueryOptions.Default); } else { Results = _mg.EntityObjects.GetRelationshipObjectsBySourceClass<EnterpriseManagementObject>(classType, ObjectQueryOptions.Default); } break; } case QueryBy.Target: { Results = _mg.EntityObjects.GetRelationshipObjectsWhereTarget<EnterpriseManagementObject>(emo.Id, ObjectQueryOptions.Default); break; } case QueryBy.TargetAndRelationship: { Results = _mg.EntityObjects.GetRelationshipObjectsWhereTarget<EnterpriseManagementObject>(emo.Id, r, DerivedClassTraversalDepth.Recursive, TraversalDepth.OneLevel, ObjectQueryOptions.Default); break; } case QueryBy.Source: { if (criteria != null) { Results = _mg.EntityObjects.GetRelationshipObjectsWhereSource<EnterpriseManagementObject>(emo.Id, criteria, TraversalDepth.Recursive, ObjectQueryOptions.Default); } else { Results = _mg.EntityObjects.GetRelationshipObjectsWhereSource<EnterpriseManagementObject>(emo.Id, TraversalDepth.Recursive, ObjectQueryOptions.Default); } break; } case QueryBy.Relationship: { if (criteria != null) { WriteVerbose("Relationship with criteria"); Results = _mg.EntityObjects.GetRelationshipObjects<EnterpriseManagementObject>(criteria, ObjectQueryOptions.Default); } else { Results = _mg.EntityObjects.GetRelationshipObjects<EnterpriseManagementObject>(r, DerivedClassTraversalDepth.Recursive, ObjectQueryOptions.Default); WriteVerbose("Relationship via r: " + r.Id.ToString() + ". Count = " + Results.Count.ToString()); } break; } default: { ThrowTerminatingError(new ErrorRecord(new InvalidOperationException("No relationship query type specified"), "BadRelationshipQueryRequest", ErrorCategory.InvalidOperation, this)); break; } } } catch (Exception e) { ThrowTerminatingError(new ErrorRecord(e, "RelationshipQuery", ErrorCategory.InvalidOperation, this)); } foreach (EnterpriseManagementRelationshipObject<EnterpriseManagementObject> o in Results) { WriteVerbose("ID: " + o.Id.ToString()); } return Results; } #endregion GetRelationshipHelper protected override void ProcessRecord() { if ( this.ParameterSetName == "TARGET" ) { WriteObject(GetRelationshipObjects(Target, QueryBy.Target, Filter), true); } else if ( this.ParameterSetName == "RELATIONSHIP" ) { foreach (ManagementPackRelationship r in Relationship) { WriteObject(GetRelationshipObjects(r, Filter), true); } } else if ( this.ParameterSetName == "SOURCE" ) { WriteObject(GetRelationshipObjects(Source, QueryBy.Source, Filter), true); } else if ( this.ParameterSetName == "TARGETOBJECT" ) { WriteObject(GetRelationshipObjects(ByTarget, QueryBy.Target), true); } else if (this.ParameterSetName == "TARGETANDRELATIONSHIP") { WriteObject(GetRelationshipObjects(TargetObject, TargetRelationship)); } else if (this.ParameterSetName == "SOURCEOBJECT") { WriteObject(GetRelationshipObjects(BySource, QueryBy.Source, Filter), true); } else if (this.ParameterSetName == "FILTER") { WriteObject(GetRelationshipObjects(Filter), true); } else { WriteObject(_mg.EntityObjects.GetRelationshipObject<EnterpriseManagementObject>(Id, ObjectQueryOptions.Default)); WriteVerbose("By Id: " + Id.ToString()); } } } [Cmdlet(VerbsCommon.Get, "SCSMConfigItem", SupportsShouldProcess = true)] public class SCSMConfigItemGet : SMCmdletBase { private String _DisplayName = null; private String _TargetProjection = "8ab27adb-13b1-2b7b-56e6-91598417cbee"; [Parameter(Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The display name of the config item.")] [ValidateNotNullOrEmpty] public string DisplayName { get { return _DisplayName; } set { _DisplayName = value; } } [Parameter(Position = 1, Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "The display name of the config item.")] [ValidateNotNullOrEmpty] public string TargetProjection { get { return _TargetProjection; } set { _TargetProjection = value; } } protected override void ProcessRecord() { ManagementPackTypeProjection targetProjection = _mg.EntityTypes.GetTypeProjection(new Guid(TargetProjection)); ManagementPack trgProjMp = targetProjection.GetManagementPack(); ManagementPack systemMp = _mg.ManagementPacks.GetManagementPack(SystemManagementPack.System); WriteVerbose("Starting to build search criteria..."); List<string> criterias = new List<string>(); // Define the query criteria string. // This is XML that validates against the Microsoft.EnterpriseManagement.Core.Criteria schema. StringBuilder configCriteria = new StringBuilder(String.Format(@" <Criteria xmlns=""http://Microsoft.EnterpriseManagement.Core.Criteria/""> <Reference Id=""System.Library"" PublicKeyToken=""{0}"" Version=""{1}"" Alias=""targetMp"" /> <Expression>", systemMp.KeyToken, systemMp.Version.ToString())); if (this._DisplayName != null) { WriteVerbose(string.Format("Adding \"DisplayName like {0}\" to search criteria", this.DisplayName)); criterias.Add(@"<SimpleExpression> <ValueExpressionLeft> <Property>$Context/Property[Type='targetMp!System.ConfigItem']/DisplayName$</Property> </ValueExpressionLeft> <Operator>Like</Operator> <ValueExpressionRight> <Value>" + this.DisplayName + @"</Value> </ValueExpressionRight> </SimpleExpression>"); } if (criterias.Count > 1) { for (int i = 0; i < criterias.Count; i++) { criterias[i] = "<Expression>" + criterias[i] + "</Expression>"; } } if (criterias.Count > 1) { configCriteria.AppendLine("<And>"); } foreach (var item in criterias) { configCriteria.AppendLine(item); } if (criterias.Count > 1) { configCriteria.AppendLine("</And>"); } configCriteria.AppendLine(@"</Expression> </Criteria>"); WriteDebug("Search criteria: " + configCriteria.ToString()); // Define the criteria object by using one of the criteria strings. ObjectProjectionCriteria criteria = new ObjectProjectionCriteria(configCriteria.ToString(), targetProjection, _mg); // For each retrieved type projection, display the properties. List<EnterpriseManagementObjectProjection> result = new List<EnterpriseManagementObjectProjection>(); foreach (EnterpriseManagementObjectProjection projection in _mg.EntityObjects.GetObjectProjectionReader<EnterpriseManagementObject>(criteria, ObjectQueryOptions.Default)) { WriteVerbose(String.Format("Adding config item \"{0}\" to the pipeline", projection.Object.DisplayName)); WriteObject(projection, false); } } } } |