I am trying to read through the Windows Event log "Error" entry messages in in c#.
foreach (EventLogEntry log in eventLog.Entries)
{
if (log.EntryType.ToString() == "Error")
{
Console.WriteLine( log.Message);
}
}
The output is "The XYZ service failed to start due to the following error: \r\n%%2"
while the entry I am looking for is
"The XYZ service failed to start due to the following error:\r\nThe system cannot find the file specified."
How does one translate from the id to the appropriate error message ?
Many thanks,
KG
Event log messages are templates, something like:
The %1 service failed to start due to the following error: \r\n%2
An event log entry contains a message number and replacement strings to substitute for %1, %2, etc.
The .Net EventLogEntry.Message property does the substitution for you, so you should never see the %1, %2, etc.
It looks like the substitution is failing, perhaps because there aren't enough replacement strings (check the EventLogEntry.ReplacementStrings property) or the format string is malformed (it seems to have a stray '%'). Though neither of these explanations seem plausible if the log entry is coming from the Service Control Manager.
Related
My team is using a program written in C# to read all users from a specific OU. The program behaves very strange. Sometimes it is working for a couple of weeks and then without any big changes on our AD or any other related component, it throws an exception. Then it is not working for a couple of weeks and after some time it start to run normally again.
Code
DirectoryEntry searchRoot = new DirectoryEntry("<LDAP string>")
searchRoot.AuthenticationType = AuthenticationTypes.None;
DirectorySearcher search = new DirectorySearcher(searchRoot);
search.Filter = <our filter>;
search.PropertiesToLoad.Add("<some property>");
search.PageSize = 1;
SearchResult result;
SearchResultCollection resultCol = null;
try
{
resultCol = search.FindAll();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
if (resultCol != null)
{
Console.WriteLine("Result Count: " + resultCol.Count); //.Count throws the Exception
}
Exception
Unhandled Exception: System.DirectoryServices.DirectoryServicesCOMException: An operations error occurred.
at System.DirectoryServices.SearchResultCollection.ResultsEnumerator.MoveNext()
at System.DirectoryServices.SearchResultCollection.get_InnerList()
at System.DirectoryServices.SearchResultCollection.get_Count()
Data: System.Collections.ListDictionaryInternal
Error Code: -2147016672
Extended Error: 8431
Extended Error Message: 000020EF: SvcErr: DSID-020A07A7, problem 5012 (DIR_ERROR), data -1018
HResult: -2147016672
Message: An operations error occured.
Source: System.DirectoryServices
Stack Trace: at System.DirectoryServices.SearchResultCollection.ResultsEnumerator.MoveNext()
Target Site: Boolean MoveNext()
Additional Information
Target Framework: .Net Framework 4.6.1 (no additional libraries)
The program is executed on a domain controller
What I have tried
I have created a loop to use the MoveNext() function of the
enumerator and found out that it loads results up to a specific
element and then crashes
It is always the same element
After the first exception all retries fail as well
The user that starts it is a domain admin (but I
have also tried it with an enterprise admin account, so it is
probably not a permission issue)
I have deleted the user that should be read when the exception happens but dring the next run the exception was thrown for a previous user
I have come to a point, where I have no more ideas on solving this problem. I would appreciate all your support.
This answer just summarizes our conversation in comments.
This thread partially matches the error you are getting:
problem 5012 (DIR_ERROR) data -1018
And the answer from a Microsoft MVP is:
That is a checksum error in the database, you have corruption in your
database which is usually due to a failing disk or disk subsystem or
possibly a system crash and data not being written from a write cache.
So it sounds like you might have the same thing going on.
But it may only be one DC that has the problem. So to help you narrow down which one, you can specify the DC in the LDAP path like so:
LDAP://dc1.example.com/OU=Target,OU=My User Group,OU=My Users,DC=example,DC=com
This can help you in two ways:
It can identify the bad DC so you know which one you need to fix (and possibly take it offline until it is fixed), and
You can specifically target a good DC so your script will keep working.
I have some pretty basic code that seems to work for most people but there's at least one workstation that throws this HRESULT code when it runs these couple lines of code:
Outlook.Application _OutlookInstance = new Outlook.Application();
Outlook.Stores stores = _OutlookInstance.Session.Stores;
Any idea what HRESULT code 0xCA140115 is or what it means? I can't find it on MSDN anywhere...
The workstation that experiences the problem is at a remote call center location, so I can't do any immediate testing/debugging, or easily see what is specifically different about this workstation versus the others. I would imagine there might be more workstations at that same call center that could have the error, but this code is still in the testing phase.
Sorry for the delay, but I was able to get through several more iterations of testing and find out what the issue was. First off, my original post was incorrect. The code flow made it seem like the error was happening during those 2 initial lines, but it was actually happening a little later, when I was looping through the stores, like this:
Outlook.Stores stores = _OutlookInstance.Session.Stores;
foreach(Outlook.Store store in stores) // <----- THIS LINE
{
...
}
Each time the user ran this, he would get a different HRESULT error code:
0xCA140115
0xAF64011D
0xC1F4011D
0xC834011D
The only consistent factor was the "4011" in the middle.
When I upped the logging, I could see that the user had 18 mailboxes and the foreach() loop was getting through the first 3 but failing on the 4th. The 4th mailbox was a "Public Folders" store associated to another mailbox that was added in a different way than the rest of the mailboxes (it had something to do with it being an Outlook 365 mailbox that required different authentication).
So essentially it ended up being that any attempt to even touch that particular mailbox/store (including the "store" variable being set) would result in that COM exception.
I was able to work around it by looping through stores via numeric index so that the setting of "store" was inside my try/catch block, like this:
for(int i = 0; i < stores.Count; i++)
{
try
{
Outlook.Store store = stores[i];
...
}
catch(Exception)
{
...
}
}
Now when the loop hit that particular store, I could tell that it was Outlook saying that the server wasn't available, and the store was an online-only store, so the store couldn't be accessed.
I'm still not certain about why the error codes changed each time, but there you have it.
I have an issue with pdftron, where opening a certain file, will cause our application to crash with following error:
An unhandled exception of type 'pdftron.Common.PDFNetException' occurred in PDFNet.dll
Additional information: Exception:
Message: Missing resource
Conditional expression: res
Filename : ContentResources.hpp
Function : trn::PDF::ContentResources::GetResource
Linenumber : 26
In our code: it's in the following line that the error occurs:
while ((element = elReader.Next()) != null)
When doing try/catch, we see that the only thing missing from the page is the text that's written diagonally on that page. Does this have anything to do with a missing font maybe ? Don't mind the cursor in the picture, it doesn't know where to go with the text missing.
I can send the pdf file on request.
PDF File
If you are not on the latest version of PDFNet, 6.7.1, then I would first try against that, as the issue might have been resolved already.
Otherwise, since the issue is document specific, you would need to provide that, by either sharing here, or sending to pdftron support.
I got the following snippet (SomeName/SomeDomain contains real values in my code)
var entry = new DirectoryEntry("LDAP://CN=SomeName,OU=All Groups,dc=SomeDomain,dc=com");
foreach (object property in entry.Properties)
{
Console.WriteLine(property);
}
It prints OK for the first 21 properties, but then fail with:
COMException {"Unknown error (0x8000500c)"}
at System.DirectoryServices.PropertyValueCollection.PopulateList()
at System.DirectoryServices.PropertyValueCollection..ctor(DirectoryEntry entry, String propertyName)
at System.DirectoryServices.PropertyCollection.PropertyEnumerator.get_Entry()
at System.DirectoryServices.PropertyCollection.PropertyEnumerator.get_Current()
at ActiveDirectory.Tests.IntegrationTests.ObjectFactoryTests.TestMethod1() in MyTests.cs:line 22
Why? How can I prevent it?
Update
It's a custom attribute that fails.
I've tried to use entry.RefreshCache() and entry.RefreshCache(new[]{"theAttributeName"}) before enumerating the properties (which didn't help).
Update2
entry.InvokeGet("theAttributeName") works (and without RefreshCache).
Can someone explain why?
Update3
It works if I supply the FQDN to the item: LDAP://srv00014.ssab.com/CN=SomeName,xxxx
Bounty
I'm looking for an answer which addresses the following:
Why entry.Properties["customAttributeName"] fails with the mentioned exception
Why entry.InvokeGet("customAttributeName") works
The cause of the exception
How to get both working
If one wants to access a custom attribute from a machine that is not
part of the domain where the custom attribute resides (the credentials
of the logged in user don't matter) one needs to pass the fully
qualified name of the object is trying to access otherwise the schema
cache on the client machine is not properly refreshed, nevermind all
the schema.refresh() calls you make
Found here. This sounds like your problem, given the updates made to the question.
Using the Err.exe tool here
http://www.microsoft.com/download/en/details.aspx?id=985
It spits out:
for hex 0x8000500c / decimal -2147463156 :
E_ADS_CANT_CONVERT_DATATYPE adserr.h
The directory datatype cannot be converted to/from a native
DS datatype
1 matches found for "0x8000500c"
Googled "The directory datatype cannot be converted to/from a native" and found this KB:
http://support.microsoft.com/kb/907462
I have the same failure. I´m read and saw a lot of questions about the error 0x8000500c by listing attribute from a DirectoryEntry.
I could see, with the Process Monitor (Sysinternals), that my process has read a schema file. This schema file is saved under
C:\Users\xxxx\AppData\Local\Microsoft\Windows\SchCache\xyz.sch.
Remove this file and the program works fine :)
I just encountered the issue and mine was with a web application.
I had this bit of code which pulls the user out of windows authentication in IIS and pulls their info from AD.
using (var context = new PrincipalContext(ContextType.Domain))
{
var name = UserPrincipal.Current.DisplayName;
var principal = UserPrincipal.FindByIdentity(context, this.user.Identity.Name);
if (principal != null)
{
this.fullName = principal.GivenName + " " + principal.Surname;
}
else
{
this.fullName = string.Empty;
}
}
This worked fine in my tests, but when I published the website it would come up with this error on FindByIdentity call.
I fixed the issue by using correct user for the app-pool of the website. As soon as I fixed that, this started working.
I had the same problem with a custom attribute of a weird data type. I had a utility program that would extract the value, but some more structured code in a service that would not.
The utility was working directly with a SearchResult object, while the service was using a DirectoryEntry.
It distilled out to this.
SearchResult result;
result.Properties[customProp]; // might work for you
result.Properties[customProp][0]; // works for me. see below
using (DirectoryEntry entry = result.GetDirectoryEntry())
{
entry.Properties[customProp]; // fails
entry.InvokeGet(customProp); // fails as well for the weird data
}
My gut feel is that the SearchResult is a little less of an enforcer and returns back whatever it has.
When this is converted to a DirectoryEntry, this code munges the weird data type so that even InvokeGet fails.
My actual extraction code with the extra [0] looks like:
byte[] bytes = (byte[])((result.Properties[customProp][0]));
String customValue = System.Text.Encoding.UTF8.GetString(bytes);
I picked up the second line from another posting on the site.
logging exception
the code below allows to save the content of an exception in a text file. Here I'm getting only the decription of the error.
but it is not telling me where the exception occured, at which line.
Can anyone tell me how can I achive that so I can get even the line number where the exception occured?
#region WriteLogError
/// <summary>
/// Write an error Log in File
/// </summary>
/// <param name="errorMessage"></param>
public void WriteLogError(string errorMessage)
{
try
{
string path = "~/Error/" + DateTime.Today.ToString("dd-mm-yy") + ".txt";
if (!File.Exists(System.Web.HttpContext.Current.Server.MapPath(path)))
{
File.Create(System.Web.HttpContext.Current.Server.MapPath(path))
.Close();
}
using (StreamWriter w = File.AppendText(System.Web.HttpContext.Current.Server.MapPath(path)))
{
w.WriteLine("\r\nLog Entry : ");
w.WriteLine("{0}", DateTime.Now.ToString(CultureInfo.InvariantCulture));
string err = "Error in: " + System.Web.HttpContext.Current.Request.Url.ToString()
+ ". Error Message:" + errorMessage;
w.WriteLine(err);
w.WriteLine("__________________________");
w.Flush();
w.Close();
}
}
catch (Exception ex)
{
WriteLogError(ex.Message);
}
}
#endregion
I find that the easiest way to log exceptions in C# is to call the ToString() method:
try
{
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
This usually gives you all the information you need such as the error message and the stack trace, plus any extra exception specific context information. (however note that the stack trace will only show you source files and line numbers if you have your application compiled with debug information)
It is worth noting however that seeing a full stack trace can be fairly offputting for the user and so wherever possible you should try to handle exceptions and print out a more friendly error message.
On another note - you should replace your method WriteLogError with a fully featured logging framework (like Serilog) instead of trying to write your own.
Your logging method is not thread safe (your log file will probably end up with log messages being intermingled with each other) and also should definitely not call itself if you catch an exception - this will mean that any exceptions that occur whilst logging errors will probably cause a difficult to diagnose StackOverflow exception.
I could suggest how to fix those things, however you would be much better served just using a proper logging framework.
Just log ToString(). Not only will it give you the stack trace, but it'll also include the inner exceptions.
Also, when you deploy a release build of your code to a production environment for instance, don't forget to include the .pdb files in the release package. You need that file to get the line number of the code that excepted (see How much information do pdb files contain? (C# / .NET))
Your solution is pretty good. I went through the same phase
and eventually needed to log more and more (it will come...):
logging source location
callstack before exception (could be in really different place)
all internal exceptions in the same way
process id / thread id
time (or request ticks)
for web - url, http headers, client ip, cookies, web session content
some other critical variable values
loaded assemblies in memory
...
Preferably in the way that I clicked on the file link where the error occurred,
or clicked on a link in the callstack, and Visual Studio opened up at the appropriate location.
(Of course, all you need to do is *.PDB files, where the paths from the IL code
to your released source in C # are stored.)
So I finally started using this solution:
It exists as a Nuget package - Desharp.
It's for both application types - web and desktop.
See it's Desharp Github documentation. It has many configuration options.
try {
var myStrangeObj = new { /*... something really mysterious ...*/ };
throw new Exception("Something really baaaaad with my strange object :-)");
} catch (Exception ex) {
// store any rendered object in debug.html or debug.log file
Desharp.Debug.Log(myStrangeObj, Desharp.Level.DEBUG);
// store exception with all inner exceptions and everything else
// you need to know later in exceptions.html or exceptions.log file
Desharp.Debug.Log(ex);
}
It has HTML log formats, every exception in one line,
and from html page you can open in browser, you can click
on file link and go to Visual Studio - it's really addictive!
It's only necessary to install this Desharp editor opener.
See some demos here:
Web Basic App
Web MVC App
Console App
Try to check out any of those repos and log something by the way above.
then you can see logged results into ~/Logs directory. Mostly anything is configurable.
I am only answering for the ask, other people have already mentioned about the code already. If you want the line number to be included in your log you need to include the generated debug files (pdb) in your deployment to the server. If its just your Dev/Test region that is fine but I don't recommend using in production.
Please note that the exception class is serializable. This means that you could easily write the exception class to disk using the builtin XmlSerializer - or use a custom serializer to write to a txt file for example.
Logging to output can ofcourse be done by using ToString() instead of only reading the error message as mentioned in other answers.
Exception class
https://learn.microsoft.com/en-us/dotnet/api/system.exception?redirectedfrom=MSDN&view=netframework-4.7.2
Info about serialization, the act of converting an object to a file on disk and vice versa.
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/serialization/