Powershell - New User home folder permissions - powershell

I am working on a PS script to automate new network accounts, their home folder and exchange mailbox. We have multiple Domain controllers so am looking for a way of creating a network account on one domain controller but creating the home directory on a different site with its own domain controller. I have tried this but when setting permissions an issue has occurred because the account has not replicated over to the other DC. Anyone have any ideas to get around this?
New Account Function
Function New-BVStandardUser
{
Param (
$FirstName,
$LastName,
$CallRef,
$SiteName,
$EmployeeID,
$ExpiryDate,
$InternetAccess,
$ExternalEmailAccess
)
$ImportGroups = Import-Csv -Path "\\UKSP-FS01\Lawsonja$\Scripts\New-ADUser\SiteGroups.csv" -Delimiter ","
$ImportServers = Import-Csv -Path "\\UKSP-FS01\Lawsonja$\Scripts\New-ADUser\SiteServers.csv" -Delimiter ","
$ImportOUs = Import-Csv -Path "\\UKSP-FS01\Lawsonja$\Scripts\New-ADUser\SiteOUs.csv" -Delimiter ","
# Convert the first and last name so it does not have special characters for the email address/ UPN
$LastNameEdit = $LastName -replace '[^a-zA-Z]', ''
$FirstNameEdit = $FirstName -replace '[^a-zA-Z]', ''
# Fetch a free username from AD based on the provided first and last name from the user
$Username = Get-ADUsername -FirstName $FirstNameEdit -LastName $LastNameEdit
# Generate a random password using the imported module
$Password = Get-Randompassword
# Create the AD account based on the inputted fields
$Params = #{
DisplayName = "$($LastName), $($FirstName)"
DirectoryName = "$($LastName), $($FirstName)"
SamAccountName = "$Username"
UserPrincipalName = "$FirstNameEdit.$LastNameEdit#Bakkavor.com"
Comment = "Created $($env:USERNAME) - $(Get-Date -Format dd/MM/yy) - $($CallRef)"
GivenName = "$FirstNameEdit"
Surname = "$LastNameEdit"
Description = "$($SiteName) User"
Enabled = $true
ChangePasswordAtLogon = $true
Path = "$ImportOUs.$($SiteName)"
HomeDirectory = "\\$ImportServers.$($SiteName)\$Username$"
HomeDrive = "U"
AccountPassword = (ConvertTo-SecureString $Password -AsPlainText -Force)
}
try
{
New-ADUser #Params -ErrorAction Stop
Write-Verbose -Verbose "Network Account Created"
}
catch
{
Write-Warning "Error creating network account. Error: $($_.Exception.Message)"
break
}
New Home Drive Function
Function New-BVUDrive
{
Param
(
$Username,
$Server
)
# Connect to the relevant server in CSV, create new folder, create new SMB Share for the user and add share/ NTFS permissions
Invoke-Command -ComputerName $Server -ArgumentList $Username -ErrorAction Stop -ScriptBlock
{
param($Username)
$FindShare = (Get-SmbShare -Name Users$).Path
if($FindShare -eq $true)
{
try
{
New-Item -ItemType Directory -Path "$FindShare\$Username" -ErrorAction Stop
New-SmbShare -Name "$Username$" -Path "$FindShare\$Username" -FullAccess "AD\Server Admins", "AD\Domain Admins" -ChangeAccess "AD\$Username" -ErrorAction Stop
$Acl = Get-Acl "$FindShare\$Username"
foreach($Rule in $Acl.Access)
{
$Acl.RemoveAccessRule($Rule)
}
$Ar = New-Object system.security.accesscontrol.filesystemaccessrule("Everyone","FullControl","Allow")
$Acl.SetAccessRule($Ar)
$Acl.SetAccessRuleProtection($false, $true)
Set-Acl "$FindShare\$Username" $Acl -ErrorAction Stop
}
catch
{
Write-Warning "U drive failed to create. Error: $($_.Exception.Message)"
}
}
else
{
Write-Warning "Users$ share not found on server"
}
}
}

Have you tried using the SID?
In the second function New-BVUDrive, replace the username with SID. and use the following cmdlet to get the SID:
(Get-ADUser -Identity $SamAccountName).SID.Value
you will be able to set the ACL now, until the data will replicate you will see in the security tab the SID, but the user will be able to access the folder if he will try.
$Ar = New-Object System.Security.AccessControl.FileSystemAccessRule ($SIDIdentity, 'FullControl', ('ContainerInherit','ObjectInherit'), 'None','Allow')
Hope it will help.

Related

AD-user script has no output

I'm creating a script for adding multiple users in Active Directory. I stumbled upon this link, when I couldn't get the guide described in the question to work either. I then tried one of the solutions in the comments
Import-Module ActiveDirectory
# this defaults to csv fields delimited by a comma. If your CSV file uses a different
# character, then add parameter '-Delimiter' followed by the actual character
$ADUsers = Import-Csv -Path 'C:\Users\Desktop\Powershell files\EM-mis-new-AD.csv'
# the Where-Object clause is just a precaution to omit records that have no username value
$ADUsers | Where-Object { $_.username -match '\S'} | ForEach-Object {
$Username = $_.username
if (Get-ADUser -Filter "SamAccountName -eq '$Username'" -ErrorAction SilentlyContinue) {
Write-Warning "A user account with SamAccountName '$Username' already exist in Active Directory."
}
else {
$Firstname = $_.firstname
$Lastname = $_.lastname
# use splatting on cmdlets that use a lot of parameters
$userParams = #{
SamAccountName = $Username
UserPrincipalName = "$Username#Mydomain.com"
Name = "$Firstname $Lastname"
GivenName = $Firstname
Surname = $Lastname
Enabled = $true
DisplayName = "$Firstname, $Lastname"
Path = $_.ou
AccountPassword = (ConvertTo-SecureString $_.Password -AsPlainText -Force)
ChangePasswordAtLogon = $true
}
# create the user and report back
New-ADUser #userParams
Write-Host "Created new user '$Username' with initial password: $($_.Password)"
}
}
Here is my CSV file
firstname;lastname;username;password;ou
Mette;Frederiksen;MeFr;Password1;OU=Salg,OU=Users,OU=RGD Aarhus,DC=rgd,DC=local
Sussi;Hart;SuHa;Password1;OU=Salg,OU=Users,OU=RGD Aarhus,DC=rgd,DC=local
Ove;Tylstrup;OvTy;Password1;OU=Salg,OU=Users,OU=RGD Aarhus,DC=rgd,DC=local
Karlos;Mondolez;KaMo;Password1;OU=Lager,OU=Users,OU=RGD Aarhus,DC=rgd,DC=local
Anne;Otto;AnOt;Password1;OU=Lager,OU=Users,OU=RGD Aarhus,DC=rgd,DC=local
Dennis;Ågard;DeÅg;Password1;OU=Lager,OU=Users,OU=RGD Aarhus,DC=rgd,DC=local
Helena;Riss;HeRi;Password1;OU=Okonomi,OU=Users,OU=RGD Aarhus,DC=rgd,DC=local
Risa;Lamende;RiLa;Password1;OU=Okonomi,OU=Users,OU=RGD Aarhus,DC=rgd,DC=local
However, when I run the above code nothing happens
PS C:\Users\RGDAdmin> C:\Users\RGDAdmin\Documents\ADUser.ps1
PS C:\Users\RGDAdmin>
When I add the Delimiter parameter, I get this
Created new user 'KaMo' with initial password: Password1
New-ADUser : The directory service was unable to allocate a relative identifier
At C:\Users\RGDAdmin\Documents\ADUser.ps1:31 char:9
+ New-ADUser #userParams
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (CN=Anne Otto,OU...DC=rgd,DC=local:String) [New-ADUser], ADException
+ FullyQualifiedErrorId :
ActiveDirectoryServer:8208,Microsoft.ActiveDirectory.Management.Commands.NewADUser
PS. I know the password is bad practice in terms of passwords
Your file is delimited by semicolons, so you will definitely need to specify the -Delimiter parameter. But the documentation has a caveat:
To specify a semicolon (;) enclose it in single quotation marks.
So it should look like this:
$ADUsers = Import-Csv -Delimiter ';' -Path 'C:\Users\Desktop\Powershell files\EM-mis-new-AD.csv'
If that still results in that RID error, then there's possibly something wrong on the server. Can you create users manually using AD Users and Computers?
Try reviewing this. I don't have access to ActiveDirectory to test it myself.
#helpers
function usernameIsNotBlank {
[CmdletBinding()]
param(
$Username
)
[regex]$rx = "\S"
return $rx.match($Username)
}
function usernameDoesNotAlreadyExist {
[CmdletBinding()]
param(
$Username
)
$UserDoesNotExist = $true
$UserObject = $(
try {
Get-ADUser $Username
}
catch {
$null
}
)
if ($null -ne $UserObject) {
$UserDoesNotExist = $false
Write-Verbose "$Username already exists"
}
else {
$UserDoesNotExist = $true
}
return $UserDoesNotExist
}
function suppliedUsernameIsAvailable {
[CmdletBinding()]
param(
$Username
)
return ((usernameIsNotBlank -Username $Username) -and (usernameDoesNotAlreadyExist -Username $Username))
}
#script
$OriginalVerbose = $VerbosePreference
$VerbosePreference = "Continue"
Import-Module ActiveDirectory
$CSV = "C:\Users\Desktop\Powershell file\EM-mis-new-AD.csv"
$Data = Import-CSV $CSV
foreach ($Line in $Data) {
if (suppliedUsernameIsAvailable($Line.username)) {
New-ADUser -Name "$Line.firstname $Line.lastname" -GivenName "$Line.firstname" -Surname "$Line.lastname" -SamAccoutnname "$(Line.username)#mydomain.com" -AccountPassword (ConvertTo-SecureString $Line.password -AsPlainText -Force) -ChangePasswordAtLogon $true -Path "$Line.ou"
}
}
$VerbosePreference = $OriginalVerbose

How can I run powershell script that uses both local & elevated permissions?

I need to edit two registry keys. One needs to be run by the local user, the other by an account with elevated privileges.
How can I write a script that is run as a different user, but still has access to the local user's credentials?
As administrator, you can set the registry value for the currently logged on user too, if you can get the SID for that user.
When you have that, you can access the local users registry via the HKEY_USERS hive.
Import-Module ActiveDirectory
# set this to the registry path, property name and value you need to access
$regPath = 'Software\SomePath\SomeKey'
$propName = 'ThePropertyName'
$propValue = 'ThePropertyValue'
$propType = 'String' # use any of the `[Microsoft.Win32.RegistryValueKind]` enum values or names
# get the domain\username of the user currently logged in to the computer
$user = (Get-CimInstance -ClassName Win32_ComputerSystem).UserName
# get the SID for that user
$sid = (Get-ADUser -Identity ($user -split '\\', 2)[0]).SID
if (!$sid) {
throw "Could not determine the SID for user '$user'"
}
# Admin registry: HKEY_LOCAL_MACHINE
$path = Join-Path -Path 'HKLM:' -ChildPath $regPath
Set-Itemproperty -Path $path -Name $propName -Value $propValue -Type $propType
# Current user registry: HKEY_USERS
$path = Join-Path -Path "Registry::HKEY_USERS\$sid" -ChildPath $regPath
Set-Itemproperty -Path $path -Name $propName -Value $propValue -Type $propType
As mklement0 commented,
the above code uses the ActiveDirectory module to get the SID for the currently logged on user via Get-ADUser.
If this is not possible for you, or you are not in an AD domain, the following helper function can also get the SID, without the need for ActiveDirectory:
function Get-UserSID {
param (
[Parameter(ValuefromPipeline = $true, Position = 0)]
[Alias('Account', 'User')]
[string]$UserName = $env:USERNAME,
[string]$Domain = $env:USERDOMAIN
)
if ($UserName.Contains("\")) { $Domain, $UserName = $UserName -split '\\', 2 } #"# split on the backslash
try {
$objUser = New-Object System.Security.Principal.NTAccount($Domain, $UserName)
$strSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier])
$strSID.Value
}
catch [System.Security.Principal.IdentityNotMappedException] {
Write-Warning "User '$UserName' does not exist in '$Domain'"
}
catch {
throw
}
}
Put that on top of your script and then use as:
# get the domain\username of the user currently logged in to the computer
$user = (Get-CimInstance -ClassName Win32_ComputerSystem).UserName
# get the SID for that user
$sid = Get-UserSID $user
A possible third way of getting the SID is by reading the registry:
# get the domain\username of the user currently logged in to the computer
$user = (Get-CimInstance -ClassName Win32_ComputerSystem).UserName
# get the SID for that user by probing the registry
$sid = ((Get-ItemProperty -Path 'Registry::HKEY_USERS\S-*\Volatile Environment' |
Where-Object { ('{0}\{1}' -f $_.USERDOMAIN, $_.USERNAME) -eq $user }).PSParentPath -split '\\')[-1]
You can use key "-credential" to set user that would be change registry like :
New-Item –Path "HKCU:\dummy" –Name newregistrykey -Credential myuser#domain
or to set property:
Set-Itemproperty -path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run' -Name 'someProcess' -value 'C:\Program Files\someapp\myprogramm.exe' -Credential myuser#domain
And you can save you both cred to variables like:
$localCred = Get-Credential
$domainCred = Get-Credential

Error mapping home directory with a PowerShell script

I'm using a script to create new users and everything is working fine. However, when I try to log in with a user created with this script, I get the following error:
A Problem has occurred and your network home directory is not available.
This may be because a network file server is offline.
You have been logged on with a temporary home drive (H:) which may be shared
with other users.
The script creates the user and applies the correct permissions as far as I can tell.
Here's the script:
# Import active directory module for running AD cmdlets
Import-Module activedirectory
#Store the data from ADUsers.csv in the $ADUsers variable
$ADUsers = Import-csv .\Create_Staff_Accounts.csv
#Loop through each row containing user details in the CSV file
foreach ($User in $ADUsers)
{
#Read user data from each field in each row and assign the data to a variable as below
$Username = $User.username
$Password = $User.password
$Firstname = $User.firstname
$Lastname = $User.lastname
$OU = $User.ou #This field refers to the OU the user account is to be created in
$group = $User.group
$title = $User.title
$start = $User.start
$Homedrive = "H:"
$UserRoot = "\\servername\st$\"
$HomeDirectory = $UserRoot + $Username
#Check to see if the user already exists in AD
if (Get-ADUser -F {SamAccountName -eq $Username})
{
#If user does exist, give a warning
Write-Warning "A user account with username $Username already exists in Active Directory."
}
else
{
#User does not exist then proceed to create the new user account
#Account will be created in the OU provided by the $OU variable read from the CSV file
New-ADUser `
-SamAccountName $Username `
-Name "$Firstname $Lastname" `
-UserPrincipalName "$($username)#domain.local" `
-GivenName $Firstname `
-Surname $Lastname `
-Enabled $True `
-DisplayName "$Firstname $Lastname" `
-Path $OU `
-AccountPassword (convertto-securestring $Password -AsPlainText -Force) `
-Homedrive $Homedrive `
-HomeDirectory $HomeDirectory `
-ScriptPath "logonscript.bat" `
-Description "Staff Account: $($title) from: $($start)"
#-ChangePasswordAtLogon $True `
#Now create the home folder and set modify permissions
Add-ADGroupMember -Identity $group -Members $Username
Add-ADGroupMember -Identity groupname -Members $Username
Add-ADGroupMember -Identity groupname -Members $Username
New-Item -ItemType Directory -Path "\\servername\st$\$($User.username)"
$path = Get-Item -Path "\\servername\st$\$($User.username)"
$acl = (Get-Item $path).GetAccessControl('Access')
$AR = New-Object System.Security.AccessControl.FileSystemAccessRule($Username, 'Modify', 'ContainerInherit,ObjectInherit', 'None', 'Allow')
$acl.SetAccessRule($AR)
Set-Acl -Path $Path -AclObject $acl
}
}
Thank you for your help and support.

Updating AD User Object Manager Attribute With Contact DN

I have two forests after a merger. Managers of some people reside in the opposite forest. To get around this we have contacts in each forest for all the users of the opposite forest. I am trying to update the manager attribute for several users based on a csv import where I am matching on the managers email address. My script can match the DN of the managers contact, but for some reason will not add it to the ad userobject manager attribute stating it cannot find the DN of an object that is clearly present.
If I run a simple get-adobject with an ldap filter it returns the DN of a managers contact:
PS C:\temp> Get-ADObject -ldapfilter "(&(objectclass=contact)(name=$fname*)(name=*$lname))" -SearchBase "OU=station,OU=CONTACTS,DC=workplace,DC=COM" |select distinguishedname
distinguishedname
-----------------
CN=Nick Hill,OU=station,OU=Contacts,DC=workplace,DC=com
However, the script below will error when trying to add this DN to a users manager attribute. What's confusing is the DN it claims it cannot find is clearly present per the command above.
The script below errors with:
set-aduser : Identity info provided in the extended attribute: 'Manager' could not be resolved. Reason: 'Cannot find an object with identity: 'CN=Nick Hill,OU=station,OU=Contacts,DC=workplace,DC=com' under: 'DC=workplace,DC=com'.'.
$users = import-csv test1.csv
FOREACH ($user in $users)
{
$username = $user.UserName
$employeeid = $user.employeeid
$city = $user.city
$country = $user.country
$department = $user.department
$division = $user.division
$office = $user.location
$state = $user.state
$postalcode = $user.postal_code
$manageremail = $user.manageremail
$manager = get-aduser -f "mail -eq '$($manageremail)'"
FUNCTION LocalManager
{
get-aduser -f {mail -eq $username} |set-aduser -Manager $manager
}
FUNCTION RemoteManager
{
$data = $manageremail.split("#")
$name = $data[0]
$namesplit = $name.split(".")
$fname = $namesplit[0]
$lname = $namesplit[1]
$rmanager = Get-ADObject -SearchBase 'OU=station,OU=Contacts,DC=workplace,DC=com' -ldapfilter "(&(objectclass=contact)(name=$fname*)(name=*$lname))"
get-aduser -f {mail -eq $username} |set-aduser -Manager "$rmanager"
}
IF ($manager -eq $null)
{
RemoteManager
}
Else
{
Localmanager
}
}
I have had a similar error on my own script to handle cross-domain user population. I've exported some of our old decom'd user accounts and am importing them (with suitably generic information) to populate our test/dev environments.
Unfortunately when I try and create these accounts as new users in AD with managers in different domains, I find the following problem:
Set-ADUser : The server is unwilling to process the request
At line:1 char:1
+ Set-ADUser -Identity $user.SamAccountName -Manager $user.Manager -Ser ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (user.name:ADUser) [Set-ADUser], > ADInvalidOperationException
+ FullyQualifiedErrorId : > ActiveDirectoryServer:8245,Microsoft.ActiveDirectory.Management.Commands.SetADUser
So this was in an attempt to set the user with the manager's DN.
function create-testaccts {
[CmdletBinding()]
param(
[Parameter(Mandatory=$True,Position=1)]
[string] $rootPath ,
[Parameter(Mandatory=$True,Position=2)]
[string] $userList ,
[Parameter(Mandatory=$True,Position=3)]
[string] $pw ,
[Parameter(Mandatory=$True,Position=4)]
[string] $OU = $(throw "Please specify a query.")
)
$newUsers = import-csv $userList
$password = $pw | ConvertTo-SecureString -AsPlainText -Force
foreach ($user in $newUsers){
$profPath = $rootpath + $user.samaccountname
try {
write-host -fore Cyan "Creating the user profile path - $profPath"
new-item $profPath -ItemType Directory -Force -ErrorAction stop | Out-Null
}# END OF TRY
Catch [System.Management.Automation.ActionPreferenceStopException] {
write-host -fore Yellow "caught a StopExecution Exception - Home directory creation "
$error[0]
}# END OF CATCH
try {
Write-Host -Fore Cyan "Creating the user object in AD -" $user.Name
# Name - Name
# Givenname - Firstname
# Surname - Lastname
# Password - AccountPassword Specific to new-aduser
# SamAccountName - same in both command/attribute name used userlogon and samaccount
# Manager - same in both command/attribute name
# ProfilePath - same in both command/attribute name
# HomeDirectory - same in both command/attribute name
# HomeDrive - same in both command/attribute name
# Enabled - False - same in both command/attribute name
# UserPrincipalName - same in both command/attribute name
# Server
$name = $user.Name
New-ADUser -Name "$name" `
-GivenName $user.givenname `
-Surname $user.surname `
-DisplayName $user.displayname `
-SamAccountName $user.SamAccountName `
-Path $ou `
-AccountPassword $Password `
-ProfilePath $user.profilepath `
-HomeDirectory $user.HomeDirectory `
-HomeDrive $user.homedrive `
-Enabled $False `
-UserPrincipalName $user.UserPrincipalName `
-Server domain.local `
-Credential $creds `
-ErrorAction Stop
#-Manager $user.Manager `
}# END OF TRY
Catch [System.Management.Automation.ActionPreferenceStopException] {
Write-Host -fore Yellow "caught a StopExecution Exception - Account Creation"
$error[0]
}# END OF CATCH
}#END FOREACH NEW USERS
} #END OF FUNCTION (CREATE-TESTACCTS)
When I try and use this with a trusted domain it fails due to the manager DN not being found in the local domain. I've tried multiple ways, but can't seem to find out why it does this and won't seem to chain.
However i found a workaround where i can create the user without the mgr field and then set the user using the following link/command:
https://social.technet.microsoft.com/Forums/office/en-US/ade19ad5-ecfd-48af-987b-5958983676b6/active-directory-update-the-manager-field-when-the-manager-is-in-a-different-domain?forum=ITCG
Set-ADUser -Identity $ADUser_Domain1 -Credential $DomainAdmin_Domain1 -Server $Domain1 -Replace #{manager = $ManagerDN_Domain2}
This works and I have no idea why the replace works, but seems to require the credential being passed. I've even tried with passing the domain 2 credential.
Overall this is very confusing and i feel like if the local session credential has rights between domains it should be able to look this up without issue. Any additional help or explanation would be REALLY helpful!

Trying to add global security groups to a folder

I wrote a script to create a new folder based on some company variables and later on add a group with users to handle the permissions on this folder.
I can not find a decent way to add one, or more, AD groups to a folder in the same script.
Here is my script:
$parentfolder = Read-Host -Prompt "Please enter the name of the parent folder (i.e. FOLDER1234)"
$folder = Read-Host -Prompt "Please enter the name of the new network folder"
New-Item \\DC02\product\$parentfolder\$folder -type directory
Write-Host "Folder has been created!"
Start-Sleep -s 2
$newgroup = Read-Host -Prompt "Please enter the new group name for this folder (1234-1234-12xx format)"
$description = Read-Host -Prompt "Please enter the abbreviation of the product (i.e. PDPROD)"
NEW-ADGroup -Name $newgroup -GroupScope Global -Description $description -Path "OU=Project Groups,DC=ourdomain,DC=nl"
do {
$stringquit = Read-Host -Prompt "Please enter the member username's to add or press Q if you are done."
$userfilter3 = Get-ADUser -Filter {sAMAccountName -eq $stringquit}
if ($userfilter3 -eq $Null,"Q") {
Write-Host = "User does not exist in AD, please try again"
Start-Sleep -s 1
} else {
if ($stringquit -ne "Q") {
Write-Output -InputObject $stringquit | Out-File -Append c:\userlist.csv
} else {
Write-Host "You pressed Q, moving on."
}
}
} until ($stringquit -eq "Q")
$addgroup = "cn=$newgroup,ou=Project Groups,dc=ourdomain,dc=nl"
$list = Get-Content c:\userlist.csv
foreach ($user in $list) {
Add-ADGroupMember -Identity $addgroup -Member $user
}
#set permissions
$acl = Get-Acl \\DC02\product\$parentfolder\$folder
$ar = New-Object System.Security.AccessControl.FileSystemAccessRule("1234-all","Modify"."ContainerInherit,ObjectInherit","None","Allow")
$acl.SetAccessRule($ar)
Set-Acl \\DC02\product\$parentfolder\$folder $acl
Replace SetAccessRule() with AddAccessRule().