Going multi-tenancy with SharePoint 2010

I recently needed to do a multi-tenancy installation of SharePoint 2010 for a customer. I was very impressed by the AutoSPInstaller scripts to do a full install of SharePoint, so I figured: I want to use this!

So I modified the script to handle multi-tenancy installations as well. This was actually not that complicated. I altered the Service-Applications to have an additional attribute “PartitionMode”, which can be true or false. This will trigger the corresponding PowerShell switch for creating the Service-Application.

When doing a multi-tenancy installation I also modified the installation of the root web-application for the hosting as described by Spence Harbar in his Rational Guide to Multi Tenancy.

I also added new Configuration-Elements to setup tenants (aka Subscriptions).

This code was originally based on the 2.5.5 version and was recently re-based to 2.5.7.

The patch can be found on the CodePlex project site.

Mass-Updating Active Directory

I just love PowerShell! Although I’m not really mature in the syntax yet, I find myself moreoften doing little things in powershell.

Today I figured, that in my previous task of creating 150 sample accounts I missed out on the email-address. So I just wrote a simple line of powershell. First off, I went to the OU just by navigating to the AD-provider cd AD: and then change to cd OU=Test,DC=demo,DC=local. That’s already cool. Then just a simple line like

dir | foreach { $x = Get-AdUser $_; $y=$x.samAccountName; Set-Aduser -identity $x -emailaddress "$y@demo.local"; }

And since I’m on a roll, I also updated the passwords for all users

Get-ADUser -Filter 'Name -like "*"' -SearchBase "OU=Acme,DC=demo,DC=local" | Set-ADAccountPassword -Reset -NewPassword (ConvertTo-SecureString -AsPlainText "demo" -Force)

Sample Domain Data

Sometimes you just need to have a decent amount of sample data. Recently I created an active directory to do some development using SharePoint 2010. In order to have a realistic baseline I needed to have a decent amount of fictive users.

So instead of creating a ton of users like User1 to User150 I thought of something more elaborate. Why not create random user-accounts?

After some google-research I found a blogpost with a list of first- and lastnames as CSV-files. Fantastic! This looks like a promising starting point. To spice everything up a notch I also created list of departments and functions. So this will give me quite a batch of user-data.

To mix everything quite good, I created a little piece of powershell:

# Import list of Last names from Simple Text file
$lastname=import-csv '.\lastname.csv'
# Import list of First names Simple Text file
$firstname=import-csv '.\firstname.csv'
# Import list of roles, prefixes and departments
$roles=import-csv '.\role.csv'
$prefixs=import-csv '.\prefix.csv'
$departments=import-csv '.\department.csv'
# How many names to generate
$totalnames=150
# the Header for our new CSV file
$firstline='Firstname,Lastname,Position,Department,Phone'
# Create a file called “DomainUsers.csv”
Set-content -path 'DomainUsers.csv' -value $firstline
$firstnamecount=$firstname.Count
$lastnamecount=$lastname.Count
$rolecount=$roles.Count-1
$prefixcount=$prefixs.Count-1
$departmentcount=$departments.Count-1
# Go through and Generate some names
foreach ( $namecounter in 1..$totalnames )
{
    # Pick a random first and Last name
    $lastnamenumber=(get-random -min 0 -max ($lastnamecount-1))
    $firstnamenumber=(get-random -min 0 -max ($firstnamecount-1))
    $rolenumber=(get-random -min 0 -max ($rolecount))
    $prefixnumber=(get-random -min 0 -max ($prefixcount))
    $departmentnumber=(get-random -min 0 -max ($departmentcount))
    $FakeName=($firstname[$firstnamenumber].Firstname+','+$lastname[$lastnamenumber].Lastname)+','+
        ($prefixs[$prefixnumber].Prefix+' '+$departments[$departmentnumber].Department+' '+$roles[$rolenumber].Role).Trim()+','+
        $departments[$departmentnumber].Department+','+
        '555-'+(get-random -min 100 -max 999)+'-'+(get-random -min 1000 -max 9999)
    # Echo the New name to the Screen
    write-host $fakename
    # and write to the File
    add-content -path 'DomainUsers.csv' -value $fakename
}

I think the script doesn’t need any further explanation. The result will be a CSV-file with a bunch of random user account data.

The Import into active directory is done in a second powershell-script (just because I had that already).

param([string]$FileName, [string]$adpath)
Import-Module ActiveDirectory
function Import-Users([string]$UserFile)
{
    Import-Csv $UserFile | foreach-object {
        $accountName = $_.Lastname+$_.Firstname.Substring(0,2)
        $displayName=$_.Firstname+" "+$_.LastName
        New-AdUser $accountName -samAccountName $accountName -Company "Acme Corp." -Department $_.Department -DisplayName $displayName -GivenName $_.Firstname -Surname $_.Lastname -OfficePhone $_.Phone -Title $_.Position -CannotChangePassword $true -PasswordNeverExpires $true -Enabled $true -AccountPassword (ConvertTo-SecureString -AsPlainText "demo" -Force) -Path $spou
    }
}
$spou = "OU=Acme,$adpath"
Import-Users $FileName

This is rather boring. To start the script you have to supply the name of the CSV containing the user-data and you have to supply the path to your domain in the form of “dc=acme,dc=local”. This snipplet assumes that there is an OU called Acme, where all the user accounts should be placed.

These are the files I used to generate the sample accounts:

Creating local users – en mass

The traditional way of creating a vast amount of users would include a lot of time as well as patience. Or – maybe just a few lines of (magic) PowerShell code.

So first of all, we have to connect to the local ADSI. This can be done via WinNT://[ComputerName]:

$ComputerName = $env:COMPUTERNAME
$Computer = [adsi]"WinNT://$ComputerName"

This is already the most crucial part. Next we create a new user, set the username, fullname and description and the password.

function Add-User([string]$UserName, [string]$FullName, [string]$Description, [string]$Password)
{
    $User = $Computer.Create("user", $UserName)
    $User.Put("fullName", $FullName)
    $User.Put("description", $Description)
    $User.SetPassword($Password)
    $User.SetInfo()
}

The SetInfo() call ensures, that the data is actually persisted.

Voila, that’s already all you need to get going. Well, in order to create a massive amount of users you will want to create a csv-file of users like:

UserName,FullName,Description,Password
usera,User A,Desc A,passworda
userb,User B,Desc B,passwordb

This can be read with just a single line of code.

function Import-Users([string]$UserFile)
{
    Import-Csv $UserFile | foreach-object { Add-User $_.UserName $_.FullName $_.Description $_.Password }
}

So now all you need is to call Import-Users myNewUsers.csv from the PowerShell command-line and off you go!

When "save" feels like lockdown

So Microsoft really got down to business with this security thing – after installing PowerShell on my new machine I figured, that it’s configured in restricted mode.

This is not some kind of limited mode of operation, but rather this denies the execution of all scripts whatsoever – the term restricted suggested something else, at least in my mindset.

The four PowerShell execution policies include the following:

  • Restricted: No scripts can run.
  • AllSigned: Ps1 and .Ps1xml files must be digitally signed.
  • RemoteSigned: Ps1 and .Ps1xml files from the internet must be digitally signed.
  • Unrestricted: No digital signatures are required and all scripts can be executed.

To find your current policy-setting just use Get-ExecutionPolicy.