On Windows PowerShell and other admin-related topics

Tips when scripting users in SBS 2008

If you`re like me you like to automate repetitive tasks. Today I was setting up a Windows Small Business Server 2008, and got an Excel spreadsheet with the users to be created.
I customized the spreadsheet and saved it as a csv-file. This is the headers I used in the csv-file:


I then installed Quest`s PowerShell AD Cmdlets to use when creating the user accounts. PowerShell was already installed since Exchange 2007 are installed on SBS 2008.

This the PowerShell code i used:

  1. import-csv "C:\temp\users.csv" |   
  2. foreach-object { $username = $_.samaccountname;New-QADUser -FirstName $_.givenname -LastName $ -ParentContainer $_.ParentContainer -SamAccountName $_.samaccountname -Name $ -displayname $_.displayname -userprincipalname $_.userprincipalname -Company $ -Department $_.department -PhoneNumber $_.telephonenumber | Set-QADUser -UserPassword Password1 -ObjectAttributes @{homeDrive= ‘F:’ ;homeDirectory= "\\domain.local\Data\Users\$username" ;scriptPath=‘netlogon.bat’}|Enable-QADUser} 

SBS 2008 aren`t actually meant for using other tools than the SBS Console, i.e. users should not be created using “Active Directory Users and Computers”. Instead there is a wizard for creating users in the SBS Console. When using this several things happens in the background, like creating home folders, mailboxes, permissions, group membership, and so on…

Also users which are not created using the SBS Console wizard does not show up in the user list in the SBS Console. I knew there is a attribute on the AD objects which the wizard stamps so they are shown in the SBS Console, but I couldn`t remember the name of the attribute. So I asked my very good friend Mr Google, and he gave me a link to a post on the SBS Blog. There I found the name of the attribute which is “msSBSCreationState”, and was planning to script the value of this attribute to the users I`ve just scripted.
Then I read this part of the blogpost:

“If you have users that do not show in the SBS Console, you can get them to show by using the Change user role for user accounts wizard. It is important to notice that this wizard does much more than correctly “stamping” the user’s msSBSCreationState attribute. Using this wizard is only a work around to get the users to show in the SBS Console that were not created using the SBS provided tools. As shown above, the only recommended way adding new users are using the Add a new user account or Add multiple user accounts wizard.”

Then I ran the “Change user role for accounts wizard” to set the account type to “Standard user” for all the scripted user accounts, and afterwards the “magic” of permissions, group membership, mailbox creation and so on were applied. So the tips when scripting user accounts in SBS 2008 is to run this wizard afterwards.

If anyone got any reasons not to create users this way in SBS, please let me know.

You might wonder if there was so many users to be created on a SBS-server which is too much to be done manually, the number was 40 and I`m just too lazy to do that manually 🙂


January 7, 2009 - Posted by | Active Directory management, SBS 2008, Scripting


  1. Jan,

    your powershell sample helped me out alot. I had some problems with setting the homedirectory and drive. Now it all works fine. In my older 2000 environment I had an automated script that also created the user folders, how do you do that after importing the users? Anyway, thanks alot for sharing this info.



    Comment by Yves | March 27, 2009 | Reply

  2. Hi Yves!

    I`m glad the sample helped you.

    Here is another sample which also creates the homefolders:
    import-csv “C:\import.csv” | foreach-object { $username = $_.samaccountname;New-QADUser -FirstName $_.givenname -LastName $ -ParentContainer $_.ParentContainer -SamAccountName $_.samaccountname -Name $ -displayname $_.displayname -userprincipalname $_.userprincipalname -Company $ -Department $_.department -PhoneNumber $_.telephonenumber | Set-QADUser -UserPassword Passord1 -ObjectAttributes @{homeDrive= ‘F:’ ;homeDirectory= “\\domain.local\Data\Users\$username” ;scriptPath=’netlogon.cmd’}|Enable-QADUser;New-Item -Path \\domain.local\Data\Users\$username -type directory}

    For setting NTFS security on the homefolders I`ve used Eric McCarty`s set-FileSystemSecurity function available on his blog:!CE2AE9EFF99E6598!131.entry

    Hint: Install PowerShell Community Extensions (PSCX) SCX 1.1.1 from
    and install it.

    Then grant the “SeRestore” privilege to the PowerShell process (needed for the set-FileSystemSecurity function to be able to set permissions):

    PS > $SeRestore = new-object Pscx.Interop.TokenPrivilege “SeRestorePrivilege”, $true

    Then, grant it to the current process’s token (powershell.exe):

    PS > Set-Privilege $SeRestore

    Then run set-FileSystemSecurity C:\homefolders domain.local

    Comment by Jan Egil Ring | March 31, 2009 | Reply

  3. I’ll try that out, thank you very much.



    Comment by Yves | April 2, 2009 | Reply

  4. Great, thanks

    I’ll keep using (for a while, at least) my VBS + Excel (hacked at MS scriptcenter), but you told me what I was looking for: set “my” users as if they were added using that wizard.

    P.S. Besides your “laziness” reason, there is another one: avoid mistakes & errata

    Comment by Rodeca | October 7, 2009 | Reply

  5. Rodeca, good point! Glad I could help.

    Comment by Jan Egil Ring | October 7, 2009 | Reply

  6. Thanks for this code!

    Inspired by this thread I have made a revision including terminal services settings, that are not created when not using the SBS Wizard.

    Also some of the data is unnecessary in the CSV-fil, because they can be made of other informations already present:
    name, displayname, userprincipalname and parentcontainer

    Since i don’t use telephone and department they are shaved of in my code. They can of course be found in the original script.

    Here goes:


    $UsersCSVPath = “D:\JMA\brugere.csv”
    $LocalDomain = (([DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()).Domains | foreach { $ }) -as [string]
    $ParentContainer= “$LocalDomain/MyBusiness/Users/SBSUsers”
    $Password = “07Navision”

    $TimeSpanZero = New-TimeSpan -Days 0 -Hours 0 -Minutes 0 -Seconds 0

    function WhatIsTehName ([string]$GivenName,[string]$sn) {

    if (($GivenName) -and ($sn)) {
    return “$GivenName $sn”
    } else {
    if ($_.givenname) {
    return $GivenName
    } else {
    return $null


    function CreateUsersFromCSV {

    import-csv $UsersCSVPath |
    foreach-object {

    $Name = WhatIsTehName $_.givenname $

    if ($Name) {

    $username = $_.SamAccountName

    $TsSettings = get-qaduser -Identity support |
    select-object TsAllowLogon,TsRemoteControl,TsMaxDisconnectionTime,TsMaxConnectionTime,TsMaxIdleTime,TsReconnectionAction,TsBrokenConnectionAction,TsConnectClientDrives,TsConnectPrinterDrives,TsDefaultToMainPrinter

    if (!(get-qaduser -SamAccountName $username)){

    try {

    New-QADUser `
    -FirstName $_.givenname `
    -LastName $ `
    -ParentContainer $ParentContainer `
    -SamAccountName $username `
    -Name $Name `
    -displayname $Name `
    -Description $_.description `
    -userprincipalname “$username@$LocalDomain” `
    -UserPassword $Password |
    Get-QADUser |
    Set-QADUser `
    -TsAllowLogon $TsSettings.TsAllowLogon `
    -TsRemoteControl $TsSettings.TsRemoteControl `
    -TsMaxDisconnectionTime $TsSettings.TsMaxConnectionTime `
    -TsMaxConnectionTime $TsSettings.TsMaxDisconnectionTime `
    -TsMaxIdleTime $TsSettings.TsMaxIdleTime `
    -TsReconnectionAction $TsSettings.TsReconnectionAction`
    -TsBrokenConnectionAction $TsSettings.TsBrokenConnectionAction `
    -TsConnectClientDrives $TsSettings.TsConnectClientDrives `
    -TsConnectPrinterDrives $TsSettings.TsConnectPrinterDrives `
    -TsDefaultToMainPrinter $TsSettings.TsDefaultToMainPrinter |

    } catch {
    Write-Host $_.exception.gettype().fullname
    Write-Host $_.exception.message
    } else {
    Write-Host “$Name ($username) allready created (No Problemo)” -BackgroundColor yellow -ForegroundColor Green

    if (Test-Path $UsersCSVPath) {

    Comment by Anders from Randers (DK) | November 12, 2010 | Reply

    • Great, thanks for sharing your revised code!

      Comment by Jan Egil Ring | November 12, 2010 | Reply

      • Thank YOU 🙂

        Comment by Anders | November 12, 2010

  7. Edit:
    This line should have been removed/is not necessary:
    $TimeSpanZero = New-TimeSpan -Days 0 -Hours 0 -Minutes 0 -Seconds 0

    Comment by Anders | November 12, 2010 | Reply

  8. Oups – and a nother thing should be mentioned. The TS-settings are taken from a template user, that must be created prior to running the script (in my script this user is called ‘Support’). Alternatively the data could be exported in some way and then imported. This procedure seems more simple but does require a template user.

    Comment by Anders | November 12, 2010 | Reply

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: