Set-acl on resource cross trusted forest

This topic contains 11 replies, has 2 voices, and was last updated by  Jason McMahan 3 years, 9 months ago.

  • Author
    Posts
  • #10360

    Jason McMahan
    Participant

    I have a script to create folders in a trusted domain, the script will create the folders properly and get-acl information for the folders however i am unable to change the ace/alc

    When i get-acl it returns the sids instead of the friendly names for the groups.

    I am running the script from Forest A attempting to get/set-acl on resources in Forest B

    What is have so far is

    ###########################################

    #region Apply Access Controls to $ftpFolder
    $aclFtpRoot = {Get-Acl -Path $($ftpFolder)}

    if
    ($aclFtpRoot.AreAccessRulesProtected) { $aclFtpRoot.Access | % {$aclFtpRoot.purgeaccessrules($_.IdentityReference)} }
    else
    {

    $isProtected = $true
    $preserveInheritance = $false
    $aclFtpRoot.SetAccessRuleProtection($isProtected, $preserveInheritance)}

    $rule1 = New-Object System.Security.AccessControl.FileSystemAccessRule("BUILTIN\Administrators","FullControl","ContainerInherit,ObjectInherit","None","Allow")
    $aclFtpRoot.AddAccessRule($rule1)
    Set-Acl -aclobject $aclFtpRoot -Path $ftpFolder

    $rule2 = New-Object System.Security.AccessControl.FileSystemAccessRule($filerDRwGroup,"FullControl","ContainerInherit,ObjectInherit","None","Allow")
    $aclFtpRoot.AddAccessRule($rule2)
    Set-Acl -aclobject $aclFtpRoot -Path $ftpFolder

    $rule3 = New-Object System.Security.AccessControl.FileSystemAccessRule($divisionListGroup,"ListDirectory","None","None","Allow")
    $aclFtpRoot.AddAccessRule($rule3)
    Set-Acl -aclobject $aclFtpRoot -Path

    $ftpFolder

    #endregion

    ###########################################

    If i perform

    $ftpfolder = '\\Filer\test.com'
    $aclFtpRoot = Get-Acl -Path $ftpFolder
    $aclFtpRoot | Select-Object -ExpandProperty access

    It returns

    FileSystemRights : FullControl
    AccessControlType: Allow
    IdentityReference:BUILTIN\Administrators
    IsInherited:False
    InheritanceFlags: ContainerInherit,ObjectInherit
    PropagationFlags:None

    FileSystemRights: ReadAndExecute, Synchronize
    AccessControlType:Allow
    IdentityReference:S-1-5-11-1111111111-1111111111-1111111111-1111
    IsInherited:False
    InheritanceFlags:ContainerInherit
    PropagationFlags: None

    If i would like to add the rule i get error

    $aclFtpRoot.AddAccessRule($rule3)

    Exception calling "AddAccessRule" with "1" argument(s): "Some or all identity references could not be translated."

    At line:1 char:1

    + $aclFtpRoot.AddAccessRule($rule3)

    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException

    + FullyQualifiedErrorId : IdentityNotMappedException

    Thank you

  • #10361

    Dave Wyatt
    Moderator

    What are the contents of your $divisionListGroup variable? Make sure that it's a DOMAIN\GroupName format string (or [System.Security.Principal.NTAccount] object), and that the group actually exists; no typos in the name, etc.

    If, for some reason, the .NET IdentityReference classes aren't translating names to SIDs across these forest trusts properly, it's always possible to code around them (either using the underlying Win32 API functions to translate names to SIDs, or fetching the SIDs with ADSI, etc.) However you accomplish it, all you should need to do is pass a [System.Security.Principal.SecurityIdentifier] object to the FileSystemAccessRule constructor in place of your current String or [System.Security.Principal.NTAccount] object.

  • #10367

    Jason McMahan
    Participant

    The variable is IsPublic IsSerial Name BaseType
    ——– ——– —- ——–
    True False ADGroup Microsoft.ActiveDirectory.Management.ADPrincipal
    It is the same group that appears with only the SID. I added the group to the resource (manually) and gave it read access to test this portion of the script.
    It is aggravating because i am able to open explorer with my administrator creds then perform this one small portion of the script is stopping the entire thing.

  • #10368

    Dave Wyatt
    Moderator

    Oh. There's no constructor for FileSystemAccessRule that would accept an ADPrincipal object; it either needs a subclass of IdentityReference (NTAccount or SecurityIdentifier), or a string (see http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.filesystemaccessrule.filesystemaccessrule.aspx). PowerShell is probably casting your ADPrincipal object to a string, to make it fit one of these constructors, but that string value might not quite match what the FileSystemAccessRule expects.

    Try running ([string]$divisionListGroup) and ($divisionListGroup.ToString()), and see what the output is.

  • #10370

    Jason McMahan
    Participant

    Instead of that i removed the variable and input domain\groupname to try to simplify it.
    I attempted
    New-Object System.Security.AccessControl.FileSystemAccessRule("Domain\Groupname","ListDirectory","None","None","Allow")
    $aclFtpRoot.AddAccessRule($rule3)
    Exception calling "AddAccessRule" with "1" argument(s): "The trust relationship between the primary domain and the trusted domain failed.
    "
    At line:1 char:1
    + $aclFtpRoot.AddAccessRule($rule3)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : SystemException
    When i show getType
    IsPublic IsSerial Name BaseType
    ——– ——– —- ——–
    True True String System.Object

  • #10373

    Dave Wyatt
    Moderator

    Presumably that means you either really have a problem with your trust relationship (which I doubt, or you'd have known about it already), or we're back to my original statement, that you might need to work around a .NET Framework limitation here, if it's not behaving well.

    I'd test this myself, but I don't have a multi-forest test environment set up at the moment. If I have time later, I'll build a new domain controller VM and see if I get the same results.

  • #10382

    Jason McMahan
    Participant

    THank you, just Fyi
    for giggles i ran the following command from my elevated powershell console in forest A
    PS C:\Sysutil\bin> $rule3 = New-Object System.Security.AccessControl.FileSystemAccessRule("domain\groupname","ListDirectory","None","None","Allow")

    PS C:\Sysutil\bin> $aclFtpRoot.AddAccessRule($rule3)
    Exception calling "AddAccessRule" with "1" argument(s): "The trust relationship between the primary domain and the trusted domain failed.
    "
    At line:1 char:1
    + $aclFtpRoot.AddAccessRule($rule3)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : SystemException

    Then i ran the exact same command from a server in forset B
    PS C:\sysUtil\bin> $rule3 = New-Object System.Security.AccessControl.FileSystemAccessRule("domain\groupname","ListDirectory","None","None","Allow")

    __________________________________________________________________________________________________
    PS C:\sysUtil\bin> $aclFtpRoot.AddAccessRule($rule3)

    __________________________________________________________________________________________________
    PS C:\sysUtil\bin> Set-Acl -aclobject $aclFtpRoot -Path $ftpFolder1
    It added the rule and set perms as it should have.
    The only thing that sticks out for me is in forest A the get-acl returns SID of list group
    When run get-acl in forest B it returns friendly name domain\groupname

    Thank you very much for any help.

  • #10385

    Dave Wyatt
    Moderator

    I'm not sure how soon I'll have a second AD forest set up for my own testing, but in the meantime, try this as an experiment:

    $account = [System.Security.Principal.NTAccount]'DOMAIN\GroupName'
    $account.Translate([System.Security.Principal.SecurityIdentifier])
    

    I expect this to fail; it's basically doing exactly the same thing that AddAccessRule is doing behind the scenes.

    Then try this, and see if it succeeds (or if it fails with a similar error message):

    # Based on sample code at http://www.pinvoke.net/default.aspx/advapi32.LookupAccountName
    
    function Get-Sid
    {
        [CmdletBinding()]
        param (
            [Parameter(Mandatory = $true, Position = 0)]
            [System.String]
            $Account,
    
            [Parameter(Mandatory = $false, Position = 1)]
            [System.String]
            $Domain = $null
        )
    
        Add-Type -TypeDefinition @'
            using System;
            using System.Runtime.InteropServices;
            using System.Text;
    
            public enum SID_NAME_USE 
            {
                SidTypeUser = 1,
                SidTypeGroup,
                SidTypeDomain,
                SidTypeAlias,
                SidTypeWellKnownGroup,
                SidTypeDeletedAccount,
                SidTypeInvalid,
                SidTypeUnknown,
                SidTypeComputer
            }
        
            public class NativeMethods
            {
                [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError = true)]
                public static extern bool LookupAccountName (
                    string lpSystemName,
                    string lpAccountName,
                    [MarshalAs(UnmanagedType.LPArray)] byte[] Sid,
                    ref uint cbSid,
                    StringBuilder ReferencedDomainName,
                    ref uint cchReferencedDomainName,
                    out SID_NAME_USE peUse);
            }
    '@
    
        $NO_ERROR = 0
        $ERROR_INSUFFICIENT_BUFFER = 122
        $ERROR_INVALID_FLAGS = 1004
    
        $sidBytes = $null
        $sidByteCount = 0
        $referencedDomainName = New-Object System.Text.StringBuilder
        $referencedDomainNameCharCount = [System.UInt32]$referencedDomainName.Capacity
        [SID_NAME_USE]$sidNameUse = [SID_NAME_USE]::SidTypeUnknown
    
        $errorCode = $NO_ERROR
    
        if (-not [NativeMethods]::LookupAccountName($Domain, $Account, $sidBytes, [ref]$sidByteCount, $referencedDomainName, [ref] $referencedDomainNameCharCount, [ref] $sidNameUse))
        {
            $errorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
            if ($errorCode -eq $ERROR_INSUFFICIENT_BUFFER -or $errorCode -eq $ERROR_INVALID_FLAGS)
            {
                $sidBytes = New-Object Byte[]($sidByteCount)
                $null = $referencedDomainName.EnsureCapacity([int]$referencedDomainNameCharCount)
                $errorCode = $NO_ERROR
    
                if (-not [NativeMethods]::LookupAccountName($Domain, $Account, $sidBytes, [ref]$sidByteCount, $referencedDomainName, [ref] $referencedDomainNameCharCount, [ref] $sidNameUse))
                {
                    $errorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
                }
            }
        }
        else
        {
            $displayAccount = ""
            
            if (-not [string]::IsNullOrEmpty($Domain))
            {
                $displayAccount += "$Domain\"
            }
    
            $displayAccount += $Account
    
            throw "Account '$displayAccount' could not be translated to a SID."
        }
    
        if ($errorCode -eq $NO_ERROR)
        {
            $sid = New-Object System.Security.Principal.SecurityIdentifier($sidBytes,0)
            Write-Output $sid
        }
        else
        {
            throw (New-Object System.ComponentModel.Win32Exception($errorCode))
        }
    }
    
    Get-Sid -Domain 'DOMAIN' -Account 'GroupName'
    

    This code uses the Win32 API; if anything's going to work, it should work. If this does work, you can use it to get around the .NET problem. The SecurityIdentifier object returned by Get-Sid (unless it throws an exception) can be passed to the constructor of FileSystemAccessRule objects.

  • #10390

    Jason McMahan
    Participant

    You were right,
    PS C:\Sysutil\bin> $account = [System.Security.Principal.NTAccount]'Domain\Groupname'

    PS C:\Sysutil\bin> $account.Translate([System.Security.Principal.SecurityIdentifier])
    Exception calling "Translate" with "1" argument(s): "The trust relationship between the primary domain and the trusted domain failed.
    "
    At line:1 char:1
    + $account.Translate([System.Security.Principal.SecurityIdentifier])
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : SystemException

    I then added the function and ran Get-sid which returned:
    BinaryLength AccountDomainSid Value
    ———— —————- —–
    28 S-1-1-11-1111111111-1111111111-1111111111 S-1-1-11-1111111111-1111111111-1111111111-1111

  • #10560

    Jason McMahan
    Participant

    Good morning Just wanted to follow up with this thread to see if there is any more info that may help.
    Thank you very much for you time.

  • #10571

    Dave Wyatt
    Moderator

    Sorry, I thought you said that the Get-Sid function I posted was working. I did build a second AD forest in my lab, but wasn't able to reproduce the problem.

    The intended use of the Get-Sid function is like this:

    # Instead of this:
    
    $rule3 = New-Object System.Security.AccessControl.FileSystemAccessRule("Domain\Groupname","ListDirectory","None","None","Allow")
    $aclFtpRoot.AddAccessRule($rule3)
    
    # Try this:
    
    try
    {
        $sid = Get-Sid -Domain "Domain" -Account "Groupname"
        $rule3 = New-Object System.Security.AccessControl.FileSystemAccessRule($sid, "ListDirectory", "None", "None", "Allow")
        $aclFtpRoot.AddAccessRule($rule3)
    }
    catch
    {
        # If an error occurred, handle it however you like.
        
        Write-Error -ErrorRecord $_
    }
    
  • #11181

    Jason McMahan
    Participant

    I am sorry i did not respond sooner, Thank you for your help.
    This was the correct method and i can set the rules as expected.
    I really appreciate all the time and effort you gave on this issue.

You must be logged in to reply to this topic.