Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Who deleted the file? - HOW-TO 1

Status
Not open for further replies.

IlyaRabyy

Programmer
Nov 9, 2010
568
US
Colleagues,

Imagine you have files coming from a client via FTP.
This file is detected by some program, and then moved from FTP server to another (pre-production or production) server's directory.
There's a service program, that monitors these files' "arrivals" and "departures", and logs the file's attributes and From/To location into a table in a database.

Now, imagine that the file arrived to the designated directory on a Pre-Prod server, but then just disappeared w/o a trace... (And client then calls and inquires "Where's my data/paycheck/invoice/etc.?!" :-()

Problema!

There's a class FileSystemWatcher in .NET (since at least VS 2005) that detects - and can report or log - a file's creation, modification and deletion,

but,

AFAIK, it can't detect who or what deleted this file. (see here
And the Question is: how to detect who/what deleted, or renamed, or moved a file?

(The problem is, it may not be a logged in End User but some resident/service program working behind the scene...)

AHWBGA!

Regards,

Ilya
 
It can be done!

But you need to do a couple of things first

1) Set a group policy to allow auditing object access
2) Set auditing permissions on the folder you are saving the files in

(you'll also need elevated privileges for your application)


Once this is done, deleting a file from the folder will create Security Log entries, and you can write Vb code to read those entries. They include the username of whoever initiated the deletion
 
Thank you, StrongM!
Could you tell me the typical location and file name of this Security Log?

Regards,

Ilya
 
You can see it in the Event Log viewer, but that's not what I'm suggesting. It is the programmatic access, which can be done through the EventLog class in vb.net
 
None whatsoever. :-(
Here's the code (based on the sample in the VS Help, but made for Win Forms.
(Tried that code in VS 2022 As-Is - dinna work, it's made as Console app.)
I made an ASCII text file (.TXT) in a \Temp dir, ran this program from IDE. Modified and saved some text in this file... and no reaction from this program (nothing appeared on the screen).

Code:
using System;
using System.IO;
using System.Windows.Forms;

namespace SystemFileWatcherTestInC_
{
	public partial class Form1 : Form
	{
		String gcStartDir = (System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location));
		String gcWorkingDirRoot = "";
		public Form1()
		{
		InitializeComponent();
		}

		private void button1_Click(object sender, EventArgs e)
		{
			this.Close();
		}

		private void Form1_Load(object sender, EventArgs e)
		{
			gcStartDir = gcStartDir.Replace("bin\\Debug", "");
			dlgDirSelect.SelectedPath = gcStartDir;
			txtDirSelect.Text = gcStartDir;
			cboExtFilter.Items.Add("*.TXT");
			cboExtFilter.Items.Add("*.XML");
			cboExtFilter.Items.Add("*.DOCX");
			cboExtFilter.Items.Add("*.DOC");
			cboExtFilter.Items.Add("*.LOG");
		}

		private void btnDirSelect_Click(object sender, EventArgs e)
		{
		 	dlgDirSelect.SelectedPath = txtDirSelect.Text;
			DialogResult liAns = dlgDirSelect.ShowDialog();
			if (liAns != DialogResult.OK) { return; }
			else
			{
				txtDirSelect.Text = dlgDirSelect.SelectedPath;
				gcWorkingDirRoot = txtDirSelect.Text;
			}

		}

		private void btnStart_Click(object sender, EventArgs e)
		{
			var watcher = new FileSystemWatcher(txtDirSelect.Text);
			watcher.Filter = cboExtFilter.Text;

			watcher.NotifyFilter = NotifyFilters.Attributes
										| NotifyFilters.CreationTime
										| NotifyFilters.DirectoryName
										| NotifyFilters.FileName
										| NotifyFilters.LastAccess
										| NotifyFilters.LastWrite
										| NotifyFilters.Security
										| NotifyFilters.Size;

			watcher.Changed += OnChanged;
			watcher.Created += OnCreated;
			watcher.Deleted += OnDeleted;
			watcher.Renamed += OnRenamed;
			watcher.Error += OnError;
		}
		private void OnChanged(object sender, FileSystemEventArgs e)	   //	  static 
		{
		if (e.ChangeType != WatcherChangeTypes.Changed) { return; }
		else {rtbReport.Text += "Changed: " + e.FullPath; }			//	Console.WriteLine($");
		}
		private void OnCreated(object sender, FileSystemEventArgs e)      //	  static 
		{
		if (e.ChangeType != WatcherChangeTypes.Created) { return; }
		else { rtbReport.Text += "Created: " + e.FullPath; }        //	Console.WriteLine($");
		}

		private void OnDeleted(object sender, FileSystemEventArgs e)      //	  static 
		{
		if (e.ChangeType != WatcherChangeTypes.Deleted) { return; }
		else { rtbReport.Text += "Deleted: " + e.FullPath; }        //	Console.WriteLine($");
		}
		private void OnRenamed(object sender, FileSystemEventArgs e)      //	  static 
		{
			if (e.ChangeType != WatcherChangeTypes.Renamed) { return; }
			else { rtbReport.Text += "Renamed: " + e.FullPath + "\r\n"; }        //	Console.WriteLine($");	
																										//	+ "		Old: " + e.OldFullPath + "\r\n" }
		private static void OnError(object sender, ErrorEventArgs e) =>
					  PrintException(e.GetException());
		private static void PrintException(Exception ex)
		{
		if (ex != null)	 {
			string lsErrMsg = "Error: " + ex.Message + "\n";
		//			Console.WriteLine($"Message: {ex.Message}");
		lsErrMsg += ("Stasck Trace: " + ex.StackTrace + "\n");	// Console.WriteLine("Stacktrace:");
		// Console.WriteLine(ex.StackTrace);
		// Console.WriteLine();
		// PrintException(ex.InnerException);
			}
		}
	}
}
// Form Designer
namespace SystemFileWatcherTestInC_
{
	partial class Form1
	{
		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.IContainer components = null;

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
		protected override void Dispose(bool disposing)
		{
		if (disposing && (components != null))
		{
		components.Dispose();
		}
		base.Dispose(disposing);
		}

		#region Windows Form Designer generated code

		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.btnExit = new System.Windows.Forms.Button();
			this.dlgDirSelect = new System.Windows.Forms.FolderBrowserDialog();
			this.txtDirSelect = new System.Windows.Forms.TextBox();
			this.label1 = new System.Windows.Forms.Label();
			this.btnDirSelect = new System.Windows.Forms.Button();
			this.rtbReport = new System.Windows.Forms.RichTextBox();
			this.btnStart = new System.Windows.Forms.Button();
			this.label2 = new System.Windows.Forms.Label();
			this.cboExtFilter = new System.Windows.Forms.ComboBox();
			this.SuspendLayout();
			// 
			// btnExit
			// 
			this.btnExit.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
			this.btnExit.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
			this.btnExit.Location = new System.Drawing.Point(988, 503);
			this.btnExit.Name = "btnExit";
			this.btnExit.Size = new System.Drawing.Size(75, 24);
			this.btnExit.TabIndex = 0;
			this.btnExit.Text = "E&xit";
			this.btnExit.UseVisualStyleBackColor = true;
			this.btnExit.Click += new System.EventHandler(this.button1_Click);
			// 
			// txtDirSelect
			// 
			this.txtDirSelect.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
			this.txtDirSelect.Font = new System.Drawing.Font("Arial", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
			this.txtDirSelect.Location = new System.Drawing.Point(93, 22);
			this.txtDirSelect.Name = "txtDirSelect";
			this.txtDirSelect.Size = new System.Drawing.Size(930, 23);
			this.txtDirSelect.TabIndex = 1;
			// 
			// label1
			// 
			this.label1.AutoSize = true;
			this.label1.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
			this.label1.Location = new System.Drawing.Point(12, 25);
			this.label1.Name = "label1";
			this.label1.Size = new System.Drawing.Size(69, 16);
			this.label1.TabIndex = 2;
			this.label1.Text = "Select Dir";
			// 
			// btnDirSelect
			// 
			this.btnDirSelect.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
			this.btnDirSelect.Font = new System.Drawing.Font("Arial", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
			this.btnDirSelect.Location = new System.Drawing.Point(1031, 25);
			this.btnDirSelect.Name = "btnDirSelect";
			this.btnDirSelect.Size = new System.Drawing.Size(41, 23);
			this.btnDirSelect.TabIndex = 3;
			this.btnDirSelect.Text = "...";
			this.btnDirSelect.UseVisualStyleBackColor = true;
			this.btnDirSelect.Click += new System.EventHandler(this.btnDirSelect_Click);
			// 
			// rtbReport
			// 
			this.rtbReport.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
            | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
			this.rtbReport.Location = new System.Drawing.Point(29, 54);
			this.rtbReport.Name = "rtbReport";
			this.rtbReport.Size = new System.Drawing.Size(1043, 434);
			this.rtbReport.TabIndex = 4;
			this.rtbReport.Text = "";
			// 
			// btnStart
			// 
			this.btnStart.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
			this.btnStart.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
			this.btnStart.Location = new System.Drawing.Point(549, 503);
			this.btnStart.Name = "btnStart";
			this.btnStart.Size = new System.Drawing.Size(75, 24);
			this.btnStart.TabIndex = 5;
			this.btnStart.Text = "&Go";
			this.btnStart.UseVisualStyleBackColor = true;
			this.btnStart.Click += new System.EventHandler(this.btnStart_Click);
			// 
			// label2
			// 
			this.label2.AutoSize = true;
			this.label2.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
			this.label2.Location = new System.Drawing.Point(17, 503);
			this.label2.Name = "label2";
			this.label2.Size = new System.Drawing.Size(84, 16);
			this.label2.TabIndex = 6;
			this.label2.Text = "Select Filter";
			// 
			// cboExtFilter
			// 
			this.cboExtFilter.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
			this.cboExtFilter.FormattingEnabled = true;
			this.cboExtFilter.Location = new System.Drawing.Point(126, 503);
			this.cboExtFilter.Name = "cboExtFilter";
			this.cboExtFilter.Size = new System.Drawing.Size(384, 24);
			this.cboExtFilter.TabIndex = 7;
			// 
			// Form1
			// 
			this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
			this.ClientSize = new System.Drawing.Size(1084, 540);
			this.Controls.Add(this.cboExtFilter);
			this.Controls.Add(this.label2);
			this.Controls.Add(this.btnStart);
			this.Controls.Add(this.rtbReport);
			this.Controls.Add(this.btnDirSelect);
			this.Controls.Add(this.label1);
			this.Controls.Add(this.txtDirSelect);
			this.Controls.Add(this.btnExit);
			this.Name = "Form1";
			this.Text = "Form1";
			this.Load += new System.EventHandler(this.Form1_Load);
			this.ResumeLayout(false);
			this.PerformLayout();
		}

		#endregion

		private System.Windows.Forms.Button btnExit;
		private System.Windows.Forms.FolderBrowserDialog dlgDirSelect;
		private System.Windows.Forms.TextBox txtDirSelect;
		private System.Windows.Forms.Label label1;
		private System.Windows.Forms.Button btnDirSelect;
		private System.Windows.Forms.RichTextBox rtbReport;
		private System.Windows.Forms.Button btnStart;
		private System.Windows.Forms.Label label2;
		private System.Windows.Forms.ComboBox cboExtFilter;
	}
}

What am I doing wrong?

Regards,

Ilya
 
Rite!
I can try it in VB.
Will take some head scratching to translate it from C# to VB, though...

Regards,

Ilya
 
Here's about the simplest version I can put togethr that should illustrate how you could do it:

Code:
[COLOR=blue]Imports System.IO

Public Class Form1
    Private fsWatch As FileSystemWatcher

    Private Sub StartWatch_Click(sender As Object, e As EventArgs) Handles StartWatch.Click

        fsWatch = New FileSystemWatcher("D:\Downloads\DeleteMeSoon")
        fsWatch.SynchronizingObject = Me

        AddHandler fsWatch.Deleted, AddressOf FileDeleted
        AddHandler fsWatch.Changed, AddressOf FileChanged
        AddHandler fsWatch.Renamed, AddressOf FileRenamed
        fsWatch.EnableRaisingEvents = True
    End Sub

    Private Sub FileDeleted(ByVal sender As Object, ByVal e As FileSystemEventArgs)
        Debug.Print(e.FullPath & " deleted " & whodidit())
    End Sub

    Private Sub FileChanged(ByVal sender As Object, ByVal e As FileSystemEventArgs)
        Debug.Print(e.FullPath & " changed " & whodidit())
    End Sub

    Private Sub FileRenamed(ByVal sender As Object, ByVal e As RenamedEventArgs)
        Debug.Print(e.OldFullPath & " renamed to " & e.FullPath & whodidit())
    End Sub

    [COLOR=green]'For this to work, assumes that relevant auditing permission has been set on the folder to being watched, that the relevant group policy has been set, and t5hat this program is running with elevated permissions (e.g Admin)[/color]
    Public Function whodidit() As String
        Dim eventLogEntry As EventLogEntry
        Dim mylog As New EventLog("Security")
        Dim mostrecent = mylog.Entries.Count - 1
        Dim current As Long

        whodidit = ""
        For current = mostrecent To 0 Step -1
            eventLogEntry = mylog.Entries(current)
            If eventLogEntry.InstanceId = 4663 Then ' file access audit event
                If eventLogEntry.ReplacementStrings(9) = "0x10000" Then [COLOR=green]' access was of type 'delete'; this is actually raised by deleting, moving or renaming a file[/color]
                    whodidit = " by " & eventLogEntry.ReplacementStrings(1) & " at " & eventLogEntry.TimeGenerated.ToString & " via " & eventLogEntry.ReplacementStrings(11)
                    Exit For
                End If
            End If
        Next
    End Function
End Class[/color]

>relevant group policy has been set

e.g

Local Group Policy Editor -> computer configuration -> Windows Settings -> Security Settings -> Advanced Audit Policy Configuration -> Object Access -> Audit File System

and enable 'Success'
 
Unfortunately, see the screenshot:

2024-03-08_No_Advanced_Audit_Polocy_Configuration_hfc13u.jpg


It's on my W/S, not on a network share.
Besides, our company's cybersecurity division set very strict rules for the end users (even for S/W developers like yours truly). Maybe this is why my code doesn't work?


Regards,

Ilya
 
It isn't in the newer settings panels, so ity doesn't come up in a search.


Which is why I gave the route that I did,. starting with launching the Local Group Policy Editor. If you don't know how to do that, then try searching for Edit Group Policy

That being said, if your cybersecurity team have locked down your PC then this probably isn't going to work anyway.
 
Alrite, here's the latest development:

1. Thank you for your code StrongM! [bow]
With some minor tweaking and embellishments, it came to life and started breathing! :)
2024-03-08_FileWatcherRunAsAdmin_MsgBox_v6ndnv.jpg


Here's the code (with my modifications):
Code:
	Public Function whodidit() As String
		Dim eventLogEntry As EventLogEntry
		Dim mylog As New EventLog("Security")
		Dim mostrecent = mylog.Entries.Count - 1
		Dim current As Long

		whodidit = ""
		For current = mostrecent To 0 Step -1
			eventLogEntry = mylog.Entries(current)
			If eventLogEntry.InstanceId = 4663 Then ' file access audit event
				If eventLogEntry.ReplacementStrings(9) = "0x10000" Then  'access was of type 'delete';
					'this is actually raised by deleting, moving or renaming a file
					whodidit = " by " & eventLogEntry.ReplacementStrings(1) & " at " & eventLogEntry.TimeGenerated.ToString &
									" via " & eventLogEntry.ReplacementStrings(11)
					MsgBox("File was modified, moved or deleted" + vbCrLf + whodidit)
					rtbReport.Text += whodidit
					rtbReport.Refresh()
					Exit For
				End If
			End If
		Next

	End Function

and the form's screenshot:
2024-03-08_FileWatcherRunAsAdmin_RTFBox_co7anm.jpg


2. This PB$ (redacted) is the name of the W/S, and I'd like to also have a name of the User who did it.

Any suggestions?

Regards,

Ilya
 
Windows Defender is a Service so it is the name of the service account thaty the service is logged in under that you will get for this, rather than a user.
 
Well, one problem's solved, one to go.
But thew latter is the matter of another thread.
Thank you, StrongM!


Regards,

Ilya
 
One more thing: you stated (in the code) that

If eventLogEntry.ReplacementStrings(9) = "0x10000" Then ' access was of type 'delete'

I tried to find in the VS 2022 Help codes for other actions/events, like "create" and "modify", and could not...
Could you point me in the right direction, please?

Regards,

Ilya
 
Thank you!
Studying...
Looks like exactly what I need...
Works!
2024-03-11_FileWatcher_per_StrongM_tips_s1ujvc.jpg


[thanks2]

Regards,

Ilya
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top