You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

修改文件所有者触发UnauthorizedAccessException的.NET解决方案

在.NET中修改文件所有者的可行方案

问题根源分析

你的代码抛出UnauthorizedAccessException主要有两个核心原因:

  • SID类型错误:你使用的WinBuiltinIUsersSid对应INTERACTIVE用户组,而非目标的BUILTIN\Users,正确的SID类型应为WinBuiltinUsersSid。
  • Windows权限规则限制:默认情况下,只有文件的当前所有者或拥有Take Ownership权限的用户(如管理员)才能修改文件所有者。普通用户对自己创建的文件拥有所有权,理论上可以转移,但需要遵循正确的权限操作流程。

修正后的.NET原生实现代码

先纠正SID类型,同时优化权限配置逻辑(额外添加删除权限确保后续修剪操作可行):

private static void ChangeBackupOwner(string filePath)
{
    try
    {
        var fi = new FileInfo(filePath);
        // 获取包含所有者与访问权限的控制对象
        var fs = fi.GetAccessControl(AccessControlSections.Owner | AccessControlSections.Access);
        
        // 初始化BUILTIN\Users组的正确SID
        var usersSid = new SecurityIdentifier(WellKnownSidType.WinBuiltinUsersSid, null);
        
        // 设置新所有者
        fs.SetOwner(usersSid);
        
        // 给BUILTIN\Users组添加删除权限,确保后续修剪操作不受限
        var usersRule = new FileSystemAccessRule(
            usersSid,
            FileSystemRights.Delete | FileSystemRights.DeleteSubdirectoriesAndFiles,
            InheritanceFlags.None,
            PropagationFlags.NoPropagateInherit,
            AccessControlType.Allow);
        fs.AddAccessRule(usersRule);
        
        // 应用所有权限修改
        fi.SetAccessControl(fs);
    }
    catch (UnauthorizedAccessException ex)
    {
        Logger.PostMessage($"无权限修改所有者:{ex.Message}");
    }
    catch (Exception ex)
    {
        Logger.PostMessage(ex.ToString());
    }
}

进阶方案:直接调用Windows API

如果.NET原生封装仍存在权限细节问题,可以通过P/Invoke调用底层Windows APISetNamedSecurityInfo,实现更精确的权限控制:

using System.Runtime.InteropServices;

private enum SE_OBJECT_TYPE
{
    SE_FILE_OBJECT = 1
}

private enum SECURITY_INFORMATION
{
    OWNER_SECURITY_INFORMATION = 0x00000001
}

[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern uint SetNamedSecurityInfo(
    string lpFileName,
    SE_OBJECT_TYPE ObjectType,
    SECURITY_INFORMATION SecurityInfo,
    IntPtr psidOwner,
    IntPtr psidGroup,
    IntPtr pDacl,
    IntPtr pSacl);

private static void ChangeBackupOwnerViaApi(string filePath)
{
    IntPtr sidPtr = IntPtr.Zero;
    try
    {
        var usersSid = new SecurityIdentifier(WellKnownSidType.WinBuiltinUsersSid, null);
        byte[] sidBytes = new byte[usersSid.BinaryLength];
        usersSid.GetBinaryForm(sidBytes, 0);
        
        sidPtr = Marshal.AllocHGlobal(sidBytes.Length);
        Marshal.Copy(sidBytes, 0, sidPtr, sidBytes.Length);
        
        uint result = SetNamedSecurityInfo(
            filePath,
            SE_OBJECT_TYPE.SE_FILE_OBJECT,
            SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION,
            sidPtr,
            IntPtr.Zero,
            IntPtr.Zero,
            IntPtr.Zero);
        
        if (result != 0)
        {
            throw new System.ComponentModel.Win32Exception((int)result);
        }
    }
    catch (Exception ex)
    {
        Logger.PostMessage(ex.ToString());
    }
    finally
    {
        if (sidPtr != IntPtr.Zero)
        {
            Marshal.FreeHGlobal(sidPtr);
        }
    }
}

关于提权的说明

  • 如果文件是普通用户自行创建:修正代码后无需提权,即可将所有者转移给BUILTIN\Users。
  • 如果文件是管理员创建:普通用户无权限修改其所有者,必须以管理员身份运行程序(触发UAC)才能操作。这种情况下,你可以按计划跳过此类文件,等待管理员下次运行工具时再处理。

内容的提问来源于stack exchange,提问作者Roger Wolf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 17:40:31