在给定SID的情况下,C#无法以编程方式获取用户域

时间:2017-06-21 08:54:40

标签: c# powershell active-directory

我正在尝试将具有安全规则的所有用户提取到某个文件夹,为此我正在使用C#应用程序,但是我无法为用户获取正确的域。

假设我在域CURRENT上,但有些访问该文件夹的用户也在域OLD上。在域之间有一个信任。但是,当我查找其SID时,由于某种原因从OLD迁移到CURRENT的某些用户似乎在CURRENT上。然而奇怪的是,Windows资源管理器正确地显示它们在域OLD上。

代码

public IdentityReference GetUser(string SID)
{
    return ( new NTAccount(SID) ).Translate(typeof(NTAccount));
}

如您所见,它获取用户的SID并返回NTAccount(DOMAIN \ user)。要获取SID,我使用以下代码:

DirectorySecurity ACL = Directory.GetAccessControl(folder);
AuthorizationRuleCollection rules = ACL.GetAccessRules(true, true, typeof(SecurityIdentifier));

foreach (FileSystemAccessRule rule in rules)
{
    IdentityReference user = GetUser(rule.IdentityReference.value);
    //do stuff ...
}

我还有一个PowerShell脚本可以执行相同的操作:

echo (New-Object System.Security.Principal.SecurityIdentifier($sid)).Translate([System.Security.Principal.NTAccount]).Value

问题

现在,我有用户OLD \ user1,但是,它也作为CURRENT \ user1出现在新域中。当我右键单击Windows资源管理器时,它正确地将用户显示为OLD \ user1,但是当我运行C#代码时,它总是给我CURRENT \ user1,这不是我想要的。

奇怪的是,当我尝试在PowerShell中执行相同的操作时,用户也被正确识别为OLD \ user1。更奇怪的是,如果我运行PowerShell脚本并且只运行C#代码,我会得到正确的结果,但是在10分钟后,C#代码再次出现错误。

我已经尝试了什么

鉴于这些信息,我发现它必定是一种缓存问题(因为它似乎也发生在其他人身上)并且由于某种原因,C#和PowerShell以不同的方式处理查找请求,(见下面的 EDIT1 )所以我尝试了以下内容:

  • 从C#内部运行PowerShell代码

    PowerShell ps = PowerShell.Create();
    ps.AddScript("New-Object System.Security.Principal.SecurityIdentifier(\""+SID+"\")).Translate([System.Security.Principal.NTAccount]");
    return (IdentityReference)(ps.Invoke()[0].BaseObject);
    
  • 运行与exe

    中可执行文件保存在同一文件夹中的相同脚本
    Process p = new Process();
    p.StartInfo.FileName = @"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe";
    p.StartInfo.Arguments = String.Format("-File \"{0}\" {1}", Directory.GetCurrentDirectory() + @"\get_user.ps1", SID);
    p.StartInfo.UseShellExecute = false;
    p.StartInfo.RedirectStandardOutput = true;
    p.Start();
    
    p.WaitForExit();
    return (new NTAccount(output)).Translate(typeof(NTAccount));
    
  • 使用P / Invoke使用WIN32API进行查找

    enum SID_NAME_USE
    {
        SidTypeUser = 1,
        SidTypeGroup,
        SidTypeDomain,
        SidTypeAlias,
        SidTypeWellKnownGroup,
        SidTypeDeletedAccount,
        SidTypeInvalid,
        SidTypeUnknown,
        SidTypeComputer
    }
    
    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern bool LookupAccountSid(
                          string lpSystemName,
                          [MarshalAs(UnmanagedType.LPArray)] byte[] Sid,
                          StringBuilder lpName,
                          ref uint cchName,
                          StringBuilder ReferencedDomainName,
                          ref uint cchReferencedDomainName,
                          out SID_NAME_USE peUse);
    
    byte[] sid = { /* the SID in bytes */ };
    StringBuilder name = new StringBuilder();
    uint cchName = (uint)name.Capacity;
    StringBuilder referencedDomainName = new StringBuilder();
    uint cchReferencedDomainName = (uint)referencedDomainName.Capacity;
    SID_NAME_USE sid_use;
    
    LookupAccountSid(null, sid, name, ref cchName, referencedDomainName, ref cchReferencedDomainName, out sid_use);
    
    if (Marshal.GetLastWin32Error() == 0)
        Console.WriteLine(String.Format("Account({0}): {2}\\{3}", sid_use, "...", referencedDomainName.ToString(), name.ToString()));
    

但这些都没有解决这个问题。还请注意,更改服务器缓存选项并不是真正的解决方案,因为我无法做到这一点。

EDIT1:

显然,PowerShell以不同的方式处理请求是不正确的,我忘了提到的是,在PS代码中,在从SID请求NTAccount之前,我做了相反的反应:我首先请求了SID NTAccount,像这样:

echo (New-Object System.Security.Principal.NTAccount("OLD\user1")).Translate([System.Security.Principal.SecurityIdentifier]).Value
echo (New-Object System.Security.Principal.SecurityIdentifier($sid)).Translate([System.Security.Principal.NTAccount]).Value

这一定必须触发缓存,所以它绝对是一个缓存问题。

EDIT2

我已经设法通过将可执行文件移动到OLD域下的计算机来解决问题(因为这是它应该从另一台机器远程执行其任务的地方),但我将离开问题没有解决,因为它不是真正最好的解决方案。

0 个答案:

没有答案