Programmatically determine user who last modified file on Windows?
Asked Answered
H

2

12

I've been tasked with writing a simple command line utility in C# that will monitor a directory on a server that several users will be accessing to copy/cut/paste/view data. I used FileSystemWatcher to do this but it's lacking a couple features.

Is it possible to determine the user or at least the computer name from where the file is being accessed/modified?

(Note: This doesn't have to be with FileSystemWatcher, I'm looking for ANY way to do this.)

Heer answered 6/12, 2011 at 20:56 Comment(6)
I don't believe the OS keeps track of this information.Wondrous
This gives two decent ways of doing it.Priorate
@J.Kommer Ah thanks. I was sure someone had asked this before, I just couldn't find it.Heer
I have done exactly what you are looking to do using FileSystemWatcher. there are certain triggers / events that you can setup that will capture things like edit, add, delete. That's set using the NotifyFilterAgma
using this code will get you started -- it from the example that you listed SystemFileWatcher Link, within those events you could also write additional custom methods that get at the domain user and things like that using system.security.principalAgma
@DJKRAZE: FileSystemWatcher events don't capture the name of the user or computer that made the change.Shuma
D
7

I don't think you'll be able to monitor this from C# directly. Not without the help of the host operating system anyway. Windows and NTFS allow you to audit a particular directory and log the accesses in the Security event log for the host machine (so the server hosting the share would have to audit, not the client).

From KB310399 - How to audit user access of files, folders, and printers in Windows XP

Auditing User Access of Files, Folders, and Printers

The audit log appears in the Security log in Event Viewer. To enable this feature:

  1. Click Start, click Control Panel, click Performance and Maintenance, and then click Administrative Tools.
  2. Double-click Local Security Policy.
  3. In the left pane, double-click Local Policies to expand it.
  4. In the left pane, click Audit Policy to display the individual policy settings in the right pane.
  5. Double-click Audit object access.
  6. To audit successful access of specified files, folders and printers, select the Success check box.
  7. To audit unsuccessful access to these objects, select the Failure check box.
  8. To enable auditing of both, select both check boxes.
  9. Click OK.

Specifying Files, Folders, and Printers to Audit

After you enable auditing, you can specify the files, folders, and printers that you want audited. To do so:

  1. In Windows Explorer, locate the file or folder you want to audit. To audit a printer, locate it by clicking Start, and then clicking Printers and Faxes.
  2. Right-click the file, folder, or printer that you want to audit, and then click Properties.
  3. Click the Security tab, and then click Advanced.
  4. Click the Auditing tab, and then click Add.
  5. In the Enter the object name to select box, type the name of the user or group whose access you want to audit. You can browse the computer for names by clicking Advanced, and then clicking Find Now in the Select User or Group dialog box.
  6. Click OK.
  7. Select the Successful or Failed check boxes for the actions you want to audit, and then click OK.
  8. Click OK, and then click OK.

The process is similar for the server operating systems and Windows Vista/Windows 7. If you go this route, you can have the C# program read the event log (See EventLog class) to look for the data you want.

Note: Starting with vista you must be and (UAC elevated if needed) administrator to read them from code.

Delighted answered 6/12, 2011 at 21:5 Comment(4)
I added the link to the EventLog class and a note about needing elevation to access such logs, hope you don't mind Joshua (I posted an answer but your's is a lot better, so i just completed it and removed mine)Hachmin
Great answer thanks, there's a problem though. When opening up the properties of a directory as the in step 2 of part 2, there is no security tab. Has anyone tried this and has a security tab? Do I need to enable something?Heer
Nevermind, fixed it following this geekswithblogs.net/ram/archive/2006/03/09/71789.aspxHeer
@VirtualBlackFox: Nope, both of those edits are fine with me. I'm always on 7 so it is easy for me to overlook needing to elevate as I know when I do and when I don't need to elevate. (I run as a normal, limited user (no admin permissions) on my computers, so I'm used to elevating when needed... which isn't all that often, as the detractors would like you to believe.)Delighted
A
0

Make sure to have WMI installed or enabled on your PC, also make sure to add a reference to System.Management and System.Management.Instrumentation as well. There is also a C# and VB WMI scripting application GUI that you can download to run and test WMI Queries against as well Google that one. Since I work for Dept of Defense there are certain things that I can get to from here in regards to the web other things are blocked out so please forgive me if I don't post certain web links.

Here is something to get you started

    ManagementScope mgtScope = new ManagementScope("\\\\ComputerName\\root\\cimv2");
    // you could also replace the username in the select with * to query all objects
    ObjectQuery objQuery = new ObjectQuery("SELECT username FROM Win32_ComputerSystem");

    ManagementObjectSearcher srcSearcher = new ManagementObjectSearcher(mgtScope, objQuery);

    ManagementObjectCollection colCollection = srcSearcher.Get();

    foreach (ManagementObject curObjCurObject in colCollection)
    {

        Console.WriteLine(curObjCurObject["username"].ToString());
    } 

  //if you want ot get the name of the machine that changed it once it gets into that  Event change the query to look like this. I just tested this locally and it does work 

    ManagementObjectSearcher mosQuery = new ManagementObjectSearcher("SELECT * FROM Win32_Process WHERE ProcessId = " + Process.GetCurrentProcess().Id.ToString());
    ManagementObjectCollection queryCollection1 = mosQuery.Get();
    foreach (ManagementObject manObject in queryCollection1)
    {
        Console.WriteLine("Name : " + manObject["name"].ToString());
        Console.WriteLine("Version : " + manObject["version"].ToString());
        Console.WriteLine("Manufacturer : " + manObject["Manufacturer"].ToString());
        Console.WriteLine("Computer Name : " + manObject["csname"].ToString());
        Console.WriteLine("Windows Directory : " + manObject["WindowsDirectory"].ToString());
    }  
Agma answered 7/12, 2011 at 15:51 Comment(4)
You might want to seriously have a look at your formatting of answers. I have tried to edit some of your other answers, but you consistently have bad formatting. Look at the text before your code section. What's with all the slashes?Grayson
I quote "//make sure to.." "// also make sure to add" "// There is also a C#" " //since I work for Dept " .... What's with all the slashes? And besides that, many of your answers have wrongly formatted code blocks, containing what should be text. I don't know if you're perhaps on a system that does not show it properly to you, but you might want to have a look.Grayson
I will make sure to double check next time.. sorryAgma
@Bart: +1 for the funny yet constructive comment, no offense meant to anyone :)Protagonist

© 2022 - 2024 — McMap. All rights reserved.