Click here to Skip to main content
11,577,721 members (61,750 online)
Click here to Skip to main content

Monitoring Access to Your Shared Files on Network

, 9 Mar 2010 CPOL 30.8K 3.9K 53
Rate this:
Please Sign up or sign in to vote.
ShareMonitor allows you to monitor any access to your network shared files

Introduction

ShareMonitor allows you to monitor any access to your network shared files. When a user remotely opens shared files on your computer, the application detects it and displays information such as who opened it, when it was opened, duration, etc. about that file. All details will be logged and can be saved to .CSV or .XML files for further analysis.
You can also disconnect any active connection whenever you want.

Using the Code

Using “OpenFiles.exe”, it queries opened files in regular periods of time. It continuously compares sequence of OpenFiles.exe outputs and updates the data table. For newly opened files, it inserts related data into a data table. Next time if the file is not still open, it sets it as closed and stores closed time for that file and repeats this routine.

OpenFiles.exe” was the simplest way possible to find out access to shared resources. Of course there must some Windows API for it and it's better to use them but they seems to be undocumented and I couldn't find anything. Please let me know if you found any related Windows API.

As I tested the program, I noticed that it can't show non-English (Unicode) file names. As this problem refers to output of OpenFiles.exe, I couldn't fix it by code-page manipulating.

Note: OpenFiles.exe is a Windows tool that shows shared files which are currently opened by others. This file is in WINDOWS\system32 folder.

OpenFiles.JPG

Openfiles.exe output has some information such as connection ID, user who accessed the file, filename, etc. These data are stored in a data table that is created in the code below. There is an extra boolean column named "Closed" which holds the state of the shared file: still in use or closed.

private void PrepareDataTable()
{
    dataTable = new DataTable("ShareMonitor");
    dataTable.Columns.Add("Opened at", typeof(DateTime));
    dataTable.Columns.Add("Closed at", typeof(DateTime));
    dataTable.Columns.Add("Duration", typeof(TimeSpan));

    dataTable.Columns.Add("Host Name");
    dataTable.Columns.Add("ID", typeof(int));
    dataTable.Columns.Add("User Name");
    dataTable.Columns.Add("Type");
    dataTable.Columns.Add("Locks");
    dataTable.Columns.Add("Open Mode");
    dataTable.Columns.Add("File/Folder");

    dataTable.Columns.Add("Closed", typeof(bool));

    dataTable.PrimaryKey = new DataColumn[] { dataTable.Columns["ID"] };
}

RefreshData() is the main method of application which is run periodically by a timer. In this method, I create a new process and execute openfiles.exe with "/query /FO CSV /v" parameters. These parameters mean that I want to get a detailed comma-separated list of shared files which are currently in use.

RedirectStandardOutput property lets you get the process output (which is sent to the console).

Before reading the output (lines), I set all unclosed connections to "closed". This is because they may be closed since the last check and I may not find them in current openfiles output anymore.

Finally, I check the lines string variable. Each line represents one file connection. If connection ID does not exist in the datatable, I insert it as a new open connection. Otherwise, if connection ID exists in datatable, it means that the connection was opened before and is still open. So I set the "Closed" field to false and clear "Closed at" field.

By setting FirstDisplayedScrollingRowIndex property of the grid, you can be assured that newly added connections will be shown in the grid. Something that we call auto scrolling grid rows.

private void RefreshData()
{
    var process = new Process();
    process.StartInfo.FileName = "openfiles.exe";
    process.StartInfo.Arguments = "/query /FO CSV /v";
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.CreateNoWindow = true;
    process.StartInfo.RedirectStandardOutput = true;
    try
    {
        process.Start();
        if ((process.StandardOutput != null))
        {
            var result = process.StandardOutput.ReadToEnd().Trim().Replace("\"", "");
            var lines = result.Split('\n');
            foreach (DataRow row in dataTable.Rows)
            {
                //set all previous open connections to closed because 
                //they may not be still in use!
                var closed = row.Field<bool?>("Closed");
                if (closed == null || closed.Value == false)
                {
                    row["Closed"] = true;
                    row["Closed at"] = DateTime.Now.ToString("G");
                }
                else
                {
                    if (row["Duration"] == DBNull.Value)
                        row["Duration"] = ((DateTime)row["Closed at"]) - 
			((DateTime)row["Opened at"]);
                }
            }

            var firstLineIndex = 1 + lines.Cast<string>().ToList().FindIndex
				(l => l.Contains("Hostname"));
            for (int i = firstLineIndex; i < lines.Count() && firstLineIndex > 0; i++)
            {
                var fields = lines[i].Split(',');
                var row = dataTable.Rows.Find(fields[1]); //ID
                if (row == null) 	//it is a new file and not exists 
				//in datatable... so add it
                {
                    var newRow = dataTable.NewRow();
                    newRow["Opened at"] = DateTime.Now.ToString("yyyy MM dd HH:mm:ss");
                    newRow["Host Name"] = fields[0];
                    newRow["ID"] = fields[1];
                    newRow["User Name"] = fields[2];
                    newRow["Type"] = fields[3];
                    newRow["Locks"] = fields[4];
                    newRow["Open Mode"] = fields[5];
                    newRow["File/Folder"] = fields[6];
                    dataTable.Rows.Add(newRow);

                    //auto scroll
                    var gridRow = grdMain.Rows.Cast<DataGridViewRow>().
                        Where(r => (r.DataBoundItem as DataRowView).Row.Field<int>("ID") 
				== newRow.Field<int>("ID")).
                        SingleOrDefault();
                    if (gridRow != null)
                        grdMain.FirstDisplayedScrollingRowIndex = gridRow.Index;

                }
                else  //it is still in use and not closed
                {
                    row["Closed"] = false;
                    row["Closed at"] = DBNull.Value;
                }
            }

            //auto size columns
            grdMain.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
        }
        process.WaitForExit();
    }
    catch (Exception e)
    {
        lblMsg.Text = " Error: " + e.Message + " : " + DateTime.Now.ToShortTimeString();
    }
    finally
    {
        process.Close();
    }
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Alan Zawari
Software Developer (Senior)
United States United States
Blog: C# Tips

You may also be interested in...

Comments and Discussions

 
GeneralMy vote of 5 Pin
satya raaz mali18-Nov-10 15:22
membersatya raaz mali18-Nov-10 15:22 
GeneralRe: My vote of 5 Pin
Simon Clifton Cardenas4-Jan-11 20:22
memberSimon Clifton Cardenas4-Jan-11 20:22 
GeneralHardcoded for English Language - Not for Located Windows Versions Pin
Member 335868730-Jun-10 5:54
memberMember 335868730-Jun-10 5:54 
GeneralRe: Hardcoded for English Language - Not for Located Windows Versions Pin
Abdollah Zawari30-Jun-10 6:01
memberAbdollah Zawari30-Jun-10 6:01 
GeneralWindows API NetFileEnum Pin
Norbert Bietsch18-Mar-10 12:49
memberNorbert Bietsch18-Mar-10 12:49 
GeneralRe: Windows API NetFileEnum Pin
Abdollah Zawari20-Mar-10 9:36
memberAbdollah Zawari20-Mar-10 9:36 
GeneralRe: Windows API NetFileEnum Pin
Truedarkside28-Apr-10 9:23
memberTruedarkside28-Apr-10 9:23 
GeneralRe: Windows API NetFileEnum Pin
Abdollah Zawari2-May-10 1:51
memberAbdollah Zawari2-May-10 1:51 
GeneralNice Job Pin
Amir Razmjou9-Mar-10 2:12
memberAmir Razmjou9-Mar-10 2:12 
GeneralRe: Nice Job Pin
Abdollah Zawari9-Mar-10 2:14
memberAbdollah Zawari9-Mar-10 2:14 
Generalerror Pin
mikejobu238-Mar-10 10:10
membermikejobu238-Mar-10 10:10 
GeneralRe: error Pin
Abdollah Zawari8-Mar-10 17:35
memberAbdollah Zawari8-Mar-10 17:35 
GeneralRe: error Pin
mikejobu239-Mar-10 2:00
membermikejobu239-Mar-10 2:00 
AnswerRe: error (FIXED) Pin
Abdollah Zawari9-Mar-10 7:23
memberAbdollah Zawari9-Mar-10 7:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150603.1 | Last Updated 9 Mar 2010
Article Copyright 2010 by Alan Zawari
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid