New Bulk ADUser

Welcome Forums General PowerShell Q&A New Bulk ADUser

This topic contains 13 replies, has 5 voices, and was last updated by

 
Participant
2 months, 3 weeks ago.

  • Author
    Posts
  • #109097

    Participant
    Points: 48
    Rank: Member

    I wish to do a bulk import .csv and then do a New-ADUser. I have this:

    $secpass = Read-Host "Password" -AsSecureString 
    Import-Csv .\SVCAccounts_test.csv |
    foreach {
      $name = "$($_.DisplayName)"
       
     New-ADUser -Name $name -DisplayName $($_.DisplayName) `
        -SamAccountName $($_.SamAccountName) `
        -Department $($_.Department) `
        -Description $($_.Description) `
        -EmailAddress $($_.mail) `
        -AccountPassword $secpass -Path "OU=ServiceAccts,DC=corp,DC=com" `
        -Enabled:$true
        -PasswordNeverExpires:$true
        -otherAttributes @{'otherMailbox'=$_.otherMailbox}
       
    }

    There are errors with it however, balking of parameters that don't exist. Please tell me what's wrong with my above code.

    ...but I also have this code because it seems to allow me to work with the 'otherMailbox' parameter of Set-ADuser:

    $User = Import-Csv -Path .\Manager.csv | Set-ADUser -Identity $User -EmailAddress $User.mail -Department $User.Department -Add @{otherMailbox=$User.OtherMailbox}

    How do I implement a bulk New-ADUser as well as set some of it's non-default parameters such as 'otherMailbox' in one piece of code?

    thank you

  • #109109

    Participant
    Points: 158
    Helping Hand
    Rank: Participant

    Not a fan of the accent characters, I prefer splatting. You can just pipe the new user to Set-AdUser, something like this:

    $secpass = Read-Host "Password" -AsSecureString 
    Import-Csv .\SVCAccounts_test.csv |
    foreach {
        $newUserParams = @{
            Name                 = $_.DisplayName
            DisplayName          = $_.DisplayName
            SamAccountName       = $_.SamAccountName
            Department           = $_.Department
            Description          = $_.Description
            EmailAddress         = $_.mail
            AccountPassword      = $secpass
            Path                 = "OU=ServiceAccts,DC=corp,DC=com"
            Enabled              = $true
            PasswordNeverExpires = $true
        }
    
        $setUserParams = @{
            Add = @{'otherMailbox'=$_.otherMailbox}
        }
    
       
        New-ADUser @newUserParams | 
        Set-ADUser @setUserParams
       
    }
    
    • #109118

      Participant
      Points: 48
      Rank: Member

      Very clean approach Rob, thank you.

  • #109111

    Participant
    Points: 0
    Rank: Member

    Pre-validate your attribute, avoiding the null values like the code behind:

    OtherAttributes = if(!([string]::IsNullOrEmpty($_.otherMailbox))){@{otherMailbox = $_.otherMailbox}}else {@{otherMailbox = 'NA'}}
    

    I used this link as a base:
    https://stackoverflow.com/questions/50319539/new-aduser-argument-otherattributes

  • #109124

    Participant
    Points: 58
    Rank: Member

    Since most of parameters for New-ADUser accept pipeline by property name, you could take advantage of that approach as well. I have not tested this, but don't see why it wouldn't work since we are declaring values for all parameters that do not accept pipeline input.

    $secpass = Read-Host "Password" -AsSecureString 
    Import-Csv .\SVCAccounts_test.csv | New-ADUser -AccountPassword $secpass -PasswordNeverExpires $true -Path "OU=ServiceAccts,DC=corp,DC=com" -OtherAttributes @{'otherMailbox'=$_.otherMailbox} -Verbose
    
    • #109243

      Participant
      Points: 48
      Rank: Member

      L-Bo, I'm trying ton understand your premise. you say most parameters of New-ADUser accept pipeline input (assuming this includes all of the one I'll be needing) but then you state your one-liner would most likely work because the (same?) parameters do not accept pipeline input?

      Sorry, I lost your reasoning.

    • #109496

      Participant
      Points: 58
      Rank: Member

      Jeff,

      Most of the parameters have pipeline support by property name. SamAccountName,Department,Description, etc all accept pipeline input. (get-help is useful for determining what does and doesn't accept pipeline input)

      An example of a parameter that doesn't accept pipeline input is "OtherAttribute" which is why it is defined in the command, where "description" isn't. -Path as well as -PasswordNeverExprires are also capable of accepting pipeline input, but since it was statically defined in your original script I made an educated guess that it wasn't included in your csv file.
      You can use the below command to get a list of all the parameters that accept pipeline input for the New-ADUser cmdlet

      Get-Help New-ADUser -Parameter * | ? {$_.pipelineInput -match 'true'} | ft -AutoSize
      

      I was simply demonstrating that although Splatting is useful, and an approach I often take, why NOT take advantage of the great pipeline support that is built right into the cmdlet? Its 6 in one, half a dozen in the other.

  • #109501

    Participant
    Points: 48
    Rank: Member

    thanks L-Bo that's clearer.

    So, during this part of the pipeline approach

    Import-Csv .\SVCAccounts_test.csv 

    ...on the other side of the pipeline (not including the calculated property) will automatically see the comma delimited properties that I have, and then set those in the New-User statement?

    I don't actually have to define each and every one ( the 3, etc. you mention and that I have in my csv) on the other side of the pipeline?

    "accept Pipeline by Input" does it for me?

    NOTE: I tested your one-liner but get an error and the new Users are not created:

    New-ADUser : Cannot validate argument on parameter 'OtherAttributes'. The argument is 
    null or an element of the argument collection contains a null value.
    • #109600

      Participant
      Points: 58
      Rank: Member

      Jeff,

      Yes, ValueFromPipelineByPropertyName "does it for you" so to speak. If you feed the cmdlet an object with property names that match it's parameters then you do not need to define them. Keep in mind that the headers of your csv file (it's "properties") must match the corresponding parameter exactly for ValueFromPipelineByPropertyName to work. I wasn't suggesting this is the best way to achieve this for your purposes, I am simply providing an example that utilizes a slightly different approach and yields the same results. If the data in the .csv file is "dirty" (null values, formatting issues, etc.) then the pipeline is probably not the best approach.

    • #109610

      Participant
      Points: 48
      Rank: Member

      L-Bo, yep got it thanks again for the additional clarification.

  • #109558

    Participant
    Points: 158
    Helping Hand
    Rank: Participant

    Just want to make sure I understand that the problem was\is just how to call Set-ADUser. If your CSV has NULL values for some values, this can be handled with splatting as well to dynamically build the parameters:

    $secpass = Read-Host "Password" -AsSecureString 
    Import-Csv .\SVCAccounts_test.csv |
    foreach {
        $newUserParams = @{
            Name                 = $_.DisplayName
            DisplayName          = $_.DisplayName
            SamAccountName       = $_.SamAccountName
            Department           = $_.Department
            Description          = $_.Description
            EmailAddress         = $_.mail
            AccountPassword      = $secpass
            Path                 = "OU=ServiceAccts,DC=corp,DC=com"
            Enabled              = $true
            PasswordNeverExpires = $true
        }
    
     
        $setUserParams = @{
            Department = $_.Department
        }
    
        #Only if the otherMailbox has a value, add the "Add" param
        If ( $_.otherMailbox ) {
            $setUserParams.Add('Add', @{'otherMailbox'=$_.otherMailbox})
        }
    
        New-ADUser @newUserParams | 
        Set-ADUser @setUserParams
       
    }
    
    • #109597

      Participant
      Points: 48
      Rank: Member

      Rob,

      In your second example, you have

      $setUserParams = @{
      
      Department = $_.Department
      
      }

      ..but you already had it defined in the $newUserParams array. Not sure why it would need here.

  • #109561

    Participant
    Points: 527
    Helping Hand
    Rank: Major Contributor

    Like Rob pointed out, its better to do splatting here. When your input is subjected for changes, its always good to "See failures ahead" and code. You can do a lot of error handling here.

  • #109622

    Participant
    Points: 158
    Helping Hand
    Rank: Participant

    @jeff-taylor I just don't want to pipe nothing to Set-ADUser, if I know Department will always be there but otherMailBox could be NULL I won't get an error sending nothing to Set-ADUser. So, the code you referenced is a static reference. If the initial problem for otherMailBox was that certain users have a NULL value, you could get rid of Set-ADUser all together and use the splat $newUserParams to add otherAttributes like you were doing in your initial post.

You must be logged in to reply to this topic.