public OpenImportConnectionResults OpenImportConnection(System.Collections.ObjectModel.KeyedCollection <string, ConfigParameter> configParameters, Schema types, OpenImportConnectionRunStep openImportRunStep) { Tracer.Enter("openimportconnection"); try { Tracer.TraceInformation("getting-schema"); try { foreach (SchemaType type in types.Types) { foreach (SchemaAttribute attr in type.AnchorAttributes) { //Tracer.TraceInformation("{0}-anchor-attribute {1} [{2}]", type.Name, attr.Name, attr.DataType); objectTypeAnchorAttributeNames.Add(type.Name, attr.Name); } foreach (SchemaAttribute attr in type.Attributes) { //Tracer.TraceInformation("{0}-attribute {1} [{2}]", type.Name, attr.Name, attr.DataType); } } InitializeSchemaVariables(types); } catch (Exception ex) { Tracer.TraceError("getting-schema", ex); } finally { Tracer.TraceInformation("got-schema"); } InitializeConfigParameters(configParameters); //SetupImpersonationToken(); OpenRunspace(); Tracer.TraceInformation("resetting-pipeline-results-and-counters"); importResults = new List <PSObject>(); pageToken = ""; OpenImportConnectionResults oicr = new OpenImportConnectionResults(); ImportRunStepPageSize = openImportRunStep.PageSize; Tracer.TraceInformation("openimportrunstep-pagesize '{0}'", ImportRunStepPageSize); oicr.CustomData = openImportRunStep.ImportType == OperationType.Full ? "" : openImportRunStep.CustomData; Tracer.TraceInformation("openimportrunstep-customdata '{0}'", oicr.CustomData); importOperationType = openImportRunStep.ImportType; Tracer.TraceInformation("openimportrunstep-importtype '{0}'", importOperationType); return(oicr); } catch (Exception ex) { Tracer.TraceError("openimportconnection", ex); throw; } finally { Tracer.Exit("openimportconnection"); } }
public GetImportEntriesResults GetImportEntries(GetImportEntriesRunStep importRunStep) { Tracer.Enter("getimportentries"); try { #region call import script // if results is null, then this is the first time that we're called, // so call script and get pipeline object and custom data Tracer.TraceInformation("more-to-import '{0}'", MoreToImport); if (MoreToImport) { MoreToImport = false; // make sure we set more-to-import to false; could be overwritten further down if pagedimports is true, though // on first call, we set customdata to value from last successful run returnedCustomData = importRunStep.CustomData; Command cmd = new Command(Path.GetFullPath(ImportScript)); cmd.Parameters.Add(new CommandParameter("User", Username)); cmd.Parameters.Add(new CommandParameter("Password", Password)); cmd.Parameters.Add(new CommandParameter("Credentials", GetSecureCredentials())); cmd.Parameters.Add(new CommandParameter("OperationType", importOperationType.ToString())); cmd.Parameters.Add(new CommandParameter("UsePagedImport", UsePagedImport)); cmd.Parameters.Add(new CommandParameter("PageSize", ImportRunStepPageSize)); cmd.Parameters.Add(new CommandParameter("Schema", schemaPSObject)); Tracer.TraceInformation("setting-custom-data '{0}'", importRunStep.CustomData); powershell.Runspace.SessionStateProxy.SetVariable("RunStepCustomData", importRunStep.CustomData); Tracer.TraceInformation("setting-page-token '{0}'", pageToken); powershell.Runspace.SessionStateProxy.SetVariable("PageToken", pageToken); importResults = InvokePowerShellScript(cmd, null).ToList <PSObject>(); returnedCustomData = powershell.Runspace.SessionStateProxy.GetVariable("RunStepCustomData"); pageToken = powershell.Runspace.SessionStateProxy.GetVariable("PageToken"); Tracer.TraceInformation("page-token-returned '{0}'", pageToken == null ? "(null)" : pageToken); Tracer.TraceInformation("custom-data returned '{0}'", returnedCustomData); Tracer.TraceInformation("number-of-object(s)-in-pipeline {0:n0}", importResults.Count); if (UsePagedImport) { // Tracer.TraceError("paged-import-not-supported-currently"); object moreToImportObject = powershell.Runspace.SessionStateProxy.GetVariable("MoreToImport"); if (moreToImportObject == null) { Tracer.TraceError("For paged imports, the global variable 'MoreToImport' must be set to 'true' or 'false'"); } else { Tracer.TraceInformation("MoreToImport-value-returned '{0}'", moreToImportObject); if (bool.TryParse(moreToImportObject == null ? bool.FalseString : moreToImportObject.ToString(), out MoreToImport)) { Tracer.TraceInformation("paged-import-setting-MoreToImport-to '{0}'", MoreToImport); } else { Tracer.TraceError("Value returned in MoreToImport must be a boolean with value of 'true' or 'false'"); } } } else { MoreToImport = false; Tracer.TraceInformation("non-paged-import-setting-MoreToImport-to '{0}'", MoreToImport); } } #endregion #region parse returned objects if (importResults != null && importResults.Count > 0) { List <PSObject> importResultsBatch = importResults.Take(ImportRunStepPageSize).ToList(); if (importResults.Count > ImportRunStepPageSize) { importResults.RemoveRange(0, importResultsBatch.Count); } else { importResults.Clear(); } Tracer.TraceInformation("converting-objects-to-csentrychange {0:n0}", importResultsBatch.Count); foreach (PSObject obj in importResultsBatch) { HashSet <AttributeDefinition> attrs = new HashSet <AttributeDefinition>(); Tracer.TraceInformation("start-connector-space-object"); try { CSEntryChange csobject = CSEntryChange.Create(); if (obj.BaseObject.GetType() != typeof(System.Collections.Hashtable)) { Tracer.TraceWarning("invalid-object-in-pipeline '{0}'", 1, obj.BaseObject.GetType()); continue; } object AnchorValue = null; string AnchorAttributeName = null; string objectDN = null; string objectClass = ""; // should be string to prevent null exceptions string changeType = null; string ErrorName = null; string ErrorDetail = null; MAImportError ImportErrorType = MAImportError.Success; // assume no error Hashtable hashTable = (Hashtable)obj.BaseObject; #region get control values Tracer.TraceInformation("start-getting-control-values"); foreach (string key in hashTable.Keys) { if (key.Equals(Constants.ControlValues.ObjectClass, StringComparison.OrdinalIgnoreCase) || key.Equals(Constants.ControlValues.ObjectClassEx, StringComparison.OrdinalIgnoreCase)) { objectClass = (string)hashTable[key]; Tracer.TraceInformation("got-objectclass {0}, {1}", objectClass, key); continue; } if (key.Equals(Constants.ControlValues.DN, StringComparison.OrdinalIgnoreCase)) { objectDN = (string)hashTable[key]; Tracer.TraceInformation("got-dn {0}, {1}", objectDN, key); continue; } if (key.Equals(Constants.ControlValues.ChangeType, StringComparison.OrdinalIgnoreCase) || key.Equals(Constants.ControlValues.ChangeTypeEx, StringComparison.OrdinalIgnoreCase)) { changeType = (string)hashTable[key]; Tracer.TraceInformation("got-changetype {0}, {1}", changeType, key); continue; } if (key.Equals(Constants.ControlValues.ErrorName, StringComparison.OrdinalIgnoreCase)) { ErrorName = (string)hashTable[key]; Tracer.TraceInformation("got-errorname {0}, {1}", ErrorName, key); continue; } if (key.Equals(Constants.ControlValues.ErrorDetail, StringComparison.OrdinalIgnoreCase)) { ErrorDetail = (string)hashTable[key]; Tracer.TraceInformation("got-errordetail {0}, {1}", ErrorDetail, key); continue; } } if (string.IsNullOrEmpty(objectClass)) { Tracer.TraceError("missing-objectclass"); ImportErrorType = MAImportError.ImportErrorCustomContinueRun; ErrorName = "missing-objectclass-value"; ErrorDetail = "No value provided for objectclass attribute"; } else { AnchorAttributeName = objectTypeAnchorAttributeNames[objectClass] == null ? "" : (string)objectTypeAnchorAttributeNames[objectClass]; if (string.IsNullOrEmpty(AnchorAttributeName)) { ImportErrorType = MAImportError.ImportErrorInvalidAttributeValue; ErrorName = "invalid-objecttype"; ErrorDetail = "Objecttype not defined in schema"; } foreach (string key in hashTable.Keys) { if (key.Equals(AnchorAttributeName, StringComparison.OrdinalIgnoreCase)) { AnchorValue = hashTable[key]; Tracer.TraceInformation("got-anchor {0}, {1}", AnchorValue, key); break; } } } Tracer.TraceInformation("end-getting-control-values"); if (AnchorValue == null) { Tracer.TraceError("missing-anchor"); ImportErrorType = MAImportError.ImportErrorCustomContinueRun; ErrorName = "missing-anchor-value"; ErrorDetail = "No value provided for anchor attribute"; } if (AnchorValue != null && string.IsNullOrEmpty(objectDN)) { Tracer.TraceInformation("setting-anchor-as-dn {0}", AnchorValue); objectDN = AnchorValue.ToString(); } if (!string.IsNullOrEmpty(ErrorName)) { ImportErrorType = MAImportError.ImportErrorCustomContinueRun; if (string.IsNullOrEmpty(ErrorDetail)) { ErrorDetail = "No error details provided"; } } #endregion control values #region return invalid object if (ImportErrorType != MAImportError.Success) { Tracer.TraceInformation("returning-invalid-object"); if (AnchorValue != null) { csobject.AnchorAttributes.Add(AnchorAttribute.Create(AnchorAttributeName, AnchorValue)); } csobject.ObjectModificationType = ObjectModificationType.Add; if (!string.IsNullOrEmpty(objectClass)) { try { csobject.ObjectType = objectClass; } catch (NoSuchObjectTypeException otEx) { Tracer.TraceError("no-such-object '{0}'", otEx); } } if (!string.IsNullOrEmpty(objectClass)) { csobject.DN = objectDN; } Tracer.TraceError("invalid-object dn: {0}, type: {1}, name: {2}, details: {3} ", objectDN, ImportErrorType, ErrorName, ErrorDetail); csobject.ErrorCodeImport = ImportErrorType; csobject.ErrorName = ErrorName; csobject.ErrorDetail = ErrorDetail; csentryqueue.Add(csobject); continue; } #endregion #region return deleted object // we must set ObjectModificationType before any other attributes; otherwise it will default to 'Add' if (!string.IsNullOrEmpty(changeType) && changeType.Equals("delete", StringComparison.OrdinalIgnoreCase)) { Tracer.TraceInformation("returning-deleted-object"); Tracer.TraceInformation("change-type {0}", changeType); csobject.ObjectModificationType = ObjectModificationType.Delete; csobject.ObjectType = objectClass; csobject.DN = objectDN; // we need to get the object anchor value for the deletion csobject.AnchorAttributes.Add(AnchorAttribute.Create(AnchorAttributeName, AnchorValue)); csentryqueue.Add(csobject); continue; } #endregion #region returned live object Tracer.TraceInformation("returning-valid-object"); csobject.ObjectModificationType = ObjectModificationType.Add; csobject.ObjectType = objectClass; csobject.DN = objectDN; csobject.AnchorAttributes.Add(AnchorAttribute.Create(AnchorAttributeName, AnchorValue)); foreach (string key in hashTable.Keys) { try { if (Regex.IsMatch(key, string.Format(@"^(objectClass|\[objectclass\]|changeType|\[changetype\]|\[DN\]|\[ErrorName\]|\[ErrorDetail\]|{0})$", AnchorAttributeName), RegexOptions.Compiled | RegexOptions.IgnoreCase)) { Tracer.TraceInformation("skip-control-value {0}", key); continue; } if (hashTable[key] == null) { Tracer.TraceInformation("skip-null-value-for '{0}'", key); continue; } SchemaAttribute sa = schema.Types[objectClass].Attributes[key]; Tracer.TraceInformation("attribute: {0} (type {1}, {2}): '{3}'", key, sa.DataType, sa.IsMultiValued ? "multi-value" : "single-value", hashTable[key]); if (sa.IsMultiValued) { //Tracer.TraceInformation("add-multivalue '{0}' [{1}]", key, hashTable[key].GetType()); List <object> mvs = new List <object>(); if (hashTable[key].ToString().EndsWith("[]")) { mvs.AddRange((object[])hashTable[key]); } else { mvs.Add(hashTable[key]); } csobject.AttributeChanges.Add(AttributeChange.CreateAttributeAdd(key, mvs)); } else { csobject.AttributeChanges.Add(AttributeChange.CreateAttributeAdd(key, hashTable[key])); } } catch (KeyNotFoundException keyexception) { Tracer.TraceError("attribute-is-not-defined-for '{0}' / '{1}' ({2})", key, objectClass, keyexception.ToString()); } } #endregion if (csobject.ErrorCodeImport != MAImportError.Success) { Tracer.TraceError("defective-csentrychange id: {0}, dn: {1}, errorcode: {2}, error: {3}, details: {4}", csobject.Identifier, csobject.DN, csobject.ErrorCodeImport, csobject.ErrorName, csobject.ErrorDetail); } Tracer.TraceInformation("returning-csentry dn: {0}, id: {1}", csobject.DN, csobject.Identifier); csentryqueue.Add(csobject); } catch (Exception ex) { Tracer.TraceError("creating-csentrychange", ex); } finally { Tracer.TraceInformation("end-connector-space-object"); } } // clearing results for next loop importResultsBatch.Clear(); } #endregion #region dequeue csentries GetImportEntriesResults importReturnInfo = null; Tracer.TraceInformation("total-import-object(s)-left {0:n0}", importResults.Count); Tracer.TraceInformation("total-connector-space-object(s)-left {0:n0}", csentryqueue.Count); List <CSEntryChange> batch = csentryqueue.Take(ImportRunStepPageSize).ToList(); if (csentryqueue.Count > ImportRunStepPageSize) { csentryqueue.RemoveRange(0, batch.Count); } else { csentryqueue.Clear(); } importReturnInfo = new GetImportEntriesResults(); importReturnInfo.MoreToImport = MoreToImport || importResults.Count > 0 || (csentryqueue.Count > 0); importReturnInfo.CustomData = returnedCustomData == null ? "" : returnedCustomData.ToString(); importReturnInfo.CSEntries = batch; Tracer.TraceInformation("should-return-for-more {0}", importReturnInfo.MoreToImport); Tracer.TraceInformation("custom-data '{0}'", importReturnInfo.CustomData); Tracer.TraceInformation("connector-space-object(s)-returned {0:n0}", importReturnInfo.CSEntries.Count); return(importReturnInfo); #endregion } catch (Exception ex) { Tracer.TraceError("getimportentries", ex); throw; } finally { Tracer.Exit("getimportentries"); } }
Schema IMAExtensible2GetSchema.GetSchema(KeyedCollection <string, ConfigParameter> configParameters) { Tracer.Enter("getschema"); try { Schema schema = Schema.Create(); InitializeConfigParameters(configParameters); OpenRunspace(); Command cmd = new Command(Path.GetFullPath(SchemaScript)); cmd.Parameters.Add(new CommandParameter("Username", Username)); cmd.Parameters.Add(new CommandParameter("Password", Password)); cmd.Parameters.Add(new CommandParameter("ClientId", ClientId)); cmd.Parameters.Add(new CommandParameter("Secret", Secret)); cmd.Parameters.Add(new CommandParameter("Credentials", GetSecureCredentials())); cmd.Parameters.Add(new CommandParameter("ClientCredentials", GetSecureClientCredentials())); schemaResults = InvokePowerShellScript(cmd, null); CloseRunspace(); if (schemaResults != null) { foreach (PSObject obj in schemaResults) { string objectTypeName = null; HashSet <AttributeDefinition> attrs = new HashSet <AttributeDefinition>(); foreach (PSPropertyInfo p in obj.Properties) { string[] elements = p.Name.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries); string attrName = elements[0].Trim(); string attrType = elements[1].Trim(); if (string.Equals(attrName, Constants.ControlValues.ObjectClass, StringComparison.OrdinalIgnoreCase)) { objectTypeName = p.Value.ToString(); Tracer.TraceInformation("object-class '{0}'", objectTypeName); } else { AttributeDefinition ad = new AttributeDefinition(); ad.Name = Regex.Replace(attrName, "^Anchor-", "", RegexOptions.IgnoreCase); ad.IsAnchor = p.Name.StartsWith("anchor-", StringComparison.OrdinalIgnoreCase); ad.IsMultiValue = p.Name.EndsWith("[]", StringComparison.OrdinalIgnoreCase); switch (attrType.Replace("[]", "").ToLower()) { case "boolean": ad.Type = AttributeType.Boolean; break; case "binary": ad.Type = AttributeType.Binary; break; case "integer": ad.Type = AttributeType.Integer; break; case "reference": ad.Type = AttributeType.Reference; break; case "string": ad.Type = AttributeType.String; break; default: ad.Type = AttributeType.String; break; } Tracer.TraceInformation("name '{0}', isanchor: {1}, ismultivalue: {2}, type: {3}", ad.Name, ad.IsAnchor, ad.IsMultiValue, ad.Type.ToString()); attrs.Add(ad); } } if (string.IsNullOrEmpty(objectTypeName)) { Tracer.TraceError("missing-object-class"); throw new Microsoft.MetadirectoryServices.NoSuchObjectTypeException(); } SchemaType objectClass = SchemaType.Create(objectTypeName, true); foreach (AttributeDefinition def in attrs) { if (def.IsAnchor) { objectClass.Attributes.Add(SchemaAttribute.CreateAnchorAttribute(def.Name, def.Type)); } else { if (def.IsMultiValue) { objectClass.Attributes.Add(SchemaAttribute.CreateMultiValuedAttribute(def.Name, def.Type)); } else { objectClass.Attributes.Add(SchemaAttribute.CreateSingleValuedAttribute(def.Name, def.Type)); } } } if (objectClass.AnchorAttributes.Count == 1) { schema.Types.Add(objectClass); } else { Tracer.TraceError("missing-anchor-definition-on-object"); throw new Microsoft.MetadirectoryServices.AttributeNotPresentException(); } } } schemaResults.Clear(); return(schema); } catch (Exception ex) { Tracer.TraceError("getschema", ex); throw; } finally { Tracer.Exit("getschema"); } }
Collection <PSObject> InvokePowerShellScript(Command command, PSDataCollection <PSObject> pipelineInput) { Tracer.Enter("invokepowershellscript"); SetupImpersonationToken(); Collection <PSObject> results = new Collection <PSObject>(); try { try { powershell.Streams.ClearStreams(); powershell.Commands.Clear(); powershell.Commands.AddCommand(command); if (pipelineInput != null) { Tracer.TraceInformation("pipeline-object-count {0:n0}", pipelineInput.Count); } //if (ShouldImpersonate()) //{ // using (WindowsIdentity.Impersonate(impersonationToken)) // { // Tracer.TraceInformation("start-invoke-script {0}", command.CommandText); // if (pipelineInput != null) // { // powershell.Invoke(pipelineInput, results); // } // else // { // powershell.Invoke(null, results); // } // } //} //else //{ Tracer.TraceInformation("start-invoke-script {0}", command.CommandText); if (pipelineInput != null) { powershell.Invoke(pipelineInput, results); } else { powershell.Invoke(null, results); } //} Tracer.TraceInformation("end-invoke-script {0}", command.CommandText); } catch (RuntimeException e) { Tracer.TraceError("script-invocation-error", e); Tracer.TraceError("script-invocation-inner-exception", e.InnerException != null ? e.InnerException : e); Tracer.TraceError("script-invocation-inner-exception-message", e.InnerException != null ? e.InnerException.Message : "n/a"); Tracer.TraceError("script-invocation-error-stacktrace", e.StackTrace); throw; } finally { Tracer.TraceInformation("script-had-errors {0}", powershell.HadErrors); } } catch (Exception ex) { Tracer.TraceError("invokepowershellscript", ex); throw; } finally { RevertImpersonation(); Tracer.Exit("invokepowershellscript"); } return(results); }
static void Error_DataAdded(object sender, DataAddedEventArgs e) { PSDataCollection <ErrorRecord> err = (PSDataCollection <ErrorRecord>)sender; Tracer.TraceError("error id: {0}, message: {1}", err[e.Index].Exception == null ? -1 : err[e.Index].Exception.HResult, err[e.Index].FullyQualifiedErrorId, err[e.Index].ToString()); }
void OpenRunspace() { Tracer.Enter("openrunspace"); try { if (runspace == null) { Tracer.TraceInformation("creating-runspace"); runspace = RunspaceFactory.CreateRunspace(); runspace.ApartmentState = System.Threading.ApartmentState.STA; runspace.ThreadOptions = PSThreadOptions.Default; runspace.StateChanged += Runspace_StateChanged; runspace.AvailabilityChanged += Runspace_AvailabilityChanged; Tracer.TraceInformation("created-runspace"); } else { Tracer.TraceInformation("existing-runspace-state '{0}'", runspace.RunspaceStateInfo.State); } if (runspace.RunspaceStateInfo.State == RunspaceState.BeforeOpen) { Tracer.TraceInformation("opening-runspace"); runspace.Open(); } else { Tracer.TraceInformation("runspace-already-open"); } Tracer.TraceInformation("runspace-state '{0}'", runspace.RunspaceStateInfo.State); if (runspace.RunspaceStateInfo.State == RunspaceState.Opened) { Tracer.TraceInformation("runspace-powershell-version {0}.{1}", runspace.Version.Major, runspace.Version.Minor); } if (powershell == null) { Tracer.TraceInformation("creating-powershell"); powershell = PowerShell.Create(); powershell.Runspace = runspace; Tracer.TraceInformation("powershell instanceid: {0}, runspace-id: {1}", powershell.InstanceId, powershell.Runspace.InstanceId); Tracer.TraceInformation("powershell apartmentstate: {0}, version: {1}", powershell.Runspace.ApartmentState, powershell.Runspace.Version); // the streams (Error, Debug, Progress, etc) are available on the PowerShell instance. // we can review them during or after execution. // we can also be notified when a new item is written to the stream (like this): powershell.Streams.ClearStreams(); powershell.Streams.Error.DataAdded += new EventHandler <DataAddedEventArgs>(Error_DataAdded); powershell.Streams.Verbose.DataAdded += new EventHandler <DataAddedEventArgs>(Verbose_DataAdded); powershell.Streams.Warning.DataAdded += new EventHandler <DataAddedEventArgs>(Warning_DataAdded); powershell.Streams.Debug.DataAdded += new EventHandler <DataAddedEventArgs>(Debug_DataAdded); powershell.Streams.Progress.DataAdded += new EventHandler <DataAddedEventArgs>(Progress_DataAdded); Tracer.TraceInformation("created-powershell"); } } catch (Exception ex) { Tracer.TraceError("openrunspace", ex); throw; } finally { Tracer.Exit("openrunspace"); } }