Hi i am working with sharepoint 2007 , and the requirement is to stop all workflows on sharepoint lists in progress after an IISreset.
How do i Programatically find the last IISReset time using C#.
The SCM or Service Control manager logs this. You need to open up the system log in Event Viewer and look in there.
EventLog eventLog = new EventLog();
eventLog.Log = "System";
eventLog.Source = "Service Control Manager"; //Not 100% sure thats correct
eventLog.MachineName = "IIS Server name";
foreach (EventLogEntry log in eventLog.Entries)
{
Console.WriteLine("{0}\n",log.<Property you need for info>);
}
I would say figure out what the event ID would be and key off that instead of just matching Error text or anything along those lines. Just off a quick search I believe its 3203. Below is a WMI solution as well I would suggest do some performance testing on Both. There is another method that is EventLogReader which requires you to have windows vista or 7 or windows server 2008 or higher that you can use as well.
var query = new ObjectQuery("Select * from Win32_NTLogEvent
where LogFile='Application'");
var searcher = new ManagementObjectSearcher(query);
var result = searcher.Get(); // Result is your Collection of Event Log entries
foreach(var eventEntry in result)
{
//access properties in this fashion would suggest try parse
int id = int.Parse(eventEntry["Event ID Property Name"].ToString());
}
Related
So we have created an updated version of a WSP for SharePoint 2010 due to our migration/update from 2007 to 2010.
The WSP is a event handler/reciever for ItemAdded() and we have it working as intended. Issue is that the operation seems to only work for one computer/machine and no others.
When the Item is Added to a list the WSP creates a Folder in Shared Documents library, creates a wiki page, then updates the new List Item with links to the Shared Doc and Wiki.
When triggered by Machine #1 and User #1 all operations work, when Machine #2(M2) and user #2(U2) or M3 and U3 non of the tasks take place when a new Item is created.
User #2 can log in on M1 and create a new item and all operations work. But if U1 uses M2 or M3 to create an item the events don't trigger. Machine #1 is able to trigger the event as many times as they want but no other computer is able to.
If you were able to follow is it something with the code or some sort of cache setting on the local machine or the SP server, or something else? Any help is appreciated.
Update: All machines are on the same network. Non of the machines are the server but various personal laptops. Development was done on a separate machine. All are accessing via the same URL. All users have same access. This is on our test site currently which would be switched to being production once migration/upgrade takes place.
Before current .WSP deployment we noticed the same issue but it was reverse, Machine #2 did all the updates but Machine #1 and #3 couldn't. Only thing we can think of was that those machines were the first to trigger the event after deployment.
I'm Not doing the .WSP install but our IT guy is(won't let us have access :/ but I understand) but below is the install commands he is running.
Add-SPSolution -LiteralPath "OurPath/ourFile.wsp"
Install-SPSolution -Identity ourIdentity -WebApplication http://myhost.com/ -GACDeployment
Below is the main part of the code
public class CreateWikiAndFolder : Microsoft.SharePoint.SPItemEventReceiver
{
public override void ItemAdded(SPItemEventProperties properties)
{
try
{
//this.DisableEventFiring();
base.EventFiringEnabled = false;
string sUrlOfWikiPage = string.Empty;
string sUrlOfNewFolder = string.Empty;
string sSubsiteRUL = string.Empty;
string sCurrentItemTitle = properties.ListItem["Title"].ToString();
string sWikiListName = "TR Wikis";
string sDocLibName = "Shared Documents";
string sTRListID = "TR Status";
if (sTRListID.ToUpper().Equals(properties.ListTitle.ToString().ToUpper()))
{
//Create the Folder
sUrlOfNewFolder = CreateFolder(properties.ListItem.Web, sDocLibName, sCurrentItemTitle);
//Create the Wiki
string ItemDispFormUrl = String.Concat(properties.ListItem.Web.Url, "/", properties.ListItem.ParentList.Forms[PAGETYPE.PAGE_DISPLAYFORM].Url, "?ID=", properties.ListItem.ID.ToString());
sUrlOfWikiPage = CreateWiki(properties.ListItem.Web, sWikiListName, sCurrentItemTitle, ItemDispFormUrl, sUrlOfNewFolder);
//Update the current TR Item
SPWeb myWeb = properties.ListItem.Web;
myWeb.AllowUnsafeUpdates = true;
SPListItem myListItem = properties.ListItem;
SPFieldUrlValue shareFolderURLValue = new SPFieldUrlValue();
shareFolderURLValue.Description = "Shared Folder";
shareFolderURLValue.Url = sUrlOfNewFolder ;
myListItem["SharedFolder"] = shareFolderURLValue;
myListItem.Update();
myWeb.AllowUnsafeUpdates = false;
}
base.EventFiringEnabled = true;
}
catch (Exception e)
{
//Currently throwing nothing
}
}
}
It could be a hardcoded path/url, however there is not enough information to identify the problem, I would be glad to update my answer with a more detailed theory if you provide more details or if you share some of your code.
Figured out the issue. I didn't include them with the above file code. But we were StreamWriting to a text file on the server to help us with debugging. Issue was with that, When user 1 was logged on their machine and the log files didn't exist, they would get generated. Now no other users then had read/write access to those files and so it errored out at our debug files for anyone else. But that Windows user could run it as much as they wanted as they were the owner of the file :/
How do I get the XML from a specific EventLogEntry using C# on Windows XP? I already know the EventLog type (Security) and the event entry id.
EventLogWatcher and other classes are only available in Windows Vista and newer.
You can do this with LogParser. Its a utility built by an x Microsoft Employee Gabriele Giuseppini that reads a tonne of log file formats - FAST!
I've successfully used it with Event Logs before.
There is a C# interface from the good folks over at http://visuallogparser.codeplex.com
For Windows XP, you can use the EventLogReader and EventLogQuery classes to query EventLogRecords from the event log quite efficiently. This API is available since .NET Framework 3.5 (so it should work perfectly fine on Windows XP).
First, you need the name of the event log to query (either its file system path or name), and second an XPath expression that acts as the record selector. A few examples are given at https://learn.microsoft.com/en-us/windows/win32/wes/consuming-events
Basically, it works as follows:
static string RetrieveApplicationEventDetailsXmlById(string eventId)
{
const string logName = "Application";
string queryExpression = string.Format("*[System/EventId=\"{0}\"]", eventId);
var eventLogQuery = new EventLogQuery(logName, PathType.LogName, queryExpression);
using (var reader = new EventLogReader(eventLogQuery))
{
EventRecord record;
if ((record = reader.Next()) != null)
{
return record.ToXml();
}
}
return null;
}
Given that a valid XPath expression has been specified, a call to the reader´s Next method returns the next available LogEventRecord object that allows retrieving the event´s details in XML format via the ToXml method.
Take the following C# code:
EventLog[] eventLogs;
eventLogs = EventLog.GetEventLogs(computername);
foreach (EventLog evt in eventLogs)
{
statusMessagesListBox.Items.Add("evt.Log.ToString(): " + evt.Log.ToString() + "\t\tevt.LogDisplayName: " + evt.LogDisplayName);
}
When I run that, my output looks like this:
evt.Log.ToString(): Application evt.LogDisplayName: Application
evt.Log.ToString(): HardwareEvents evt.LogDisplayName: Hardware Events
evt.Log.ToString(): Security evt.LogDisplayName: Security
And so on, like that. But why is there no Setup log? Furthermore, when I attempt to run this code:
var eventLog = new EventLog("Setup", computer);
eventLog.Clear();
eventLog.Dispose();
I get an error message that the log 'Setup' does not exist on that computer, even though it definitely does. The above code works for all other event logs except the Setup log.
How do I access the Setup event log?
For reference, the .NET frameworks being tried are 4.0 and 4.5, and the target computers are Windows 7 and 2008 R2.
The EventLog class only deals with Administrative event logs. The SetUp event log is an Operational log (you can see this in Event Viewer), so cannot be dealt with by this class.
To access the SetUp event log, you have to use the classes in the System.Diagnostics.Eventing.Reader namespace. You can iterate through the events using:
EventLogQuery query = new EventLogQuery("SetUp", PathType.LogName);
query.ReverseDirection = true; // this tells it to start with newest first
EventLogReader reader = new EventLogReader(query);
EventRecord eventRecord;
while ((eventRecord = reader.ReadEvent()) != null)
{
// each eventRecord is an item from the event log
}
Take a look at this MDSN article for more detailed examples.
In our code, we have to give the users a list of printers to choose from. The user then chooses a printer and it is checked to verify it is valid before printing. On a windows 2003 server with IIS 6, this works fine. On a windows 2008 server with IIS 7, it fails each time impersonate is set to true.
PrinterSettings printerSetting = new PrinterSettings();
printerSetting.PrinterName = ddlPrinterName.SelectedItem.Text;
if (!printerSetting.IsValid)
{
lblMsg.Text = "Server Printer is not valid.";
}
else
{
lblMsg.Text = "Success";
}
Each time this code is run, the "Server Printer is not valid" displays, only if impersonate is set to true. If impersonate is set to false, the success message is displayed.
The impersonation user has full rights to the printer.
Is there a way to catch the actual reason the printer is not valid?
Is there some other 2008 setting I should check?
update
I found that IsValid fails when the IIS7 application pools has "Enable 32-bit applications" is checked. This must be checked b/c we are using a 3rd party tool to print with, and it is a 32-bit application. It is not currently part of this test, so right now it is not causing this error.
IIS 7.0 is really locked down. It sounds like the server is not impersonating properly. The printer profiles are stored in the HK_CURRENT_USER hive of the user or if it is a locally connected printer in the HK_LOCAL_MACHINE.
I would use PROCMON from SYSINTERNALS to see the calls the IIS process is making.
You can try by querying the System using WMI. A way to achive this may be the following:
using System.Management;
private List<string> GetPrinters()
{
List<string> printerNames = new List<string>();
System.Management.ObjectQuery oquery =
new System.Management.ObjectQuery("SELECT * FROM Win32_Printer");
System.Management.ManagementObjectSearcher mosearcher =
new System.Management.ManagementObjectSearcher(oquery);
System.Management.ManagementObjectCollection moc = mosearcher.Get();
foreach (ManagementObject mo in moc)
{
System.Management.PropertyDataCollection pdc = mo.Properties;
foreach (System.Management.PropertyData pd in pdc)
{
if ((bool)mo["Network"])
{
printerNames.Add(mo[pd.Name]);
}
}
}
return printerNames;
}
After that, in a similar way, you may find other printer informations as if the printer is ready.
Find more here:
https://stackoverflow.com/a/1622931/2791580
Regards
Applications Pool
Advanced Setting
Process Model
Change Identity to User Administrators
oPD.PrinterSettings.PrinterName = \\10.10.1.1\myprintertnetwork;
I've had exactly the same problem, and I was able to solve it by temporarily leaving the impersonation context. Adapting your example, the following code:
PrinterSettings printerSetting = new PrinterSettings();
printerSetting.PrinterName = ddlPrinterName.SelectedItem.Text;
using (var wic = WindowsIdentity.Impersonate(IntPtr.Zero))
{
if (!printerSetting.IsValid)
{
lblMsg.Text = "Server Printer is not valid.";
}
else
{
lblMsg.Text = "Success";
}
// Do the remainder of your printing stuff here, but beware that
// your user context is different.
}
should yield the success message. (Credit for this solution goes to Jon Saffron.)
try set a default printer on [ control panel - devices and printers right click on one the ready printers and set as default it ]
I am working on an application which reads eventlogs(Application) from remote machines. I am making use of EventLog class in .net and then iterating on the Log entries but this is very slow. In some cases, some machines have 40000+ log entries and it takes hours to iterate through the entries.
what is the best way to accomplish this task? Are there any other classes in .net which are faster or in any other technology?
Man, I feel your pain. We had the exact same issue in our app.
Your solution has a branch depending on what server version you're running on and what server version your "target" machine is running on.
If you're both on Vista or Windows Server 2008, you're in luck. You should look at System.Diagnostics.Eventing.Reader.EventLogQuery and System.Diagnostics.Eventing.Reader.EventLogReader. These are new in .net 3.5.
Basically, you can build a query in XML and ship it over to run on the remote computer. Maybe you're just searching for events of a specific type, or maybe just new events from a specific point in time. The search runs on the remote machine, and then you just get back the matching events. The new classes are much faster than the old .net 2.0 way, but again, they are only supported on Vista or Windows Server 2008.
For our app when the target is NOT on Vista/Win2008, we downloaded the raw .evt file from the remote system, and then parsed the file using its binary format. There are several sources of data about the event log format for .evt files (pre-Vista), including link text and an article I recall on codeproject.com that had some c# code.
Vista and Windows Server 2008 machines use a new .evtx format that is a new format, so you can't use the same binary parsing approach across all versions. But the new EventLogQuery and EventLogReader classes are so fast that you won't have to. It's now perfectly speedy to just use the built-in classes.
Event Log Reader is horribly slow... too slow. WTF Microsoft?
Use LogParser 2.2 - Search for C# and LogParser on the Internet (or you can use the log parser commands from the command line). I don't want to duplicate the work already contributed by others.
I pull the log from the remote system by having the log exported as an EVTX file. I then copy the file from the remote system. This process is really quick - even with a network that spans the planet (I had issues with having the log exported to a network resource). Once you have it local, you can do your searches and processing.
There are multiple reasons for having the EVTX - I won't get into the reasons why we do this.
The following is a working example of the code to save a copy of the log as an EVTX:
(Notes: "device" is the network host name or IP. "LogName" is the name of the log desired: "System", "Security", or "Application". outputPathOnRemoteSystem is the path on the remote computer, such as "c:\temp\%hostname%.%LogName%.%YYYYMMDD_HH.MM%.evtx".)
static public bool DumpLog(string device, string LogName, string outputPathOnRemoteSystem, out string errMessage)
{
bool wasExported = false;
string errorMessage = "";
try
{
System.Diagnostics.Eventing.Reader.EventLogSession els = new System.Diagnostics.Eventing.Reader.EventLogSession(device);
els.ExportLogAndMessages(LogName, PathType.LogName, "*", outputPathOnRemoteSystem);
wasExported = true;
}
catch (UnauthorizedAccessException e)
{
errorMessage = "Unauthorized - Access Denied: " + e.Message;
}
catch (EventLogNotFoundException e)
{
errorMessage = "Event Log Not Found: " + e.Message;
}
catch (EventLogException e)
{
errorMessage = "Export Failed: " + e.Message + ", Log: " + LogName + ", Device: " + device;
}
errMessage = errorMessage;
return wasExported;
}
A good Explanation/Example can be found on MSDN.
EventLogSession session = new EventLogSession(Environment.MachineName);
// [System/Level=2] filters out the errors
// Where "Log" is the log you want to get data from.
EventLogQuery query = new EventLogQuery("Log", PathType.LogName, "*[System/Level=2]");
EventLogReader reader = new EventLogReader(query);
for (EventRecord eventInstance = reader.ReadEvent();
null != eventInstance;
eventInstance = reader.ReadEvent())
{
// Output or save your event data here.
}
When waiting 5-20 minutes with the old code this one does it in less than 10 seconds.
Maybe WMI can help you:
WMI with C#
Have you tried using the remoting features in powershell 2.0? They allow you to execute cmdlets (like ones to read event logs) on remote machines and return the results (as objects, of course) to the calling session.
You could place a Program at those machines that save the log to file and sends it to your webapplication i think that would be alot faster as you can do the looping local but im not sure how to do it so i cant ive you any code :(
I recently did such thing via WCF callback interface however my clients interacted with the server through WCF and adding a WCF Callback was easy in my project, full code with examples is available here
Just had the same issue and want to share my solution. It makes a search through application, system and security eventlogs from 260 seconds (using EventLog) about a 100 times faster (using EventLogQuery).
And this in a way where it is possible to check if the event message contains a pattern or any other check without the requirement of FormatDescription().
My trick is to use the same mechanism as PowerShells Get-WinEvent does and then pass it through the result check.
Here is my code to find all events within last 4 days where the event message contains a filter pattern.
string[] eventLogSources = {"Application", "System", "Security"};
var messagePattern = "*Your Message Search Pattern*";
var timeStamp = DateTime.Now.AddDays(-4);
var matchingEvents = new List<EventRecord>();
foreach (var eventLogSource in eventLogSources)
{
var i = 0;
var query = string.Format("*[System[TimeCreated[#SystemTime >= '{0}']]]",
timeStamp.ToUniversalTime().ToString("o"));
var elq = new EventLogQuery(eventLogSource, PathType.LogName, query);
var elr = new EventLogReader(elq);
EventRecord entryEventRecord;
while ((entryEventRecord = elr.ReadEvent()) != null)
{
if ((entryEventRecord.Properties)
.FirstOrDefault(x => (x.Value.ToString()).Contains(messagePattern)) != null)
{
matchingEvents.Add(entryEventRecord);
i++;
}
}
}
Maybe that the remote computers could do a little bit of computing. So this way your server would only deal with relevant information. It would be a kind of cluster using the remote computer to do some light filtering and the server would the the analysis part.