Descubra el nombre de usuario (quién) modificó el archivo en C #

Estoy usando un FileSystemWatcher para monitorear una carpeta. Pero cuando ocurre algún evento en el directorio, no sé cómo buscar quién tuvo un impacto en ese archivo. Traté de usar EventLog. Simplemente no podría funcionar. ¿Hay alguna otra forma de hacerlo?

No recuerdo dónde encontré este código, pero es una alternativa al uso de pInvoke, que creo que es un poco exagerado para esta tarea. Use FileSystemWatcher para ver la carpeta y cuando se desate un evento, puede averiguar qué usuario hizo que el archivo cambie usando este código:

 private string GetSpecificFileProperties(string file, params int[] indexes) { string fileName = Path.GetFileName(file); string folderName = Path.GetDirectoryName(file); Shell32.Shell shell = new Shell32.Shell(); Shell32.Folder objFolder; objFolder = shell.NameSpace(folderName); StringBuilder sb = new StringBuilder(); foreach (Shell32.FolderItem2 item in objFolder.Items()) { if (fileName == item.Name) { for (int i = 0; i < indexes.Length; i++) { sb.Append(objFolder.GetDetailsOf(item, indexes[i]) + ","); } break; } } string result = sb.ToString().Trim(); //Protection for no results causing an exception on the `SubString` method if (result.Length == 0) { return string.Empty; } return result.Substring(0, result.Length - 1); } 

Shell32 es una referencia a la DLL: Microsoft Shell Controls And Automation : es una referencia COM

Aquí hay algunos ejemplos de cómo llamas al método:

 string Type = GetSpecificFileProperties(filePath, 2); string ObjectKind = GetSpecificFileProperties(filePath, 11); DateTime CreatedDate = Convert.ToDateTime(GetSpecificFileProperties(filePath, 4)); DateTime LastModifiedDate = Convert.ToDateTime(GetSpecificFileProperties(filePath, 3)); DateTime LastAccessDate = Convert.ToDateTime(GetSpecificFileProperties(filePath, 5)); string LastUser = GetSpecificFileProperties(filePath, 10); string ComputerName = GetSpecificFileProperties(filePath, 53); string FileSize = GetSpecificFileProperties(filePath, 1); 

Debe habilitar la auditoría en el sistema de archivos (y la auditoría solo está disponible en NTFS). Para ello, aplica una política de grupo o política de seguridad local. También deberá habilitar la auditoría en el archivo que desea monitorear. Lo haces de la misma manera que modificas los permisos en el archivo.

Los eventos de auditoría se escriben luego en el registro de eventos de seguridad. Deberá supervisar este registro de eventos para los eventos de auditoría que le interesen. Una forma de hacerlo es crear una tarea progtwigda que inicie una aplicación cuando se registren los eventos que le interesan. Empezar un nuevo proceso para cada evento solo es viable si los eventos no se registran a una tasa muy alta. De lo contrario, es probable que experimente problemas de rendimiento.

Básicamente, no desea mirar los contenidos o atributos del archivo (que la función de shell GetFileDetails ). Además, no desea utilizar una API de uso compartido de archivos para obtener el usuario de red que tiene el archivo abierto (lo que hace NetGetFileInfo ). Desea conocer el usuario del proceso que modificó por última vez el archivo. Esta información normalmente no es registrada por Windows porque requeriría demasiados recursos para hacer eso para todas las actividades del archivo. En su lugar, puede activar selectivamente la auditoría para usuarios específicos que realizan acciones específicas en archivos específicos (y carpetas).

Parece que necesitará invocar las funciones de la API de Windows para obtener lo que desea, lo que implica PInvoke. Algunas personas en otro foro lo han estado buscando y han descubierto algo , puedes encontrar su solución aquí . Sin embargo, parece funcionar solo con archivos en recursos compartidos de red (no en su máquina local).

Para referencia futura, este es el código publicado por dave4dl :

 [DllImport("Netapi32.dll", SetLastError = true)] static extern int NetApiBufferFree(IntPtr Buffer); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)] struct FILE_INFO_3 { public int fi3_id; public int fi3_permission; public int fi3_num_locks; public string fi3_pathname; public string fi3_username; } [DllImport("netapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] static extern int NetFileEnum( string servername, string basepath, string username, int level, ref IntPtr bufptr, int prefmaxlen, out int entriesread, out int totalentries, IntPtr resume_handle ); [DllImport("netapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] static extern int NetFileGetInfo( string servername, int fileid, int level, ref IntPtr bufptr ); private int GetFileIdFromPath(string filePath) { const int MAX_PREFERRED_LENGTH = -1; int dwReadEntries; int dwTotalEntries; IntPtr pBuffer = IntPtr.Zero; FILE_INFO_3 pCurrent = new FILE_INFO_3(); int dwStatus = NetFileEnum(null, filePath, null, 3, ref pBuffer, MAX_PREFERRED_LENGTH, out dwReadEntries, out dwTotalEntries, IntPtr.Zero); if (dwStatus == 0) { for (int dwIndex = 0; dwIndex < dwReadEntries; dwIndex++) { IntPtr iPtr = new IntPtr(pBuffer.ToInt32() + (dwIndex * Marshal.SizeOf(pCurrent))); pCurrent = (FILE_INFO_3)Marshal.PtrToStructure(iPtr, typeof(FILE_INFO_3)); int fileId = pCurrent.fi3_id; //because of the path filter in the NetFileEnum function call, the first (and hopefully only) entry should be the correct one NetApiBufferFree(pBuffer); return fileId; } } NetApiBufferFree(pBuffer); return -1; //should probably do something else here like throw an error } private string GetUsernameHandlingFile(int fileId) { string defaultValue = "[Unknown User]"; if (fileId == -1) { return defaultValue; } IntPtr pBuffer_Info = IntPtr.Zero; int dwStatus_Info = NetFileGetInfo(null, fileId, 3, ref pBuffer_Info); if (dwStatus_Info == 0) { IntPtr iPtr_Info = new IntPtr(pBuffer_Info.ToInt32()); FILE_INFO_3 pCurrent_Info = (FILE_INFO_3)Marshal.PtrToStructure(iPtr_Info, typeof(FILE_INFO_3)); NetApiBufferFree(pBuffer_Info); return pCurrent_Info.fi3_username; } NetApiBufferFree(pBuffer_Info); return defaultValue; //default if not successfull above } private string GetUsernameHandlingFile(string filePath) { int fileId = GetFileIdFromPath(filePath); return GetUsernameHandlingFile(fileId); } 

Esto se ha discutido muchas veces. Mi respuesta de la misma pregunta:

No puede hacer esto de forma asíncrona con FileSystemWatcher; sin embargo, puede hacerlo de forma síncrona utilizando el controlador de filtro del sistema de archivos. El controlador le permite obtener el nombre de usuario de la cuenta que realiza la operación.

Use el código publicado por dave4dl y actualice declare struct FILE_INFO_3 como sigue, puede supervisar el nombre de usuario de crear y actualizar la acción del archivo (Es como una combinación de FileSystemWatcher y las funciones de OpenFiles.exe de FileSharing Server)

 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct FILE_INFO_3 { public int fi3_id; public int fi3_permission; public int fi3_num_locks; [MarshalAs(UnmanagedType.LPWStr)] public string fi3_pathname; [MarshalAs(UnmanagedType.LPWStr)] public string fi3_username; }