{"id":54993,"date":"2008-10-20T11:13:00","date_gmt":"2008-10-20T11:13:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2008\/10\/20\/hey-scripting-guy-how-can-i-create-users-from-a-csv-file\/"},"modified":"2008-10-20T11:13:00","modified_gmt":"2008-10-20T11:13:00","slug":"hey-scripting-guy-how-can-i-create-users-from-a-csv-file","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-create-users-from-a-csv-file\/","title":{"rendered":"Hey, Scripting Guy! How Can I Create Users from a CSV File?"},"content":{"rendered":"<h2><img decoding=\"async\" class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" height=\"34\" alt=\"Hey, Scripting Guy! Question\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\" \/> <\/h2>\n<p>Hey, Scripting Guy! In your last article, you showed how to create random passwords for users and how to write that password out to a CSV file. You said if anyone asked that you would show how to use that CSV file and create a user from it. Well, here I am, asking you. Show me the script. I&#8217;ll send chocolate.<\/p>\n<p>&#8211; LZ<\/p>\n<p><img decoding=\"async\" height=\"5\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" border=\"0\" \/><img decoding=\"async\" class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" height=\"34\" alt=\"Hey, Scripting Guy! Answer\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\" \/> <\/p>\n<p>Hi LZ,<\/p>\n<p>Mmm&#8230;chocolate. I am glad you asked because it gives me a chance to create a really cool script. We are going to use two functions from our previous &#8220;Hey, Scripting Guy!&#8221; article: the <b>CreatePassword<\/b> function and the <b>LtrFmAscii<\/b> helper function that is used to get the letter equivalent from the ASCII integer value. We also need to create two more functions: one that will create a comma separated value (CSV) file that contains user names from a text file, as well as the newly created random passwords for each user. The next function we need to create is one that will read the CSV file and create the user accounts in Active Directory. Here is the complete script, which illustrates several important Windows PowerShell concepts such as creating temporary text files, renaming text files, using regular expressions, and a few others as&nbsp;well:<\/p>\n<pre class=\"codeSample\">Param(\n      $pwdPass = 2,\n      $text = \"C:\\fso\\users.txt\"\n      )\nFunction CreatePassword()\n{ \n for($i = 1 ; $i -le $pwdPass ; $i++)\n {\n   LtrFmAscii($rnd.Next(33,47))\n   LtrFmAscii($rnd.Next(48,57))\n   LtrFmAscii($rnd.Next(65,90))\n   LtrFmAscii($rnd.Next(97,122))\n }\n} #end CreatePassword\nFunction LtrFmAscii($ascii)\n{\n  $script:password += [char]$ascii\n} #End LtrFmAscii\nFunction CreateFile()\n{\n  $script:newText = \"C:\\fso\\UsersAndPassword.csv\"\n  if(test-path -path $script:newText) { Remove-item -path $script:newtext }\n  $tmpText = [io.path]::GetTempFileName()\n  $content = \"User,Password`r`n\"\n  Get-Content -path $text |\n  Foreach-Object `\n  {\n   CreatePassword\n   $content +=  \"$_,`\"$Script:password`\"`r`n\"\n   $script:password = $null\n  }\n  Set-Content $tmpText -value $content \n  Move-Item -path $tmpText -destination $script:newText\n} #end CreateFile\nFunction CreateUsers()\n{\n $aryUser= import-csv -Path $script:newText\n $Class = \"User\"\n $dc = \"dc=nwtraders,dc=com\"\n foreach($strUser in $aryUser)\n {\n  if($strUser.User -match \"[a-zA-Z]\")\n   {\n    $ou = \"ou=myTestOu\"\n    $ADSI = [ADSI]\"LDAP:\/\/$ou,$dc\" \n    $cnuser=\"cn=\"+$($strUser.user)\n    $User = $ADSI.create($Class,$cnuser)\n    $User.put(\"SamaccountName\", $($strUser.user))\n    $User.setInfo()\n    $User.put(\"userPassword\", $($strUser.Password))\n    $user.psbase.invokeset(\"AccountDisabled\", \"False\")\n    $User.setInfo()\n   } #end if $strUser\n } #end foreach $struser\n} #end createUser\n# *** ENTRY TO SCRIPT ***\n$script:password = $null\n$rnd = new-object system.random\nCreateFile\nCreateUsers<\/pre>\n<p>Let&#8217;s begin by taking a look at the <b>CreateFile<\/b> function. The first thing we need to do is assign a string that represents the name and the path of the new file we will create. The new file will be named <b>UsersAndPassword.csv<\/b> and we store this information in the script-level variable <b>newText<\/b>. This is seen here:<\/p>\n<pre class=\"codeSample\">$script:newText = \"C:\\fso\\UsersAndPassword.csv\"<\/pre>\n<p>As a convenience we check for the existence of the <b>UsersAndPassword.csv<\/b> file. If we find it, we delete the file. If you do not want this behavior, I would recommend you comment out the line of code by placing a <b>#<\/b> in front of the line of code. Here is the uncommented line:<\/p>\n<pre class=\"codeSample\">if(test-path -path $script:newText) { Remove-item -path $script:newtext }<\/pre>\n<p>The next thing we do is create a temporary file to hold our user names and the associated passwords. We do this to keep from messing up the list of user names. The temporary file name is generated by using the static method <b>GetTempFileName<\/b> from the <b>system.io.path<\/b> .NET Framework class. Because we are using a static method, we do not need to create an instance of the <b>system.io.path<\/b> class (by using <b>New-Object<\/b>); rather, we can call the method directly by placing the class name in square brackets and using double colons to decorate the method name. In the code below, we do not include the word \u201csystem\u201d because it is not required. With Windows PowerShell we assume .NET Framework class namespaces are preceded with &#8220;system.&#8221; This is seen here:<\/p>\n<pre class=\"codeSample\">$tmpText = [io.path]::GetTempFileName()<\/pre>\n<p>We now use the variable <b>$content<\/b> to hold the header information for our CSV file. The end of the line is a carriage return and a line feed (equivalent to VBScript <b>vbcrlf<\/b>). This is seen here:<\/p>\n<pre class=\"codeSample\">$content = \"User,Password`r`n\"<\/pre>\n<p>Now we need to read the text file containing the list of user names. We use the <b>Get-Content<\/b> cmdlet to do this. We then pass the user names into the pipeline one item at a time, and we use the <b>ForEach-Object<\/b> cmdlet to work with each item as it comes down the pipeline. The first thing we do is call the <b>CreatePassword<\/b> function. When we have the password, we append it to the <b>$content<\/b> variable, which already has our CSV header information. We use the <b>+=<\/b> operator to append to the variable. The user name is stored in the automatic variable <b>$_<\/b>, which represents the current item on the pipeline. We build a string that contains the user name, a comma, and the password that is offset with quotation marks. To allow us to use quotation marks inside a string we need to escape them by using the back tick character. We then add a carriage return line feed to the end of the line by using <b>`r`n<\/b>. Note that it must be in this order. You can use a line feed carriage return <b>`n`r<\/b>, but it will not work the same way. The last thing we need to do is empty the script level <b>$password<\/b> variable. We do this by assigning it the <b>$null<\/b> value. This section of code is seen&nbsp;here:<\/p>\n<pre class=\"codeSample\">Get-Content -path $text |\n  Foreach-Object `\n  {\n   CreatePassword\n   $content +=  \"$_,`\"$Script:password`\"`r`n\"\n   $script:password = $null\n  }<\/pre>\n<p>The last two things we need to do is use the <b>Set-Content<\/b> cmdlet to write the contents of the <b>$content<\/b> variable to the temporary text file represented by the <b>$tmpText<\/b> variable. Last, we need to rename the temporary file and move it to the location we specify in the <b>newText<\/b> variable. We do this by using the <b>Move-Item<\/b> cmdlet. There is a <b>Rename-Item<\/b> cmdlet, but it only allows you to rename items\u2014it does not move items. The <b>Move-Item<\/b> cmdlet will allow you to rename and move at the same time and is what we choose to use&nbsp;here:<\/p>\n<pre class=\"codeSample\">Set-Content $tmpText -value $content \nMove-Item -path $tmpText -destination $script:newText<\/pre>\n<p>Now we get to the <b>CreateUser<\/b> function. The first thing we do is use the <b>Import-Csv<\/b> cmdlet to import our newly created CSV file that is referenced by the script-level variable <b>$newText<\/b>. We store the array of items from the CSV file into the <b>$aryUser<\/b> variable. This is seen here:<\/p>\n<pre class=\"codeSample\">$aryUser= import-csv -Path $script:newText<\/pre>\n<p>We now initialize a couple of local variables. The first one is used to specify the class of object we are going to create in Active Directory. We are going to create users, so we assign the string value &#8220;User&#8221; to the <b>$Class<\/b> variable. Now we assign a value for the domain we are going to work with. We are in the <b>nwtraders<\/b> domain, so we specify <b>dc=nwtraders,dc=com<\/b>. This section of code is seen&nbsp;here:<\/p>\n<pre class=\"codeSample\">$Class = \"User\"\n$dc = \"dc=nwtraders,dc=com\"<\/pre>\n<p>As we walk through the array of user names and passwords, we need to ensure the user name begins with a letter of some kind. To do this, we use the regular expression pattern <b>a-zA-Z<\/b>, which means any lowercase letter and any uppercase letter. This is shown here:<\/p>\n<pre class=\"codeSample\">if($strUser.User -match \"[a-zA-Z]\")<\/pre>\n<p>Now we specify the organizational unit we are going to connect to and use the <b>[adsi]<\/b> type accelerator to connect to the organizational unit named <b>ou=myTestOu<\/b> in the <b>dc=nwtraders,dc=com<\/b> domain. We now need to prepend <b>cn=<\/b> to each user name, and when it is done, we call the <b>Create<\/b> method and give it the class of the object to create and the name of the object. We store the returned <b>DirectoryEntry<\/b> object in the <b>$user<\/b> variable, and use the <b>Put<\/b> method to assign the user name to the <b>SamAccountName<\/b> attribute in Active Directory. We then call the <b>SetInfo<\/b> method to write the information back to Active Directory. This is seen&nbsp;here:<\/p>\n<pre class=\"codeSample\">$ou = \"ou=myTestOu\"\n$ADSI = [ADSI]\"LDAP:\/\/$ou,$dc\" \n$cnuser=\"cn=\"+$($strUser.user)\n$User = $ADSI.create($Class,$cnuser)\n$User.put(\"SamaccountName\", $($strUser.user))\n$User.setInfo()<\/pre>\n<p>Now we need to set the password for our user object. We use the <b>Put<\/b> method to write the password from our CSV file into the <b>userpassword<\/b> attribute in Active Directory. Now we need to enable the user account. To do this, we use the <b>InvokeSet<\/b> method from the base <b>powershell<\/b> object. This methodology allows us to set the <b>AccountDisabled<\/b> value to <b>False<\/b>\u2014which of course means the account is enabled. (I hate double negatives, but that is another story). This is seen&nbsp;here:<\/p>\n<pre class=\"codeSample\">$User.put(\"userPassword\", $($strUser.Password))\n$user.psbase.invokeset(\"AccountDisabled\", \"False\")\n$User.setInfo()<\/pre>\n<p>Well, LZ, that is it. We read a text file containing only user names, and we used our <b>CreatePassword<\/b> function to create random passwords, and then we created a new CSV file containing both the user names and the passwords. We used the <b>Import-Csv<\/b> cmdlet and read the CSV file and created the users in Active Directory. We then set their passwords and enabled the accounts. All in all, a good day&#8217;s work. Later gator.<\/p>\n<p><font class=\"Apple-style-span\" face=\"Verdana\" size=\"3\"><span class=\"Apple-style-span\"><b><b>Ed Wilson and Craig Liebendorfer, Scripting Guys<\/b><\/b><\/span><\/font><\/p>\n<p><font class=\"Apple-style-span\" face=\"Verdana\" size=\"3\"><b><\/b><\/font><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! In your last article, you showed how to create random passwords for users and how to write that password out to a CSV file. You said if anyone asked that you would show how to use that CSV file and create a user from it. Well, here I am, asking you. Show [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[7,169,3,4,20,45],"class_list":["post-54993","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-active-directory","tag-csv-and-other-delimited-files","tag-scripting-guy","tag-scripting-techniques","tag-user-accounts","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! In your last article, you showed how to create random passwords for users and how to write that password out to a CSV file. You said if anyone asked that you would show how to use that CSV file and create a user from it. Well, here I am, asking you. Show [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/54993","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=54993"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/54993\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=54993"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=54993"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=54993"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}