Adventure in SPWonderland

Take apart and put back together


SharePoint/PowerShell 3: Now add the users to SharePoint

Ok now we have the users in AD we can add them to the portal. Again we can use import-csv to add them from the users CSV file

heres the routine

# Function:         Add-UsersToSP
# Description:        Add each user in the import CSV file to the given role
# Parameters:        SiteCollectionURL     URL for the root of the Site Collection    
#            UserFile         Location of the CSV file containing the users
#            Domain            Users domain
#            Role             Name of the SharePoint Role e.g Reader, Contribute
function Add-UsersToSP([string]$SiteCollectionURL,[string]$UserFile, [string]$Domain, [string]$Role)
Import-Csv $UserFile | foreach-object {$spsite=new-object Microsoft.SharePoint.SPSite($SiteCollectionURL) } {$spsite.RootWeb.Roles[$Role].AddUser($Domain + "\" + $_.LoginName, $_.Email, $_.DisplayName, "") }

In this script we get a SPSite object, get its rootweb and index into the roles collection to return the role we want. We then use the AddUser method to add the user.

And we call it like this Add-UsersToSP "http://sps:2828" "users.csv" "contoso" "contribute"

Now there is something a little different going on in this script. In the foreach-object loop there are 2 scriptblocks (the curly braces). This is because you can have up to 3 scriptblocks in the foreach clause: Begin, Process and End

The Begin scriptblock will be called once at the start of the iteration, Process is called for each object in the collection and End will be called at yes the end of the iteration allowing you to clean up your objects. I don't have an end in this case but you could call dispose on the SPSite object.

In v3 the Roles collection is deprecated and you should start using the new SPRoleDefinition and SPRoleAssignment classes. These new classes have full support for the new security features but for now I'm keeping things as simple as I can. 

Now is a good time to point out how easy it is to explore the SharePoint OM interactively, in this case the Roles collection.

First of all from the command line do this

PS C:\demo> $spsite=new-object microsoft.sharepoint.spsite("http://sps:2828")
PS C:\demo> $spsite.rootweb.roles

this produces a listing like this

Name : Full Control
Users : {}
Groups : {SUGUK Intranet Owners}
Type : Administrator
Description : Has full control.
Xml : <Role ID="1073741829" Name="Full Control" Description="Has ful
l control."
Type="5" />
ID : 1073741829
PermissionMask : FullMask
ParentWeb : SUGUK Intranet

Name : Design
Users : {}
Groups : {Designers}
Type : WebDesigner
Description : Can view, add, update, delete, approve, and customize.
Xml : <Role ID="1073741828" Name="Design" Description="Can view, add
, update, delete, approve, and customize."
Type="4" />
ID : 1073741828
PermissionMask : 1012866047
ParentWeb : SUGUK Intranet


You can use the select CmdLet to produce a simple table listing

PS C:\demo> $spsite.rootweb.roles | select name, users

Name                                    Users                                 
----                                    -----                                 
Full Control                            {}                                    
Design                                  {}                                    
Manage Hierarchy                   {}                                    
Approve                                {}                                    
Contribute                             {Brian Ballack, Walter French}        
Read                                    {}                                    
Restricted Read                      {}                                    
Limited Access                       {NT AUTHORITY\authenticated users, S...
View Only                              {}  


If we want to see the full object of say the RootWeb you can do this

PS C:\demo> $spsite.rootweb | get-member

or just its properties

PS C:\demo> $spsite.rootweb | get-member -membertype property

or just its methods

PS C:\demo> $spsite.rootweb | get-member -membertype methods

I find myself using this lot before coding C# against an object as I can try out the API and mess around with it before running up VS2005

The next step will be to create a host of portal areas as defined in a CSV file.






SharePoint/PowerShell 2: Add some Users to Active Directory, maybe 1, maybe 500

Step 2 in our series is to add some users to Active Directory.

First we need a simple routine to add users to Active Directory

Update 3-11-2006 : The original add-aduser would only work in versions of PowerShell pre RC2. RC2 included some breaking changes to how the DirectoryEntry object handled. I;ve added an RC2 compatible routine.

Pre RC2 version

function add-aduser([string]$LoginName, [string]$DisplayName, [string]$FirstName, [string]$LastName)


    $ad= new-object System.DirectoryServices.DirectoryEntry
    $u = $ad.get_Children().Find("CN=Users")
    $NewUser = $u.get_Children().add("CN=$cn",'User')


    $ad=new-object System.DirectoryServices.DirectoryEntry
    $u = $ad.get_Children().Find("CN=Users")

    $NewUser= $u.get_Children().Find("CN=$cn");

    # set that the password never expires
    $NewUser.userAccountControl[0] = $NewUser.userAccountControl[0] -bor (65536)




RC2 Version

function add-aduser([string]$LoginName, [string]$DisplayName, [string]$FirstName, [string]$LastName)



   # Get an ADSI object for the default domain
   $ad= [ADSI]""

   # Get the Users OU as default
   $ou = $ad.psbase.Children.Find("CN=Users")

   # Add the user
   $NewUser = $ou.psbase.Children.Add("CN=$cn",'User') 

   # Set the basic properties

   # Commit changes 

   # Set our password 

   # And enable the account

   # set that the password never expires
   $NewUser.userAccountControl[0] = $NewUser.userAccountControl[0] -bor (65536) 

   # Commit changes


This gets us a function we can call to add test users. Note we're hardcoding the OU to users, to make this more production you'd want to parameterize the OU, passwords and set the AccountControl flags to Change Password on next login, there's a lot of other resources out there to help with that.

So If we put that in a script file loaded from our Profile we can call it like this

add-aduser "joeb" "joe blogs" "joe" "blogs"

That's nice but with PowerShell we can do better. We really want to data drive this and the built-in import-csv function will parse a CSV and create a collection of objects that match the CSV schema.

Take a simple User's CSV file like this

LoginName, DisplayName, FirstName, LastName, Email

brianb, Brian Ballack, Brian, Ballack, brianb
walterf, Walter French, Walter, French, walterf


Now if we run an import-xml command on the CSV file this is the output


Each line has been parsed and an object created. To see this more clearly we can use the get-member command to reflect over the object and see what the object looks like.


(Note: it will be PSCustomObject not MshCustomObject in post RC0 builds , I'm running Exchange 2007 on this VPC which requires PowerShell RC0)

As you can see the CSV columns have been added as a NoteProperty property (this is part of the extensible type system).

So now we can create a really simple function to import a CSV file of users, pipe the output to a foreach loop and add each user to Active Directory.

# Function:         Import-Users
# Description:        Create users in active directory as listed in the import CSV file
# Parameters:        UserFile         Location of the CSV file containing the users
function Import-Users([string]$UserFile)
    Import-Csv $UserFile | foreach-object { add-aduser $_.LoginName $_.DisplayName $_.FirstName $_.LastName }

Note that when you receiving a collection of objects in the pipeline in a scriptblock you have to loop over each object. The $_ is a special variable that gives you the current object in the loop which you can use to access properties and methods.

To call we just do

Import-Users Users.CSV

With this power 500 users are as easy as 1 user.

We're not limited to just using CSV files, I've just picked that format as I'm always amazed at the amount of data I get given in Excel spreadsheets and word documents and CSV is the easiest intermediate format to work with. There is also an import-xml command which we will use later to import an XML file containing portal content. As Powershell can call any .Net library the System.Data set of classes could also be used to pull information from databases.

The next entry will be adding our users to SharePoint.

Presention Slides and PowerShell code from UK SharePoint User Group Thursday 26'th October


Just like to thank all those who attended the Presentation last Thursday on controlling SharePoint with PowerShell and Extending the Administration Object model.

I know it was pretty fast paced and technical so I plan to follow it up with a series of blogs entries recapping the steps and scripts in greater detail.

Some of the topics covered were:

   Powershell Basics

   Exchange produces PowerShell samples from the new UI console

   Creating a new SharePoint WebApplication and applying a portal template

   Adding users defined in a CSV file to Active Directory

   Adding those users defined in a CSV file to SharePoint roles

   Adding in webs as defined in a CSV file

   Adding content in an XML file to a Publishing Web

   Uploading a directory of files in 4 lines of Script.

   Creating a custom STSAdm command

   Creating an application to sync User Profile properties back to Active Directory

I've attached the PowerShell scripts and PowerPoint Slides.

I'm not able to post the sample code of the AD Sync application as parts of the code is proprietary but I will post a sample application that does a scheduled backup using exactly the same template. (46.78 KB)

Colin Byrne

Flexnet Consultants

SharePoint/Powershell Quickie: Upload a directory of files in 4 lines

A quickie.

Heres 4 lines of code to upload a whole directory of files, in this case pictures, to a SharePoint document or image library.

The directory pictures contains the images.

The destination is the image library SiteCollectionImages for the portal running on port 2828

$wc = new-object System.Net.WebClient
$wc.Credentials = [System.Net.CredentialCache]::DefaultCredentials
function getdestname($filename){ "http://sps:2828/sitecollectionimages/" + $(split-path -leaf $filename)}
dir "pictures" | % { $uploadname=getdestname $_; $wc.UploadFile($uploadname,"PUT", $_.FullName) }

Have I mentioned PowerShell just rocks?

SharePoint/PowerShell 1: Make me a portal

In this PowerShell and SharePoint series I'd thought I'd spin through, in order of use, the commands used to create the demo Portal site in the SUGUK user group presentation.

First step: Creating a Web Application using the API.

The new SPWebApplicationBuilder object makes this easy. This object creates a Web Application using a default port and the default settings, you can override any settings you like in your script but for simplicity I'm just changing the default timezone.

SPWebApplicationBuilder also creates an AppPool to go along with the new IIS Website which has Network Service as the user. In Beta 2TR that account doesn't have the correct permissions so you need to change it to a local administrator. I tend to dev on a Virtual machine DC so I'd use the domain admin.

So we have three routines

   new-SpWebApplication - Create the IIS Website and SharePoint settings

   set-apidentity   - set the Application Pool credentials

   get-defaulttimezoneid   - returns the Greenwich Meantime TimeZone ID (adjust this one to suit)

We also then need to create the set of webs that will live inside the Web Application, this is done by calling the Add Method on the Sites method of the Web Application passing it various parameters the most important of which is the template ID, in this case SPSPORTAL to give us the default SharePoint Intranet portal look.

The Powershell commands to tie all this together are


set-apIdentity "http://sps:yourportnumber" "contoso\administrator" "password"

#Create Portal Site Collection

$webapp.Sites.Add("/", "SUGUK Intranet","SUGUK Intranet",1033, "SPSPORTAL", "contoso\administrator", "administrator", "")

Here's new-SPWebApplication

# Function:         new-SPWebApplication    
# Description:        Create and return a new SPWebApplication object
#             Use the default values which will create the web site at a random port
# Parameters:        none
function new-SPWebApplication()

    # Get our local SPFarm object
    $spfarm = [Microsoft.SharePoint.Administration.SPfarm]::Local

    # Use the new SPWebApplicationBuilder
    $appbuilder= new-object Microsoft.SharePoint.Administration.SPWebApplicationBuilder $spfarm

    # Create Web Application with the default settings
    $webapplication = $appbuilder.Create()

    # Set the timezone to Greenwich Mean Time
    $webapplication.DefaultTimeZone = $timezone.ID

    # Actually queue the application for creation

    # return the SPWebApplication object



# Return the Default TimeZone as used for the majority of our sites
function get-defaulttimezoneid
    [Microsoft.SharePoint.SPregionalSettings]::Globaltimezones | where-object { $_.Description -like "*greenwich*" }


Now to change the Credentials for the AppPool is also really simple in V3. The SPWebApplication object exposes a ApplicationPool property which you can use to set its credentials

# Function:         set-apidentity    
# Description:        Set the credentials for the application pool for the given Web Application
# Parameters:        Url        Site Collection URL
#            UserName     UserName
#            Password     Password
function set-apidentity([string]$SiteCollectionURL, [string]$UserName, [string]$Password)

    $webapp=get-spwebapplication $SiteCollectionURL
    $webapp.ApplicationPool.CurrentIdentityType= [Microsoft.SharePoint.Administration.IdentityType]::SpecificUser
    $webapp.ApplicationPool.UserName= $Username
    $webapp.ApplicationPool.Password= $Password
    # Save the settings

    # Roll the settings out via a Admin Job



To me this is way easier than using the UI.


PowerShell and SharePoint - Oh Yes


I'm about to start off a new series of entries about using Powershell to control SharePoint.  There's a big gap in the ability to script SharePoint between stsadm commands and custom .net programs and PowerShell fills it nicely.

All my entries from now on will focus on SharePoint version 3.

PowerShell is 'DOS for the .NET generation' (c) :-) and its a fantastic way to both interactively control SharePoint via its Object Model from a command line and to create scripts that can be run in a batch. Its currently at version RC2 and is available from here
It installs as a windows update package rather than a separate install as it used to in earlier betas, thats a sign of its being a core element of Windows going forward.

Ok lets do some Powershell SharePoint basics.

First although Powershell can call any .net class the assembly must be loaded first.
By default Powershell loads a small list of assemblies, this command will get the list of loaded assemblies:


The syntax for calling a .NET class's static method is for the brackets go around the Class name and the double colon between the class and the static method

The output from that is a little hard to read lets just list the files involved

[AppDomain]::CurrentDomain.GetAssemblies() | foreach-object { split-path $_.Location -leaf } | sort

Here's the list of files the above command gives on my machine


As you can see SharePoint is not one of those in the list, also missing that could be useful is the System.Web assembly

There are a few ways to load an assembly onto your AppDomain but the easiest is to call the static method LoadWithPartialName on the Assembly class.


LoadWithPartialName is great because you dont need to specify the full name to the assembly which in SharePoint v3 would be

[System.Reflection.Assembly]::Load("Microsoft.SharePoint, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c")

and for MOSS

[System.Reflection.Assembly]::Load("Microsoft.SharePoint.Portal, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c")

Now a lot of people will cry LoadWithPartialName has been deprecated as MS have got concerned how it has to make to many guesses over locating the assembly.
Personally I want to see a method that will simply load the latest version of the assembly I've told it to load, in a controlled environment like a SharePoint server thats exactly the behaviour I want to see. <rant> MS for god's sake just document the method properly and let devs choose whether to use it or not. </rant>

Anyway if you want to use the Load method take a look at this blog entry:

Now you don't want to type the load commands each time so put them in your Powershell Profile script.
This changes location a lot depending on which version of Powershell your running so see this entry for the full details

So now what can we do with this?

Well first lets get a site collection we can play with

First create an SPSite object and pass it a valid site url

      $spsite= Microsoft.SharePoint.SPSite("")

to see the contents of the object just type the object on the command line


To just get a list of the methods on the SPSite object

   $spsite | get-member -membertype method

To just get a list of the properties on the SPSite object

   $spsite | get-member -membertype property

To get a list of all sub sites


Get a list of webs ordered by the last time that the contents have been changed

   $spsite.allwebs | select LastItemModifiedDate, URL , Created | sort LastItemModifiedDate

There's lots more that you can do and I'll post them as I go.


Presenting at the SUGUK Meeting 26th October

Whoa, its been a while since I've blogged but sundry projects and SharePoint v3 has taken up all my time.

Just to let you know that I'm presenting at the UK SharePoint users group meeting this Thursday the 26th October.

I'm doing 2 sessions; one on using Powershell with SharePoint v3 in which I'll go through Powershell basics and how to use it to control SharePoint. Then I will attempt to build a portal without touching any settings in the UI! Wish me luck.

The second one will explore the new extensible admin object model.
This will demonstrate creating custom stsadm commands along with creating an application that syncs changed MOSS User profile information back to Active Directory.
It will be a small application integrated into SharePoint and built using the new SPService, SPServiceInstance and SPJobDefinition classes.
I'll be describing how they work together, its cool stuff.

Everybody is welcome (you just need to register on the suguk site) so if you are in London this Thursday it would be great to see you.  The meeting kicks off at 6.30pm

If you plan to attend just register on the SUGUK site and leave your name on this list


New Free Web Part: Flash Dynamic PhotoGrid

Flexnet Consultants have just released a brand new free Web Part.

The PhotoGrid WebPart will show a nXn grid of Picture Library images with a each image randomly chosen to be enlarged. This is similar to the Flikr Photobadge.

You can set the number of pictures on each row and the number of rows along with the time the enlarged picture is displayed (Display time).

Our Web Parts page uses a Flash embedded demo to show you how it would look.

Flash Slideshow Web Part Version 1.2 released

Version 1.2 of our free Flash Slideshow Web Part is released.

The Slideshow Web Part will show a rotating display of all the pictures in the Picture Library with an adjustable fade transition between each picture.

This version has better support for SharePoint sites running on non standard http ports.

It now also supports all the image formats that the Picture Library does.

Client Side: Who am I?

Sometimes when working in client-side javascript you'd like to know your Windows username for instance to add to the root Outlook Web Access URL for say a contacts search i.e. http://flexnetowa/exchange/colinb/contacts/?cmd=search 

Now the stock answer whenever this comes up in the SharePoint newsgroups is: it can't be done, use server side code to render it out.

Thats fair enough and easy to do, I've created a WebPart that stores a users details as a JavaScript object so it can be referenced in code. But what if I don't want to install yet another server-side Web Part.

In the interests of providing code you won't get anywhere else here's the tip.

Now its true the SharePoint Web Services provide no method to tell you who you are (side-note: I suspect you may be able to do this by creating a CAML query against the userinfo table but I've not managed to get that working) but you can get your username by using the FrontPage RPC and calling author.dll, this is how Word displays who you are on its TaskPane when you open a Word document in a document library.

When you call the author.dll ISAPI DLL with the 'open service' method name it returns a host of information about the server and the services it provides.

I'm using the XmlHttpRequest object again which despite the name can also be used to retrieve a text document not just an XML one.

heres the returned information

<html><head><title>vermeer RPC packet</title></head>
<p>method=open service:
<li>VX|windows-1257 big5 windows-1252 windows-874 utf-8 windows-1251 windows-1256 euc-kr gb2312 windows-1253 windows-1258 koi8-r iso-8859-1 gb18030 iso-2022-jp ks_c_5601-1987 windows-1250 windows-1255 us-ascii euc-jp unicode unicodeFFFE windows-1254 iso-8859-2 iso-8859-15 shift_jis
<li>SX|Microsoft.SharePoint, Version&#61;, Culture&#61;neutral, PublicKeyToken&#61;71e9bce111e9429c
<li>VR|Approved Denied Pending&#92; Review
<li>VX|default.htm default.aspx
<li>VR|Business Competition Expense&#92; Report Goals/Objectives Ideas In&#92; Process Miscellaneous Planning Schedule Travel VIP Waiting
<li>VX|vti_RulesScript vti_ServerIndexServer vti_TimedDocEvents vti_ServiceMarkUrlDirExec vti_DocSaveToDB vti_ServiceMarkUrlDirBrowse vti_ACAll vti_ServerODBC vti_ServerASP vti_ServiceMarkUrlDirScript
<li>SX|&#60;STS-based Locking&#62;


Notice my windows username is listed against the vti_username item.

Using the XmlHttpRequest object to call author.dll synchronously (we're going to wait for the call to return)

xmlrequest = "method=open service:";

if (!xmlhttp) xmlhttp=GetHTTPObject();"POST", "/_vti_bin/_vti_aut/author.dll ",false);


The responseText property on xmlhttp contains the returned document.

The hardest bit is parsing the result to extract the username.

Once that is done I show the username in a DIV element.

So the next time someone asks this question we'll be able to give them some options.

ClientSideUsername.dwp (2.92 KB)