Jump to content

[Powershell] Creating Users from CSV - Home folder


Recommended Posts

Posted

I have this Powershell script that I've amended (and edited for this post to remove specific details out)...but it works great, except for one flaw...it doesn't create the home folder on the share and I don't know why!

 

Import-Module ActiveDirectory
$objOU=[ADSI]”LDAP://LDAPCONNECTION"
$dataSource=import-csv “C:\Users\username\Desktop\users.csv”
foreach($dataRecord in $datasource) {
$cn=$dataRecord.FirstName + ” ” + $dataRecord.LastName
#$sAMAccountName=$dataRecord.FirstName + “.” + $dataRecord.LastName
$sAMAccountName=$dataRecord.Intake + $dataRecord.FirstName.Substring(0,$string.Length+3) + $dataRecord.LastName.Substring(0,$string.Length+4)
$givenName=$dataRecord.FirstName
$sn=$dataRecord.LastName
$sAMAccountName=$sAMAccountName.ToLower()
$ADGroup="Intake " + $dataRecord.Intake

$displayName=$givenName + " " + $sn
$userPrincipalName=$sAMAccountName + “@stjohnwall.local”
$objUser=$objOU.Create(“user”,”CN=”+$cn)
$objUser.Put(“sAMAccountName”,$sAMAccountName)
$objUser.Put(“userPrincipalName”,$userPrincipalName)
$objUser.Put(“displayName”,$displayName)
$objUser.Put(“givenName”,$givenName)
$objUser.Put(“sn”,$sn)
$objUser.Put("description","Intake " + $dataRecord.Intake)
$objUser.Put("mail",$sAMAccountName + "@emailaddress")
$objUser.Put("profilepath","\\SERVER1\netlogon\mandatory3")
$objUser.Put("scriptpath","students.bat")
$objUser.Put("HomeDrive","H:")
$objUser.Put("HomeDirectory","\\SERVER1\users\" + $sAMAccountName)
$objUser.SetInfo()
$objUser.SetPassword(“password”)
$objUser.psbase.InvokeSet(“AccountDisabled”,$false)
$objUser.SetInfo()
Add-ADGroupMember -Identity "Domain Guests" -Member $sAMAccountName
Add-ADGroupMember -Identity "Curriculum" -Member $sAMAccountName
Add-ADGroupMember -Identity $ADGroup -Member $sAMAccountName
}

Can anybody help? :(

Posted

Does it set the HomeDirectory details in the AD account that's created? If it does then I'd guess it's a permissions problem on the parent folder.

 

I'm also curious why you're not using New-ADUser to create accounts, it's a bit more readable and makes it easier to troubleshoot as you can specify -Verbose for extra logging when creating the accounts.

 

Are all your pupil accounts part of Domain Guests? I've never put any users into that group and just use the default Domain Users and any extras we need (intake etc).

  • Thanks 1
Posted
Does it set the HomeDirectory details in the AD account that's created? If it does then I'd guess it's a permissions problem on the parent folder.

 

I'm also curious why you're not using New-ADUser to create accounts, it's a bit more readable and makes it easier to troubleshoot as you can specify -Verbose for extra logging when creating the accounts.

 

Are all your pupil accounts part of Domain Guests? I've never put any users into that group and just use the default Domain Users and any extras we need (intake etc).

Yes, it sets the HomeDirectory details in the properties of the AD account.

 

To be honest, I'm a complete novice with Powershell. The above script is one that I've robbed from the Internet and modified to suit my needs. I'm not entirely sure how to use the New-ADUser commands in Powershell to perform what I'm after.

 

As for Domain Guests, it appears that's the way its always been done here and we don't want to change that in fear of breaking things.

Posted
Does it set the HomeDirectory details in the AD account that's created? If it does then I'd guess it's a permissions problem on the parent folder.

 

I'm also curious why you're not using New-ADUser to create accounts, it's a bit more readable and makes it easier to troubleshoot as you can specify -Verbose for extra logging when creating the accounts.

 

Are all your pupil accounts part of Domain Guests? I've never put any users into that group and just use the default Domain Users and any extras we need (intake etc).

Yes, it sets the HomeDirectory details in the properties of the AD account.

 

To be honest, I'm a complete novice with Powershell. The above script is one that I've robbed from the Internet and modified to suit my needs. I'm not entirely sure how to use the New-ADUser commands in Powershell to perform what I'm after.

 

As for Domain Guests, it appears that's the way its always been done here and we don't want to change that in fear of breaking things.

Posted
assuming its like batch file dsadd for creating users creating the user doesn't create folders you need to do that as a separate command unlike creating them manually that does create them. All the command does is add records to the ad database it doesn't do anything to the file structure
  • Thanks 1
Posted

for what its worth if it helps heres my ds add code for doing it (I do it all in an excel sheet and just copy and paste code lines out to a batch file rather than parsing a csv as that way I can autogenerate names etc

 

dsadd user cn="4someone",ou="2014",ou="pupils",ou="curriculum users2",dc="domain",dc="local" -upn "[email="[email protected]"][email protected][/email]" -display "someone user" -disabled no -hmdir "[url="file://\\domain.local\dfs\users\2014\4someone"]\\domain.local\dfs\users\2014\4someone[/url]" -hmdrv u: -profile "[url="file://\\server\profiles$\roam\pupils\4someone"]\\server\profiles$\roam\pupils\4someone[/url]" -memberof cn="2014",ou="2014",ou="pupils",ou="curriculum users2",dc="domain",dc="local" -fn "someone" -ln "user" -desc 2014 -mustchpwd no -canchpwd no -loscr "pupil.bat" -pwdneverexpires yes
pause
md "d:\users\2014\4someone"
pause
cacls "d:\users\2014\4someone" /T /E /G 4someone:C

as you can see line 1 is creating the user account line 2 creates the folder line 3 sets permissions (ignoring pause lines)

  • Thanks 1
Posted

Here is what we use for creating home directories and Importing users from CSV all in one..

 

CSV File Structure:

Forename,Surname,Username,Password,EmailAddress,Description,UPN,OU,City,Department,Script,HomeDir,Telephone,Web,Country,State,Post
Test,User,Test User,s0sqv5,[email protected],Pupil,12345678,"OU=2015,OU=Current Years,OU=Users - Pupils,DC=SCH,DC=local",Sheffield,Pupil TG,pupils.bat,\\someserver\pupils\2015\,1111 111111,www.school.com,England,Somewhere,555 555

 

And the Powershell... It defaults to users.csv in the same directory. It may need some modifying for your setup though, it also writes to duplicates.txt if it can't import.

 

By default the home directories are stored as firstname surname in the folder specified in the CSV. It also adds Read, Write and Modify permissions to the home folder.

 

I can't take credit for it as it's one I found a while ago online and modified it to suit.

 

Import-Module ActiveDirectory $Users = Import-Csv -Delimiter "," -Path "./users.csv" 

foreach ($User in $Users)   {  
       $OU = $User.OU 
       $Password = $User.password 
       $description = $User.description
       $Detailedname = $User.forename + " " + $User.surname
       $EmployeeID = $User.upn
       $UserFirstname = $User.forename 
       $emailAddress = $User.EmailAddress
       $SAM = $Detailedname 
       $homedir = $User.homedir
       $homedirAD = $homedir + $Detailedname
       New-ADUser -ErrorAction SilentlyContinue -Name $Detailedname -SamAccountName $SAM -City $User.city -telephoneNumber $User.telephone -wWWHomePage $User.web -department $User.department -postOfficeBox = $User.country -state = $User.state -postalCode = $User.post -EmailAddress $emailAddress -EmployeeID $EmployeeID -UserPrincipalName $SAM -DisplayName $Detailedname -GivenName $user.forename -Surname $user.surname -AccountPassword (ConvertTo-SecureString $Password -AsPlainText -Force) -Enabled $true -Description $description -HomeDrive "H:" -HomeDirectory $homedirAD -ScriptPath $User.script -Path $OU  


   if(!$?) {
   if($error[0] = "The specified account already exists") {
       $errorStr = $error[0] + ": " + $SAM
       Write-Warning $errorStr
       $tentry = "`n" + $Detailedname
       Add-Content ./duplicates.txt $tentry
   }
   } else {
   New-Item -path $homedir -Name $Detailedname -ItemType Directory
   $userDir = "$homedir\$Detailedname"
   $Rights= [system.Security.AccessControl.FileSystemRights]::Read -bor [system.Security.AccessControl.FileSystemRights]::Write -bor [system.Security.AccessControl.FileSystemRights]::Modify
       $Inherit=[system.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [system.Security.AccessControl.InheritanceFlags]::ObjectInherit
       $Propogation=[system.Security.AccessControl.PropagationFlags]::None
       $Access=[system.Security.AccessControl.AccessControlType]::Allow
       $AccessRule = new-object System.Security.AccessControl.FileSystemAccessRule("$Detailedname",$Rights,$Inherit,$Propogation,$Access)
       $ACL = Get-Acl $userDir
       $ACL.AddAccessRule($AccessRule)
       $Account = new-object system.security.principal.ntaccount($Detailedname)
       $ACL.setowner($Account)
       $ACL.SetAccessRule($AccessRule)
       Set-Acl $userDir $ACL


   $out = "The AD Account: " + $Detailedname + " and Home Directory: " + $homedirAD + " have been created."
   Write-Host $out
   }
} 

  • Thanks 1
Posted

From looking over your script and mine and doing a bit more testing it's almost certainly because you're not creating the folder as part of the script. Both the scripts posted by @sted and @SteveM555 do create the folders and assign permissions and I'd guess don't have the problem.

 

I'm in the process of updating my script to do this (I thought AD would do it automatically like it does with Profiles but apparently not), I'll post my script once I'm done with it (mostly writing help comments) to give you another perspective on it.

  • Thanks 1
Posted
From looking over your script and mine and doing a bit more testing it's almost certainly because you're not creating the folder as part of the script. Both the scripts posted by @sted and @SteveM555 do create the folders and assign permissions and I'd guess don't have the problem.

 

I'm in the process of updating my script to do this (I thought AD would do it automatically like it does with Profiles but apparently not), I'll post my script once I'm done with it (mostly writing help comments) to give you another perspective on it.

 

ad itself dosent create profiles (if you check your profiles folder after creating a user there isn't one for that user) BUT a user can self create at first logon (assuming correct permissions etc)

  • Thanks 1
Posted

Thanks for the replies so far. I've created a new script based on @SteveM555's script, but I'm getting an error message that I don't understand! :(

 

Import-Module ActiveDirectory

$CSV = Import-CSV -Delimiter "," "D:\PS\New-ADUser.csv”

foreach ($User in $CSV) {
$sAMAccountName = $_.Intake + $_.Forename.Substring(0,$string.Length+3) + $_.Surname.Substring(0,$string.Length+4)
$UserPrincipalName = $sAMAccountName + “@stjohnwall.local”
$DisplayName = $_.Forename + " " + $_.Surname
$Surname = $_.Surname
$GivenName = $_.Forename
$Path = "Intake " + $_.Intake + "OU=Curriculum,OU=St John Wall Student Accounts,DC=stjohnwall,DC=local"
$EmailAddress = ($sAMAccountName + "@sjw.bham.sch.uk")
$AccountPassword = ConvertTo-SecureString -AsPlainText "password" -Force
$Enabled = $true
$ChangePasswordAtLogon = $true
$Description = "Intake" + $_.Intake
$HomeDirectory = "\\curricsvr-01\users\" + $sAMAccountName
$HomeDrive = "H:"
$ProfilePath = "\\CURRICSVR-01\netlogon\mandatory3"
$ScriptPath = "students.bat"

New-ADUser -ErrorAction SilentlyContinue `
-sAMAccountName $sAMAccountName `
-UserPrincipalName $UserPrincipalName `
-DisplayName $DisplayName `
-Surname $Surname `
-GivenName $GivenName `
-Path $Path `
-EmailAddress $EmailAddress `
-AccountPassword $AccountPassword `
-Enabled $Enabled `
-ChangePasswordAtLogon $ChangePasswordAtLogon `
-Description $Description `
-HomeDirectory $HomeDirectory `
-HomeDrive $HomeDrive `
-ProfilePath $ProfilePath `
-ScriptPath $ScriptPath }

{
   New-Item -path $HomeDirectory -Name $DisplayName -ItemType Directory
       $userDir = "$HomeDirectory\$DisplayName"
       $Rights= [system.Security.AccessControl.FileSystemRights]::Read -bor [system.Security.AccessControl.FileSystemRights]::Write -bor [system.Security.AccessControl.FileSystemRights]::Modify
           $Inherit=[system.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [system.Security.AccessControl.InheritanceFlags]::ObjectInherit
           $Propogation=[system.Security.AccessControl.PropagationFlags]::None
           $Access=[system.Security.AccessControl.AccessControlType]::Allow
           $AccessRule = new-object System.Security.AccessControl.FileSystemAccessRule("$DisplayName",$Rights,$Inherit,$Propogation,$Access)
           $ACL = Get-Acl $userDir
           $ACL.AddAccessRule($AccessRule)
           $Account = new-object system.security.principal.ntaccount($DisplayName)
           $ACL.setowner($Account)
           $ACL.SetAccessRule($AccessRule)
           Set-Acl $userDir $ACL
           
$out = "The AD Account: " + $DisplayName + " and Home Directory: " + $userDir + " have been created."
   Write-Host $out
   }

I am getting the following error message:

You cannot call a method on a null-valued expression.
At line:6 char:52
+ $sAMAccountName = $_.Intake + $_.Forename.Substring <<<< (0,$string.Length+3) + $_.Surname.Substring(0,$string.Length+4)
   + CategoryInfo          : InvalidOperation: (Substring:String) [], RuntimeException
   + FullyQualifiedErrorId : InvokeMethodOnNull

I need to include this as this determines our username convention. (Intake year + 3 letters of forename + 4 letters of surname | 14tesUser)

Posted

You cannot call a method on a null-valued expression.
At line:6 char:52
+ $sAMAccountName = $_.Intake + $_.Forename.Substring <<<< (0,$string.Length+3) + $_.Surname.Substring(0,$string.Length+4)
   + CategoryInfo          : InvalidOperation: (Substring:String) [], RuntimeException
   + FullyQualifiedErrorId : InvokeMethodOnNull

I need to include this as this determines our username convention. (Intake year + 3 letters of forename + 4 letters of surname | 14tesUser)

 

You need to change the line slightly as you don't have a $string variable in use. You'll need to change it to:

 

$sAMAccountName = $_.Intake + $_.Forename.Substring(0,$_.Forename.length+3) + $_.Surname.Substring(0,$_.Surname.length+4)

  • Thanks 1
Posted
You need to change the line slightly as you don't have a $string variable in use. You'll need to change it to:

 

$sAMAccountName = $_.Intake + $_.Forename.Substring(0,$_.Forename.length+3) + $_.Surname.Substring(0,$_.Surname.length+4)

Still getting the same error with the amended line :(

You cannot call a method on a null-valued expression.
At line:6 char:52
+ $sAMAccountName = $_.Intake + $_.Forename.Substring <<<< (0,$_.Forename.length+3) + $_.Surname.Substring(0,$_.Surname.length+4)
   + CategoryInfo          : InvalidOperation: (Substring:String) [], RuntimeException
   + FullyQualifiedErrorId : InvokeMethodOnNull

When I run the script (currently using Windows PowerShell ISE), it is showing a popup box. Screenshot attached.

[ATTACH=CONFIG]31110[/ATTACH]

Posted (edited)
Still getting the same error with the amended line :(

You cannot call a method on a null-valued expression.
At line:6 char:52
+ $sAMAccountName = $_.Intake + $_.Forename.Substring <<<< (0,$_.Forename.length+3) + $_.Surname.Substring(0,$_.Surname.length+4)
   + CategoryInfo          : InvalidOperation: (Substring:String) [], RuntimeException
   + FullyQualifiedErrorId : InvokeMethodOnNull

When I run the script (currently using Windows PowerShell ISE), it is showing a popup box. Screenshot attached.

[ATTACH=CONFIG]31110[/ATTACH]

 

Just noticed the foreach loop is actually using $User instead of $_ for the variable name, that is likely causing a problem. Might also be worth wrapping the $User.Forename and $User.Surname in () brackets before the .substring section to ensure it's evaluating each part individually.

 

You'll also have to specify the -name property for New-ADUser as it's a required parameter. I'm guessing it will be the same value as your sAMAccountname but it depends on what you'd like to use, Get-ADUser -Identity will tell you what format you currently use if you don't know which one to use.

Edited by halbaradkenafin
  • Thanks 1
Posted
Just noticed the foreach loop is actually using $User instead of $_ for the variable name, that is likely causing a problem. Might also be worth wrapping the $User.Forename and $User.Surname in () brackets before the .substring section to ensure it's evaluating each part individually.

 

You'll also have to specify the -name property for New-ADUser as it's a required parameter. I'm guessing it will be the same value as your sAMAccountname but it depends on what you'd like to use, Get-ADUser -Identity will tell you what format you currently use if you don't know which one to use.

What should I enter instead of $Users in the foreach loop? Simply just $_? So those two lines would look like this?

foreach ($_ in $CSV) {
$sAMAccountName = $_.Intake + ($_.Forename).Substring(0,$_.Forename.length+3) + ($_.Surname).Substring(0,$_.Surname.length+4)

Posted
What should I enter instead of $Users in the foreach loop? Simply just $_? So those two lines would look like this?

foreach ($_ in $CSV) {
$sAMAccountName = $_.Intake + ($_.Forename).Substring(0,$_.Forename.length+3) + ($_.Surname).Substring(0,$_.Surname.length+4)

 

Just replace all instances of $_ with $User (Find/Replace tool will make this easy), it should fix the code and make it more readable.

  • Thanks 1
Posted (edited)

After finding typing mismatches between my CSV file and code (which I've now corrected), I'm now getting a different error message:

Exception calling "Substring" with "2" argument(s): "Index and length must refer to a location within the string.
Parameter name: length"
At line:7 char:60
+ $sAMAccountName = $User.Intake + ($User.Forename).Substring <<<< (0,$User.Forename.length+3) + ($User.Surname).Substring(0,$User.Surname.length+4)
   + CategoryInfo          : NotSpecified: ( [], MethodInvocationException
   + FullyQualifiedErrorId : DotNetMethodException

 

Edit:

I've changed the problematic line to:

$sAMAccountName = $User.Intake + ($User.Forename).Substring(0,3) + ($User.Surname).Substring(0,4)

That has now sorted that error, but now I'm encountering more errors further down the script!

Edited by CHiLL
Posted
Done that, but still the same error message:

You cannot call a method on a null-valued expression.
At line:6 char:60
+ $sAMAccountName = $User.Intake + ($User.Forename).Substring <<<< (0,$User.Forename.length+3) + ($User.Surname).Substring(0,$User.Surname.length+4)
   + CategoryInfo          : InvalidOperation: (Substring:String) [], RuntimeException
   + FullyQualifiedErrorId : InvokeMethodOnNull

 

 

Does the csv contain columns called Forename, Surname etc? If it does then I'd next see what data the script is trying to work with, before the $sAMAccountName line add in

Write-Host $User.Forename
Write-host $User.Surname

 

This should give you an idea of what the field actually contains. If it shows two blank lines before the error message then it means your columns aren't named the same as the script is looking for (it shouldn't be case sensitive). If it shows the correct data from your csv then I'd resorted to messing around in the command line view using various lines one at a time, probably something like:

 

$test = Import-csv -path "D:\PS\New-ADUser.csv"
Write-host $Test[0]
Write-host ($test[0].forename).Substring(0,$test[0].forename.length+3)

 

If that gives any error messages then I'd expect it to be on the last line.

 

Also, that popup is still occurring. :(

 

You'll need to add -Name to the New-ADUser command, before the -ErrorAction parameter would be best.

  • Thanks 1
Posted (edited)

I've managed to sort that, though it's now failing on the creation of the home folder section, with the following messages:

Exception calling "AddAccessRule" with "1" argument(s): "Some or all identity references could not be translated."
At line:57 char:31
+             $ACL.AddAccessRule <<<< ($AccessRule)
   + CategoryInfo          : NotSpecified: ( [], MethodInvocationException
   + FullyQualifiedErrorId : DotNetMethodException

Exception calling "SetOwner" with "1" argument(s): "Some or all identity references could not be translated."
At line:59 char:26
+             $ACL.setowner <<<< ($Account)
   + CategoryInfo          : NotSpecified: ( [], MethodInvocationException
   + FullyQualifiedErrorId : DotNetMethodException

Exception calling "SetAccessRule" with "1" argument(s): "Some or all identity references could not be translated."
At line:60 char:31
+             $ACL.SetAccessRule <<<< ($AccessRule)
   + CategoryInfo          : NotSpecified: ( [], MethodInvocationException
   + FullyQualifiedErrorId : DotNetMethodException

 

Edit: I edited the $userDir variable to be just $HomeDirectory and now it creates the home folder...however it does not assign the permissions for the user. (Still shows the same error message as above)

Edited by CHiLL
Posted
You may need to modify the lines around there that say "$Displayname" to "\$Displayname". I've found that to cause problems in the past when assigning ACEs this way. If it's still occurring then I'd add in Start-Sleep -s 10 after the New-ADUser statement to allow it time to properly update the DCs.
  • Thanks 1
Posted

Thanks, that's working! :D

 

Another question though, our username naming convention is based on the year a student leaves year 11 (don't ask me why). Is there an easy way to take the Intake variable and plus 5 onto it? So I can create that as a variable for building the $sAMAccountName?

Posted
Thanks, that's working! :D

 

Another question though, our username naming convention is based on the year a student leaves year 11 (don't ask me why). Is there an easy way to take the Intake variable and plus 5 onto it? So I can create that as a variable for building the $sAMAccountName?

 

That's quite an easy one to handle (though it will look a little convoluted at first) and depends on how your csv stores the intake year. Assuming you store it as just the two digit number then you can do this:

 

$LeavingYear = [int]$_.Intake + 5

 

And then substitute $LeavingYear in your $sAMAccountName where it currently has $_.Intake. If you do 4 digit intake year in the csv then it's just a slight modification to the above code:

 

$LeavingYear = [int]($_.Intake.substring(2)) + 5

  • Thanks 1
Posted

Thanks. :)

Currently getting this error:

Exception calling "Substring" with "2" argument(s): "Index and length must refer to a location within the string.
Parameter name: length"
At D:\PS\Complete.ps1:12 char:51
+ $sAMAccountName = $Leaving + ($Forename).Substring <<<< (0,3) + ($Surname).Substring(0,4)
   + CategoryInfo          : NotSpecified: ( [], MethodInvocationException
   + FullyQualifiedErrorId : DotNetMethodException

 

The code up that point of error is:

foreach ($User in $CSV) {
$Forename = $User.Forename
$Surname = $User.Surname
$Intake = $User.Intake
$Leaving = [int]$User.Intake + 5 #Based on 2 digit year in CSV
#$Leaving = [int]($User.Intake.substring(2)) + 5 #Based on 4 digit year in CSV
$Name = $User.Forename + " " + $User.Surname
$sAMAccountName = $Leaving + ($Forename).Substring(0,3) + ($Surname).Substring(0,4)

I think it has something to do with the fact $Leaving has been converted to an integer. I have attempted to convert it back to a string but it still isn't working.

Posted
One solution to that is to wrap the $Leaving part of $sAMAccountName in "" and it will parse it as a string with the value of the variable.

Unfortunately, that hasn't worked, still the same issue. :(

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now



×
×
  • Create New...