using set-acl to add usernames from different domain

Hi All

I am a complete novice at this and this is my first attempt at a script. I have a script working (thanks to online resource) which I’ve modified, it creates a folder scructure (home directories based on a txt file that I feed it) and applies permissions to each folder.

So it works on my PC (not a server, so am using Quest ActiveRoles software which can query AD without the need for the AD module that PS needs?) and on our network share drives (within the same domain as the users who I’m applying permissions for).

The issue is I can’t apply their permissions to the folders on the share I need to write to (different domain within our org)… I know it’s to do with th fact that the users are not ‘users’ on the ‘other’ domain. For me to add them manually on a folder via properties, security in XP, I must change the location to the ‘service’ domain, or use their fully qualified username, ie domain\username or username@domain.csv.au… then it can find them… Can I script this?

the txt file cannot be edited to inlude the fully qualified username as I also use the same name to create the folder for the user. Is there a way I can pass the "domain" to the username that’s stored in $User within the script? Alternatively, I may ask the server guys if they can all my users to the domain they are not members of?

Thanks for your help.

the code:

#>
param
(
	[String]$Path,
	[String]$UserList,
	[String[]]$FullControlMember
)

$Users=@()
$Results=@()
#Import-Module ActiveDirectory
if (-not (Test-Path $Path))
{
	write-error	-Message "Cannot find path '$Path' because it does not exist."
	return
}
if (-not (Test-Path $UserList))
{
	write-error	-Message "Cannot find  '$UserList' because it does not exist."
	return
}
else
{
	$Users=Get-Content $UserList
}
#Check whether the input AD member is correct
if ($FullControlMember)
{
	$FullControlMember|ForEach-Object {
		if (-not(Get-QADObject -Name "Name $_")){
			$FullControlMember= $FullControlMember -notmatch $_; Write-Error -Message "Cannot find an object with name:'$_'"
		}
	}
}
$FullControlMember+="BUILTIN\Administrators", "RGOperators"

foreach($User in $Users)
{	
	$HomeFolderACL=Get-Acl $Path
	$HomeFolderACL.SetAccessRuleProtection($true,$false)
	$Result=New-Object PSObject
	$Result|Add-Member -MemberType NoteProperty -Name "Name" -Value $User
	if (Get-QADUser -Name "$User")
	{
		New-Item -ItemType directory -Path "$Path\$User"|Out-Null
		#set acl to folder
		$FCList=$FullControlMember+$User
		$FCList|ForEach-Object {
		$ACL=New-Object System.Security.AccessControl.FileSystemAccessRule($_,"FullControl","ContainerInherit,ObjectInherit","None","Allow")
								$HomeFolderACL.AddAccessRule($ACL)
								}
		
        Set-Acl -Path "$Path\$User" $HomeFolderACL
		$Result|Add-Member -MemberType NoteProperty -Name "IsCreated" -Value "Yes"
		$Result|Add-Member -MemberType NoteProperty -Name "Remark" -Value "N/A"
	}
	else
	{
		$Result|Add-Member -MemberType NoteProperty -Name "IsCreated" -Value "No"
		$Result|Add-Member -MemberType NoteProperty -Name "Remark" -Value "Cannot fine an object with name:'$User'"
	}
	$Results+=$Result

Hi jemsb

If all you’re looking to do is split or concacenate, then you can use something like the following in your code :

#split between user and domain
$domainusername = ("worlddomain\hellouser").Split('\')
$domain = $domainusername[0]
$username = $domainusername[1]

And to join again

#join again
$rejoineddomainusername = "$domain\$username"

This what you’re looking for?

Hi Tim,

Thanks for the reply. Well that’s not what I was looking for, perhaps I did not explained my problem well.

basically I have a list of names (usernames) in a txt file. I create folders using this txt file. I then need to assign these users permission to their folder, the code however uses the same username from the txt file and not the fully qaulified name, tries to assign that user to the folder, but the username cannot be found as they are not users of that domain.

But in any case, I think you may have given me an idea on how to solve this problem. I will give it a go and see how I get on.

Hi jembsb,

You’ve mentioned you can’t edit the input file. The only solution I can think of is to supply the domain or a list of domains via your script parameters and loop through them to find the user SID.

#>
param
(
	[String]$Path,
	[String]$UserList,
	[String[]]$FullControlMember

	[String[]]$Domains
)

Best,
Daniel

Hi Guys

Well this is the error I’m getting if it helps…

Set-Acl : Some or all identity references could not be translated.
At C:\CreateFolder.ps1:90 char:16

  • Set-Acl <<<< -Path "$Path$User" $HomeFolderACL
  • CategoryInfo : InvalidOperation: (Y:\mnic1111:String) [Set-Acl], IdentityNotMappedException
  • FullyQualifiedErrorId : System.Security.Principal.IdentityNotMappedException,Microsoft.PowerShell.Commands.SetAclCommand

I have set a variable $domain = "service" it's static and same the for all users.

scenario… users live on 'service', my script can add them no problem to any folder within this domain

Folder on Domain2, can't add user, get above error. Our server guys tell me there's only 1 way trust between the domains if that helps?

The process if on the PC using windows explorer, to add these users to the folder, I have go to folder properties, security, and MUST click on the locations button and select service domain, Hopefully this helps…

Thank you

ok I don’t know if I’m getting closer to the solution or further away, but I think I am now passing the fully qualified username ie, domain\username but I am now seeing this, which is different (in addition to) my original error…

[PS] C:&gt;.\CreateFolder.ps1 -Path "Y:" -UserList “c:\folder script\users.txt”
Exception calling “AddAccessRule” with “1” argument(s): “Some or all identity references could not be translated.”
At C:\CreateFolder.ps1:93 char:37
+ $HomeFolderACL.AddAccessRule <<<< ($ACL)
+ CategoryInfo : NotSpecified: (:slight_smile: , MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException

OK, I’ve worked out how to get the user’s SID and tried to apply that, but still no luck…

???

Before the access control entry ever gets saved to the security descriptor, it has to be translated to a SID. You can create the ACE with any string (even if it’s not a valid user) since the translation happens when the rule is added. Let’s see if we can figure out why your usernames aren’t being translated properly.

First, let’s make sure PowerShell can translate the usernames to SIDs. To do that, type the following at a PS prompt (obviously you’ll need to replace the domain and user names):

$DomainName = "DomainNameHere"
$UserName = "UserNameHere"
([System.Security.Principal.NTAccount] "$DomainName\$UserName").Translate([System.Security.Principal.SecurityIdentifier])

Does that return a SID object, or do you get an error?

If it worked, let’s try to create an ACE again. There are actually three different ways you can pass a principal to an ACE constructor. I’ve provided an example of each below (again, fill in the $DomainName and $UserName variables with valid values):

$DomainName = "DomainNameHere"
$UserName = "UserNameHere"

# A string. Behind the scenes, the string is just cast to an NTAccount:
New-Object System.Security.AccessControl.FileSystemAccessRule (
    "$DomainName\$UserName",
    "Read",   # [System.Security.AccessControl.FileSystemRights]
    "ContainerInherit, ObjectInherit", # [System.Security.AccessControl.InheritanceFlags]
    "None",   # [System.Security.AccessControl.PropagationFlags]
    "Allow"   # [System.Security.AccessControl.AccessControlType]
)

# An NTAccount object:
$NtAccount = [System.Security.Principal.NTAccount] "$DomainName\$UserName"
New-Object System.Security.AccessControl.FileSystemAccessRule (
    $NtAccount,
    "Read",   # [System.Security.AccessControl.FileSystemRights]
    "ContainerInherit, ObjectInherit", # [System.Security.AccessControl.InheritanceFlags]
    "None",   # [System.Security.AccessControl.PropagationFlags]
    "Allow"   # [System.Security.AccessControl.AccessControlType]
)

# A SecurityIdentifier object
$Sid = $NtAccount.Translate([System.Security.Principal.SecurityIdentifier])
New-Object System.Security.AccessControl.FileSystemAccessRule (
    $Sid,
    "Read",   # [System.Security.AccessControl.FileSystemRights]
    "ContainerInherit, ObjectInherit", # [System.Security.AccessControl.InheritanceFlags]
    "None",   # [System.Security.AccessControl.PropagationFlags]
    "Allow"   # [System.Security.AccessControl.AccessControlType]
)

Do those examples work for you, or do you get any errors? Can you post the latest version of the line where you create the FileSystemAccessRule?

Thanks for the reply Rohn.

Yes I am able to get the SID of the usernames.

Please note that my code works entirely as it should if I set the creation of the folders and their permissions to my local PC or on a share within the SAME DOMAIN.

The issue is when trying to add the ‘users’ to their folders on a different Domain with a 1 way trust. It must be this as it works completey fine to a shared drive within my PC’s domain or to local PC.

Here’s my working code (part of), just not when outputting to the required domain (different to mine, but within same organisation).

$FullControlMember+="BUILTIN\Administrators", "RGOperators"
foreach($User in $Users)
{	
	$HomeFolderACL=Get-Acl $Path
	$HomeFolderACL.SetAccessRuleProtection($true,$false)
	$Result=New-Object PSObject
	$Result|Add-Member -MemberType NoteProperty -Name "Name" -Value "$User"
	if (Get-QADUser -Name "$User")
	{
		New-Item -ItemType directory -Path "$Path\$User"|Out-Null
		#set acl to folder
                               $rejoinedusername = "$domain\$User"
                               $FCList=$FullControlMember+$rejoinedusername
                               $FCList|ForEach-Object {
	               $ACL=New-Object System.Security.AccessControl.FileSystemAccessRule($_,"FullControl","ContainerInherit, ObjectInherit","None","Allow")
	              $HomeFolderACL.AddAccessRule($ACL)       
        
        	}
		        
        Set-Acl -Path "$Path\$User" $HomeFolderACL
}

You said earlier that you’re able to get the SIDs. How are you doing that? If you use the SIDs while creating the ACEs, there shouldn’t be any translation problems. Could you modify your code to do something like this?:

$FCList | ForEach-Object {
    $SidString = # DO WHATEVER YOU'RE DOING TO GET THE SID HERE

    $ACE = New-Object System.Security.AccessControl.FileSystemAccessRule(
        [System.Security.Principal.SecurityIdentifier] $SidString,
        "FullControl",
        "ContainerInherit, ObjectInherit",
        "None",
        "Allow"
    )
    $HomeFolderACL.AddAccessRule($ACE)
}

Thanks Rohn.

It’s not a translation problem so to speak, because the SID’s are translating fine within my Domain. The issue is translating them to a Domain with a 1 way trust relationship.

Thankfully, I have solved this issue simply by applying the Authenticated Users group on my root level folder.

Thank you everybody for your help. I feel this has been a great accomplishment and learning experience considering this was my first go at a script.

Thanks
Chris