Does anybody know if its possible to save the windows event logs from a given time interval as a text file with C#? For example say I want to save the System event logs from between 10 - 11 am in a text file. If it is possible does anybody have a link to a good tutorial or maybe a code snippet that could get me going? I have searched online but cant get what I am looking for.
http://www.dreamincode.net/forums/topic/93268-working-with-the-system-event-log-with-c%23-intro/
Just adding info for others on how to filter event logs by time range as part of the WMI query.
Note that 'TimeGenerated' is when events happen and 'TimeWritten' when they are logged.
The 'RecordNumber' is a unique index, useful for preventing collision or duplicate logging.
There is System.Management.ManagementDateTimeConverter that converts between C# DateTime and the WMI CIM_DATETIME format.
But be aware it makes the UTC CIM into a LOCAL DateTime while leaving Kind Unspecified, so set Kind afterwards to avoid headaches!
This is an example for grabbing security failures ( to track lockouts ) in the last 30 minutes:
private void SearchEventViewer(string computerName, string userName, string userPass)
{
var scope = CreateManagementScope(computerName, userName, userPass);
var startTime = ManagementDateTimeConverter.ToDmtfDateTime(DateTime.UtcNow.AddMinutes(-30));
var query = new SelectQuery("SELECT * FROM Win32_NTLogEvent WHERE Logfile = 'Security' AND EventType = '5' AND TimeGenerated > '" + startTime + "'");
using (var searcher = new ManagementObjectSearcher(scope, query))
{
var result = searcher.Get();
foreach (var item in result)
{
var eventTimeLocal = DateTime.SpecifyKind(ManagementDateTimeConverter.ToDateTime(item["TimeGenerated"].ToString()), DateTimeKind.Local);
var eventTimeUtc = eventTimeLocal.ToUniversalTime();
var eventDetails = item["Message"].ToString().Replace("\r\n\r\n", "\r\n");
eventDetails += "\r\nEventCode: " + item["EventCode"];
eventDetails += "\r\nCatogory: " + item["Category"];
eventDetails += "\r\nRecord Number: " + item["RecordNumber"];
eventDetails += "\r\nLocal Time: " + eventTimeLocal.ToString("yyyy-MM-dd HH:mm:ss");
// Do something...
}
}
}
private ManagementScope CreateManagementScope(string computerName, string username = "", string password = "")
{
var managementPath = #"\\" + computerName + #"\root\cimv2";
var scope = new ManagementScope(managementPath);
if (username != "" && password != "")
{
scope.Options = new ConnectionOptions
{
Username = username,
Password = password,
Impersonation = ImpersonationLevel.Impersonate,
Authentication = AuthenticationLevel.PacketPrivacy
};
}
return scope;
}
Related
I am writing an app for doing changes to DNS resource records on local server.
I wrote a function to do it:
public void UpdateDomainRecord(string domainName, string recordname, IEnumerable<JProperty> content)
{
ResourceRecord Rezults = new ResourceRecord();
string wql = "";
wql += " SELECT * ";
wql += " FROM MicrosoftDNS_ResourceRecord";
wql += " WHERE OwnerName = '" + recordname + '.' + domainName + "'";
ObjectQuery q = new ObjectQuery(wql);
ManagementObjectSearcher s = new ManagementObjectSearcher(this.Session, q);
ManagementObjectCollection col = s.Get();
int total = col.Count;
foreach (ManagementObject o in col)
{
foreach (JProperty prop in content)
{
o.SetPropertyValue(prop.Name.ToString(),prop.Value.ToString());
}
o.Put();
}
}
It seems o.Put() method does not work: the loop changed the property of ManagementObject object but changes is not saved on server.
The app has all access it needs to connect to server.
I'm not trying to change properties that can not be changed.
Do you have any ideas on why it is not working?
The Problem
I have a Visual Studios 2015 Console Application with the Microsoft.Exchange.WebServices v2.2.0 NuGet package installed. I'm trying to create an appointment, update it, and cancel it while retaining the correct Timezone in the "When" string generated automatically in the calendar invite body. Currently, the initial creation has the correct timezone, but any subsequent updates cause the timezone to revert to UTC.
Note: We have an Exchange 2010 server and use Outlook 2013 clients.
Code Sample
using System;
using System.Globalization;
using Microsoft.Exchange.WebServices.Data;
namespace EWSTesting
{
class Program
{
private const string EmailServer = ""; //replace with your Exchange server
private const string EmailAddress = ""; //replace with your email
static void Main(string[] args)
{
Console.WriteLine("Current Timezone: " + TimeZoneInfo.Local.DisplayName);
var exchangeService = new ExchangeService(ExchangeVersion.Exchange2010, TimeZoneInfo.Local)
{
PreferredCulture = new CultureInfo("en-US"),
Url = new Uri(EmailServer),
UseDefaultCredentials = true
};
Console.WriteLine("exchangeService.TimeZone.DisplayName: " + exchangeService.TimeZone.DisplayName);
var startDate = DateTime.Today;
var endDate = startDate.AddHours(1);
//Create initial appointment
var appointment = new Appointment(exchangeService)
{
Subject = "Testing Appointments",
Body = "Testing Appointments Body",
Location = "Test Location",
LegacyFreeBusyStatus = LegacyFreeBusyStatus.Busy,
Sensitivity = Sensitivity.Private,
Start = startDate,
End = endDate
};
appointment.OptionalAttendees.Add(EmailAddress);
appointment.Save(SendInvitationsMode.SendOnlyToAll);
Console.WriteLine("exchangeService.TimeZone.DisplayName: " + exchangeService.TimeZone.DisplayName);
var appointmentId = appointment.Id;
Console.WriteLine("Pause to check inbox 'When' value on invite");
Console.ReadLine();
appointment = Appointment.Bind(exchangeService, appointmentId);
appointment.Load(new PropertySet(PropertySet.FirstClassProperties)
{
AppointmentSchema.StartTimeZone,
AppointmentSchema.EndTimeZone,
AppointmentSchema.TimeZone
});
appointment.Body = "Body Updated Successfully";
appointment.Update(ConflictResolutionMode.AlwaysOverwrite, SendInvitationsOrCancellationsMode.SendOnlyToAll);
Console.WriteLine("exchangeService.TimeZone.DisplayName: " + exchangeService.TimeZone.DisplayName);
Console.WriteLine("appointment.StartTimeZone.DisplayName: " + appointment.StartTimeZone.DisplayName);
Console.WriteLine("appointment.EndTimeZone.DisplayName: " + appointment.EndTimeZone.DisplayName);
Console.WriteLine("appointment.TimeZone: " + appointment.TimeZone);
Console.WriteLine();
Console.WriteLine("Pause to check updated inbox 'When' value on invite");
Console.ReadLine();
appointment = Appointment.Bind(exchangeService, appointmentId);
appointment.Load(new PropertySet(PropertySet.FirstClassProperties)
{
AppointmentSchema.StartTimeZone,
AppointmentSchema.EndTimeZone,
AppointmentSchema.TimeZone
});
Console.WriteLine("exchangeService.TimeZone.DisplayName: " + exchangeService.TimeZone.DisplayName);
Console.WriteLine("appointment.StartTimeZone.DisplayName: " + appointment.StartTimeZone.DisplayName);
Console.WriteLine("appointment.EndTimeZone.DisplayName: " + appointment.EndTimeZone.DisplayName);
Console.WriteLine("appointment.TimeZone: " + appointment.TimeZone);
appointment.CancelMeeting();
Console.WriteLine("Appointment Deleted");
Console.ReadLine();
}
}
}
The Results of the above code
Initial Invite (Correct Timezone)
Updated Appointment (Incorrect Timezone in body)
Appointment Cancellation (Incorrect Timezone in body)
Console Result of code provided
What I'm Looking For
I do not need this additional "When" (underlined in red in pictures above) to be appended to the body of the invite. Either I would like to completely remove it (preferred) or I would like to correct it in any updates.
It appears that the issue is a bug in the EWS 2.2.0 DLL, the timezone SOAP headers are not being added to the Update() and CancelMeeting() Exchange transactions. The code below resolves this issue by manually appending the correct header.
For Update():
exchangeService.OnSerializeCustomSoapHeaders += service_OnSerializeCustomSoapHeaders;
appointment.Update(ConflictResolutionMode.AlwaysOverwrite, SendInvitationsOrCancellationsMode.SendOnlyToAll);
exchangeService.OnSerializeCustomSoapHeaders -= service_OnSerializeCustomSoapHeaders;
For CancelMeeting():
exchangeService.OnSerializeCustomSoapHeaders += service_OnSerializeCustomSoapHeaders;
appointment.CancelMeeting();
exchangeService.OnSerializeCustomSoapHeaders -= service_OnSerializeCustomSoapHeaders;
Event Implementation:
static void service_OnSerializeCustomSoapHeaders(XmlWriter writer)
{
writer.WriteRaw(Environment.NewLine + " <t:TimeZoneContext><t:TimeZoneDefinition Id=\"" + TimeZoneInfo.Local.StandardName + "\"/></t:TimeZoneContext>" + Environment.NewLine);
}
I am having an issue when attempting to create a new user in active directory. I followed the steps provided in this link for using PrincipalContext (with the exception that I am only doing one user at a time when they are hired and entered into the system and not multiple so no loop is required). I am also using a UserPrincipal Extender.
Here is the code that I have:
protected void CreateUserPE()
{
try
{
PrincipalContext userCtx = new PrincipalContext(ContextType.Domain, DomainFQDN, DomainFull);
string UserName = txtFirstName.Text.ToLower() + " " + txtLastName.Text.ToLower();
string password = "superSecretPassword";
UserPrincipalsEx newUser = new UserPrincipalsEx(userCtx, UserName, password, true);
newUser.SamAccountName = txtFirstName.Text.ToLower() + "." + txtLastName.Text.ToLower();
newUser.UserPrincipalName = txtFirstName.Text.ToLower() + "." + txtLastName.Text.ToLower() + "#rasm.com";
newUser.EmployeeId = txtEmpID.Text;
newUser.LastName = txtLastName.Text;
newUser.GivenName = txtFirstName.Text;
newUser.DisplayName = txtFirstName.Text + " " + txtLastName.Text;
newUser.Name = txtFirstName.Text + " " + txtLastName.Text;
newUser.SetPassword(password);
newUser.HomePostalAddress = txtAddress.Text + ", " + txtCity.Text + ", " + txtState.Text + ", " + txtZip.Text;
newUser.CountryName = txtCountry.Text;
newUser.HomePhone = txtHomePhone.Text;
newUser.MobilePhone = txtMobilePhone.Text;
newUser.DateOfBirth = txtDOB.Text;
newUser.EmergencyContact = txtEmergencyCnt.Text;
newUser.EmergencyPhone = txtContactPhone.Text;
newUser.Relationship = ddlRelationship1.SelectedItem.ToString();
newUser.EmergencyContact2 = txtEmergencyCnt2.Text;
newUser.EmergencyPhone2 = txtContactPhone2.Text;
newUser.Relationship2 = ddlRelationship2.SelectedItem.ToString();
newUser.EyeColor = ddlEyeColor.SelectedItem.ToString();
newUser.HairColor = ddlHairColor.SelectedItem.ToString();
newUser.Height = txtHeight.Text;
newUser.Weight = txtWeight.Text;
newUser.Gender = ddlGender.SelectedItem.ToString();
newUser.PersonalEmail = txtPersonalEmail.Text;
newUser.PassportExpires = txtPassportExp.Text;
newUser.HomeBase = ddlHomeStation.SelectedItem.ToString();
newUser.WorkLocation = txtWorkLocation.Text;
newUser.PID = txtPID.Text;
newUser.Team = txtTeam.Text;
newUser.Manager = "CN=" + txtSupervisor.Text + "," + DomainFull;
newUser.Title = ddlJobTitle.SelectedItem.ToString();
newUser.JobCode = txtJobCode.Text;
newUser.PLC = txtPLC.Text;
newUser.BPLC = txtBPLC.Text;
newUser.Specialty = txtSpecialty.Text;
newUser.Position = txtPosition.Text;
newUser.DateOfHire = txtDOH.Text;
newUser.DateOnContract = txtDOC.Text;
newUser.TaskOrder = ddlTaskOrder.SelectedItem.ToString();
newUser.Classification = ddlClass.SelectedIndex.ToString();
newUser.Section = txtSection.Text;
newUser.GatePass = txtGatePass.Text;
newUser.GatePassExpires = txtGatePassExp.Text;
newUser.WorkPhone = txtWorkPhone.Text;
newUser.CompanyEmail = txtCompEmail.Text;
newUser.aKOEmail = txtMilEmail.Text;
newUser.aKOSponsor = txtMilEmailSp.Text;
newUser.CACSponsor = txtCacSponsor.Text;
newUser.CACSponsorEmail = txtCacSponsorEmail.Text;
newUser.CacCardExpires = txtCacExpires.Text;
newUser.Enabled = true;
newUser.ExpirePasswordNow();
newUser.Save();
newUser.Dispose();
}
catch
{
}
}
The program goes all the way to newUser.Save() and then throws the following error in the catch statement:
System.DirectoryServices.AccountManagement.PrincipalOperationException was caught
HResult=-2146233087
Message=The attribute syntax specified to the directory service is invalid.
Source=System.DirectoryServices.AccountManagement
ErrorCode=-2147016693
StackTrace:
at System.DirectoryServices.AccountManagement.ADStoreCtx.Insert(Principal p)
at System.DirectoryServices.AccountManagement.Principal.Save()
at Personnel_Employee.CreateUserPE() in c:\inetpub\wwwroot\TestingFolder\Personnel\Add\Employee.aspx.cs:line 263
InnerException: System.DirectoryServices.DirectoryServicesCOMException
HResult=-2147016693
Message=The attribute syntax specified to the directory service is invalid.
Source=System.DirectoryServices
ErrorCode=-2147016693
ExtendedError=87
ExtendedErrorMessage=00000057: LdapErr: DSID-0C090D11, comment: Error in attribute conversion operation, data 0, v23f0
StackTrace:
at System.DirectoryServices.DirectoryEntry.CommitChanges()
at System.DirectoryServices.AccountManagement.SDSUtils.ApplyChangesToDirectory(Principal p, StoreCtx storeCtx, GroupMembershipUpdater updateGroupMembership, NetCred credentials, AuthenticationTypes authTypes)
InnerException:
Where am I going wrong.
You can not update an attribute with null or empty. I personaly dislike solutions with dummy values. If you are using the context principle just simply check for null or empty and dont update if its the case like:
if (!string.IsNullOrEmpty(txtbox.Text)){ newUser.attributeName = txtbox.Text}
If you are using an directory entry instead of an usercontext you can do something like this:
string adPath = "LDAP://server.domain.com/CN=John,CN=Users,dc=domain,dc=com";
DirectoryEntry userEntry = new DirectoryEntry(adPath);
if (txtBox.text == "")
{
userEntry.Properties["proppertyName"].Clear();
}
else if (!string.IsNullOrEmpty(txtBox.text))
{
userEntry.Properties[attribute.Key].Value = txtBox.text;
}
// dont do a thing when txtBox.Text is empty
It looks like more code but its much easier to make a foreachloop for it if you have a list with all attribute like:
private void UpdateEntryAttributes(DirectoryEntry entry, Dictionary<string, string> attributes)
{
foreach (KeyValuePair<string, string> attribute in attributes)
{
entry.Properties[attribute.Key].Value = attribute.Value;
if (attribute.Value == "")
{
entry.Properties[attribute.Key].Clear();
}
else if (!string.IsNullOrEmpty(attribute.Value))
{
entry.Properties[attribute.Key].Value = attribute.Value;
}
}
This can happen when attempting to write either a null or empty string to an AD field that prohibits it. An easy way to check whether this is the problem is to temporarily replace all such values with a dummy string (length > 0) and then run the code again. If that works, you can attempt a fix by changing the offending value--with AD, sometimes if null doesn't work, then an empty string will work, or vice versa.
I am new to stackoverflow as a member, although I follow this a lot :)
My code which connects to active directory to get the members of a functional group, gives me only 1490 odd members out of 1680 odd members actually in the list. I have searched a lot on Stackoverflow and on Internet, but I have not found out answer to why the code would result in incomplete list. Could, anyone please give me any pointers on this. Thanks :)
Here is the code which connects to the Active Directory to retrieve the data:
public static DataTable GetAdUsers(string configSection)
{
DataRow dr;
Hashtable ADGroups = (Hashtable)ConfigurationManager.GetSection(configSection);
string adGroup;
string adGroupDesc;
string sApplication;
string sLast_Login;
string sAccount_owner;
string sPath;
DataTable dt = new DataTable();
sApplication = "Application";
dt.Columns.Add(sApplication);
dt.Columns.Add("Profile", Type.GetType("System.String"));
dt.Columns.Add("Account Name", Type.GetType("System.String"));
sLast_Login = "Last Login";
dt.Columns.Add(sLast_Login);
sAccount_owner = "Account Owner";
dt.Columns.Add(sAccount_owner);
sPath = "Path";
dt.Columns.Add(sPath);
string domainName = "myDomain";
PrincipalContext pcRoot = new PrincipalContext(ContextType.Domain, domainName);
IDictionaryEnumerator adGroupEnumerator = ADGroups.GetEnumerator();
while (adGroupEnumerator.MoveNext())
{
adGroup = adGroupEnumerator.Key.ToString();
adGroupDesc = adGroupEnumerator.Value.ToString();
GroupPrincipal grp = GroupPrincipal.FindByIdentity(pcRoot, IdentityType.SamAccountName, adGroup);
System.DirectoryServices.DirectoryEntry de = (System.DirectoryServices.DirectoryEntry)grp.GetUnderlyingObject();
foreach (string sDN in de.Properties["member"])
{
System.DirectoryServices.DirectoryEntry deMember = new System.DirectoryServices.DirectoryEntry("LDAP://" + sDN.ToString());
try
{
dr = dt.NewRow();
string output1;
string subStringE1 = "DC=";
int length1 = de.Path.ToString().Length;
int length0 = de.Path.ToString().IndexOf(subStringE1);
string str1 = de.Path.ToString().Substring(length0, length1 - length0);
string subStringE2 = ",DC";
int length2 = str1.ToString().IndexOf(subStringE2);
output1 = str1.ToString().Substring(3, length2 - 3);
dr["Application"] = "Application";
dr["Profile"] = adGroupDesc;
string AccountName = deMember.Properties["samAccountName"].Value.ToString();
dr["Account Name"] = deMember.Properties["samAccountName"].Value.ToString();
dr["Last Login"] = "";
dr["Account Owner"] = deMember.Properties["givenName"].Value.ToString() + #"-" + deMember.Properties["sn"].Value.ToString();
string Path = output1 + #"\" + adGroup + #"\" + deMember.Properties["samAccountName"].Value.ToString();
Console.WriteLine(Path);
dr["Path"] = output1 + #"\" + adGroup + #"\" + deMember.Properties["samAccountName"].Value.ToString();
dt.Rows.Add(dr);
}
catch (Exception ex)
{
Console.WriteLine("Error occured for user name" + sDN + "\n" + ex.Message);
}
}
}
return dt;
}
}
Because of the default limit of SizeLimit, you're probably only getting around the 1,490 objects or so. To fix that you need to "page" through the results.
Just use the code referenced at Enumerating Members in a Large Group .
When there is the possibility that the result set that will be returned will contain more than 1000 items, you must use a paged search. Searches of Active Directory performed without paging are limited to returning a maximum of the first 1000 records. With a paged search, the result set is presented as individual pages, each containing a predetermined number of result entries. With this type of search, new pages of result entries are returned until the end of the result set is reached.
By default, the server that responds to a query request completely calculates a result set before returning data. In a large result set, this requires server memory as the result set is acquired, and network bandwidth when the large result is returned. Setting a page size allows the server to send the data in pages as the pages are being built. The client then caches this data and provides a cursor to the application level code.
Paging is set by defining how many rows the server calculates before the data is returned over the network to the client.
Found the answer by researching through and trying my luck.
Using Directory Entry was the problem, and did not ned to use Page Searching, although I tried the same.
The working code is as below:
GroupPrincipal grp = GroupPrincipal.FindByIdentity(pcRoot, adGroup); //fglbcmdolpctx
if (grp != null)
{
foreach (Principal p in grp.GetMembers(true))
{
try
{
dr = dt.NewRow();
dr["Application"] = "Commodities OpenLink";
dr["Profile"] = adGroupDesc;
string AccountName = p.SamAccountName.ToString().ToLower();
dr["Account Name"] = AccountName;
dr["Last Login"] = "";
string sLastName, sFirstName;
int iLastNameIndex0, iLastNameIndex1, iFirstNameIndex0, iFirstNameIndex1;
int lengthofString = p.Name.ToString().Length;
iLastNameIndex1 = p.Name.ToString().IndexOf(",");
if (iLastNameIndex1 == -1)
{
sLastName = "";
}
else
{
sLastName = p.Name.ToString().Substring(0, iLastNameIndex1);
}
iFirstNameIndex0 = p.Name.ToString().IndexOf(",");
iFirstNameIndex1 = p.Name.ToString().IndexOf(":");
if (iFirstNameIndex0 == -1 || iFirstNameIndex1 == -1)
{
sFirstName = p.Name.ToString();
sLastName = "";
}
else
{
sFirstName = p.Name.ToString().Substring(iFirstNameIndex0 + 1, iFirstNameIndex1 - iFirstNameIndex0 - 1);
}
sAccount_owner = sLastName + #"-" + sFirstName;
dr["Account Owner"] = sAccount_owner;
string sPath_Domain_Part;
string sFirstIndexofExtraction = "DC=";
int ilength_String = p.DistinguishedName.ToString().Length;
int iLenght_ExtractionPoint1 = p.DistinguishedName.ToString().IndexOf(sFirstIndexofExtraction);
string str1 = p.DistinguishedName.ToString().Substring(iLenght_ExtractionPoint1, ilength_String - iLenght_ExtractionPoint1);
string subStringE2 = ",DC";
int iLenght_ExtractionPoint2 = str1.IndexOf(subStringE2);
sPath_Domain_Part = str1.Substring(3, iLenght_ExtractionPoint2 - 3);
string sPath1 = sPath_Domain_Part + #"\" + adGroup + #"\" + p.SamAccountName.ToString();
dr["Path"] = sPath_Domain_Part + #"\" + adGroup + #"\" + p.SamAccountName.ToString();
dt.Rows.Add(dr);
}
catch (Exception ex)
{
Global.logfile.WriteLine("Error occured for user name" + adGroup + p.SamAccountName + "\n" + ex.Message);
}
}
}
I have written the following program which connects to two LDAP stores, compares the attributes and based on the outcome, creates a new csv file. I have run into a problem though.
Here is the code:
//Define LDAP Connection
string username = "****";
string password = "*****";
string domain = "LDAP://****";
//Define LDAP Connection
string ABSAusername = "****";
string ABSApassword = "****";
string ABSAdomain = "LDAP://****";
//Create Directory Searcher
DirectoryEntry ldapConnection = new DirectoryEntry(domain,username,password);
ldapConnection.AuthenticationType = AuthenticationTypes.Anonymous;
DirectorySearcher ds = new DirectorySearcher(ldapConnection);
ds.Filter = "((EmploymentStatus=0))";
ds.SearchScope = System.DirectoryServices.SearchScope.Subtree;
//Create Directory Searcher
DirectoryEntry ABSAldapConnection = new DirectoryEntry(ABSAdomain, ABSAusername, ABSApassword);
ABSAldapConnection.AuthenticationType = AuthenticationTypes.Anonymous;
DirectorySearcher ABSAds = new DirectorySearcher(ABSAldapConnection);
ABSAds.Filter = "((&(EmploymentStatus=3)(EmploymentStatusDescription=Active))";
ABSAds.SearchScope = System.DirectoryServices.SearchScope.Subtree;
ds.PropertiesToLoad.Add("cn");
ds.PropertiesToLoad.Add ("uid");
ds.PropertiesToLoad.Add("sn");
ds.PropertiesToLoad.Add("PersonnelAreaDesc");
ds.PropertiesToLoad.Add("JobcodeID");
ds.PropertiesToLoad.Add("CostCentreID");
ds.PropertiesToLoad.Add("CostCentreDescription");
ds.PropertiesToLoad.Add ("givenName");
ds.PropertiesToLoad.Add ("EmploymentStatus");
ds.PropertiesToLoad.Add("EmploymentStatusDescription");
ABSAds.PropertiesToLoad.Add("uid");
ABSAds.PropertiesToLoad.Add("EmploymentStatus");
ABSAds.Sort = new SortOption("uid", SortDirection.Ascending);
ds.Sort = new SortOption("cn", SortDirection.Ascending);
SearchResultCollection absaUsers = ds.FindAll();
SearchResultCollection srcUsers = ds.FindAll();
sw.WriteLine("Action" + "," + "uid" + "," + "Business Area" + "," + "employeeNumber" + "," + "First Name" + "," + "Last Name" + "," + "JobCodeID" + "," + "costCentreID" + "," + "costCentreDescription" + "," + "FullName" + "," + "EmploymentStatus" + "," + "EmploymentStatusDescription" );
sw.WriteLine("");
foreach (SearchResult users in srcUsers)
{
string cn = users.Properties["cn"][0].ToString();
string sn = users.Properties["sn"][0].ToString();
string userID = users.Properties["uid"][0].ToString();
string description = users.Properties["PersonnelAreaDesc"][0].ToString();
// string jobCodeID = users.Properties["JobcodeID"][1].ToString();
string CostCentreID = users.Properties["costCentreID"][0].ToString();
string CostCentreDescription = users.Properties["CostCentreDescription"][0].ToString();
string givenName = users.Properties["givenName"][0].ToString();
string employmentStatus = users.Properties["EmploymentStatus"][0].ToString();
string EmploymentStatusDescription = users.Properties["EmploymentStatusDescription"][0].ToString();
foreach (SearchResult absaUser in absaUsers)
{
string absaUID = absaUser.Properties["uid"][0].ToString();
string absaEmploymentStatus = absaUser.Properties["EmploymentStatus"][0].ToString();
if (cn == absaUID)
{
if (absaEmploymentStatus == "3")
{
sw.WriteLine(cn);
}
}
}
}
sw.Flush();
sw.Close();
sw.Dispose();
}
}
I created two foreach loops, in the first loop i assigned variables to strings, and in the second foreach loop i do a comparison with an IF statement. What i want to do is: if the uid in one LDAP is equal to the uid in the other ldap, and if the status of the user in the 1st ldap = 0 but the status of the user in the 2nd ldap = 3: then i want to print out the users that match that criteria from the 1st ldap.
If you look through my code, am i doing somthing wrong? The output of the program currently is about 10 users that are duplicated atleast 100 times each.
Thanks in advance.
There are several things obviously wrong with this code....
1) First of all, you're creating the same search result twice:
SearchResultCollection absaUsers = ds.FindAll();
SearchResultCollection srcUsers = ds.FindAll();
So if that searcher finds 10 users, you have two collections of the same 10 users here.
2) You then used nested foreach loops, so you basically go through all results from the first collection, one by one, and for each of those entries, you enumerate the entire second collection - basically doing a cartesian product between the two collections. So that's why you end up with 10 x 10 = 100 users in the end.....
3) you seem to be missing some kind of a restriction/condition to pick out only those elements from your second/inner result set that match the outer/first result set in some way. As long as you don't have such a condition in place, you'll always get all the results from the second result set for each element of the first result set = a classic cartesian product. Somehow, you want to select only certain elements from the second set, based on something from the first result set......
You have missed break in the following place:
if (cn == absaUID && absaEmploymentStatus == "3")
{
sw.WriteLine(cn);
break;
}