在C#中获取文件最后修改人(适配Azure AD环境)
解决Azure AD环境下获取文件最后修改人问题
首先要明确:你之前的代码获取的是文件所有者,并非文件的最后修改人。在Azure AD环境下,由于身份标识体系的差异,直接将SID转换为NTAccount会抛出"部分或全部身份引用无法转换"的异常,以下是几种可行的替代方案:
方案1:先获取SID,兼容无法转换的身份
先获取文件所有者的SID,再尝试转换为NTAccount,若转换失败则直接返回SID字符串,避免异常:
FileSecurity fileSecurity = file.GetAccessControl(); IdentityReference ownerSid = fileSecurity.GetOwner(typeof(SecurityIdentifier)); string ownerName; try { ownerName = ownerSid.Translate(typeof(NTAccount)).Value; } catch (IdentityNotMappedException) { // Azure AD身份无法转换时直接返回SID ownerName = ownerSid.Value; }
方案2:使用WMI查询文件的最后修改人
通过WMI的Win32_File类可以直接获取文件的LastModifiedBy属性,这是更贴合需求的方式(真正获取最后修改人,而非所有者):
using System.Management; string filePath = @"C:\Your\File\Path.txt"; string query = $"SELECT LastModifiedBy FROM CIM_DataFile WHERE Name = '{filePath.Replace("\\", "\\\\")}'"; using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(query)) { foreach (ManagementObject obj in searcher.Get()) { string lastModifiedBy = obj["LastModifiedBy"]?.ToString(); Console.WriteLine($"最后修改人:{lastModifiedBy}"); } }
注意:使用WMI需要管理员权限,且文件路径需要转义双反斜杠。
方案3:利用Windows API获取文件信息
通过P/Invoke调用GetFileInformationByHandleEx获取文件的扩展信息,其中包含文件的修改者SID,再进行转换:
using System; using System.IO; using System.Runtime.InteropServices; using System.Security.Principal; public static class FileInfoHelper { [DllImport("kernel32.dll", SetLastError = true)] private static extern bool GetFileInformationByHandleEx(IntPtr hFile, int infoClass, IntPtr lpBuffer, uint dwBufferSize); private const int FileOwnerInfo = 4; [StructLayout(LayoutKind.Sequential)] private struct FILE_OWNER_INFO { public IntPtr OwnerSid; } public static string GetFileLastModifiedBy(string filePath) { using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { FILE_OWNER_INFO ownerInfo = new FILE_OWNER_INFO(); uint bufferSize = (uint)Marshal.SizeOf(ownerInfo); IntPtr buffer = Marshal.AllocHGlobal((int)bufferSize); try { if (GetFileInformationByHandleEx(fs.SafeFileHandle.DangerousGetHandle(), FileOwnerInfo, buffer, bufferSize)) { ownerInfo = Marshal.PtrToStructure<FILE_OWNER_INFO>(buffer); SecurityIdentifier sid = new SecurityIdentifier(ownerInfo.OwnerSid); try { return sid.Translate(typeof(NTAccount)).Value; } catch (IdentityNotMappedException) { return sid.Value; } } else { throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } } finally { Marshal.FreeHGlobal(buffer); } } } }
这个方法底层调用Windows API,兼容性更强,但实现相对复杂。
内容的提问来源于stack exchange,提问作者ejyoung
相关产品推荐
相关产品推荐

