Posts Tagged ‘PowerShell’

Scripting SharePoint Learning Kit Permissions with PowerShell

March 8th, 2012 Richard No comments

If you are using SLK with more than a few sights then provisioning the permissions becomes either very time consuming or impossible by hand. A typical UK secondary school will have between 700 to 1500 distinct classes, and to use SLK to its fullest extent then each of these will need a site with unique permissions. So once you have finished any trial/prototype you will need to script the setting up of SLK Permissions.

The following is a simple proof of concept script to initially set the SLK permissions on a site. It will add permissions for specified Active Directory users or groups to specified existing sites in SharePoint. You could easily extend it to create sites by checking to see if the site exists first, and if not running New-SPWeb.

The script runs from an input csv in the following format:

http://laptop01/sites/slk/class1,demo\learner1,SLK Learner
http://laptop01/sites/slk/class1,demo\learner2,SLK Learner
http://laptop01/sites/slk/class1,demo\teacher,SLK Instructor
http://laptop01/sites/slk/class2,demo\teacher,SLK Instructor

For each line in the input file it adds the user to the given site, with the given permission level.

To use save the following PowerShell as a ps1 file, create an input csv file called sitePermissions.csv in the same directory and run the script.

Add-PSSnapIn Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue

function AddPermission($web, $userName, $permission){    # Break inheritance if required. Argument is true if copy existing permissions or false to strip all    # permissions    if ($web.HasUniqueRoleAssignments -eq $false)    {        $web.BreakRoleInheritance($true)    }

    $user = $web.EnsureUser($userName)    $roleAssignment = New-Object Microsoft.SharePoint.SPRoleAssignment($user)    $role = $web.RoleDefinitions[$permission]    $roleAssignment.RoleDefinitionBindings.Add($role);    $web.RoleAssignments.Add($roleAssignment)}

$csvData = import-csv sitePermissions.csvforeach ($line in $csvData){    $web = Get-SPWeb $line.Site    AddPermission $web $line.User $line.Role    $web.Dispose()}

Running this with the sample data above gives the following before and after screenshots on the permissions:


Notes on the script:

  1. There is no error handling so if your input in incorrect e.g. typos in your site, user name or roles, you will get screens of red error messages.
  2. Line 1, Add-PSSnapIn ensures that the PowerShell comandlets are added into the current session if not already present.
  3. The actual adding of the permissions is put into a function to break up the script and improve readability and maintainability.
  4. Permissions can only be added to sites which have unique permissions, so if the site doesn’t already have permissions it breaks them and can either copy the existing conditions, or start from none depending on the value of the argument passed to BreakRoleInheritance.
  5. EnsureUser is used to make sure that the user is added to SharePoint before trying to give them permissions
  6. To change the name of the input file, just change sitePermissions.csv in the script.
  7. It’s not particularly optimised as it opens a new SPWeb for every line. You could check to see if it’s a different site on each line and only dispose and create a new one if it is different.
  8. The script will still work if the user’s permission already exists.

This is a simple script suitable for initial setting of SLK permissions. It doesn’t attempt to remove any permissions if no longer required, or do anything else to the site apart from breaking inheritance.

For a more comprehensive solution which can completely provision a set of sites, including setting any setting on a site, adding and removing permissions and automatically adding teachers’ sites to their list when assigning permissions, as well as a multitude of other functionality, then please investigate our managed service Salamander SharePoint. This will do all this and more.

Categories: PowerShell, SLK Tags: ,

Error "Admin SVC must be running in order to create deployment timer job"

March 11th, 2011 Richard 7 comments

When running Update-SPSolution you can sometimes get the error:

Admin SVC must be running in order to create deployment timer job


There’s a very simple solution to this. Ensure that the SharePoint 2010 Administration service is started.


Once you have started that the command will run correctly.

Categories: SharePoint Tags: ,

Removing the "Use a Meeting Workspace" Option from All Existing and New SharePoint Calendars in a Site Collection

March 4th, 2011 Richard 8 comments

Having removed the "Use a Meeting Workspace" option from individual calendars in my previous post, I wondered if there was a way to remove them from all existing and new calendars within a site collection.

I found a way to do it by modifying the calendar schema in the hive folder. However, although this works, it technically leaves SharePoint in an unsupported state, so I didn’t want to go down that route.

Then I had a thought that all the items in a calendar list are of the Event content type, so if you can modify that, to make the Workspace option hidden, then it would be removed from all calendars.

Unfortunately when you look at the Event Content Type in the Site Content Types gallery, the Workspace column is greyed out so you can’t edit it.


However, it proved to be remarkably easy to script using PowerShell:

# Script to remove Use a Meeting Workspace from all calendars
$siteUrl = "http://myserver/sites/mysite"
[system.reflection.assembly]::LoadWithPartialName("Microsoft.Sharepoint") > $null
$site = New-Object Microsoft.SharePoint.SPSite($siteUrl)

$contentTypeId = [Microsoft.SharePoint.SPBuiltInContentTypeId]::Event
$eventContentType = $site.RootWeb.ContentTypes[$contentTypeId]

$fieldId = [Microsoft.SharePoint.SPBuiltInFieldId]::WorkspaceLink
$field = $eventContentType.FieldLinks[$fieldId]

$field.Hidden = $true

# Dispose the site object
if ($site) {$site.Dispose()}

The only slightly tricky bit was needing to use the FieldLinks property instead of Fields.

The $eventContentType.Update($true); line ensures that it updates all existing calendars in the site collection, otherwise it will just be for new ones.

I’ve actually increased the script by 2 lines to fit it in my blog by adding in the $fieldId and $contentTypeId. Originally it was even more compact.

Again, this takes effect immediately throughout the entire site collection with no need for an iisreset or an application pool recycle.

Using PowerShell to Remove the "Use a Meeting Workspace" Option from SharePoint Calendars

March 4th, 2011 Richard 9 comments

I’ve just deployed a custom meeting site to a customer to handle multiple meetings within one site. Hence the option to “Use a Meeting Workspace” when creating a new or updating a calendar item is unnecessary, so they asked me to remove it to prevent anyone using it by mistake.

When creating a calendar item (or updating) this is the dialog you get, with the Use a Meeting Workspace highlighted.


From SharePoint Blues I discovered that if you set the calendar list field to hidden then this option would no longer display. Taking this concept, I created a PowerShell script to set this to hidden on a one off basis.

The script is:

# Script to remove Use a Meeting Workspace from a specific calendar

function RemoveWorkspaceLink ([String]$siteUrl, [String]$calendarName)
[system.reflection.assembly]::LoadWithPartialName(“Microsoft.Sharepoint”) > $null
$site = New-Object Microsoft.SharePoint.SPSite($siteUrl)
if ($site -eq $null)

$web = $site.OpenWeb()
$list = $web.Lists[$calendarName]
if ($list -eq $null)
“Invalid list name ” + $calendarName
$field = $list.Fields[[Microsoft.SharePoint.SPBuiltInFieldId]::WorkspaceLink]
$field.Hidden = $true
“Updated ” + $calendarName + ” on ” + $siteUrl

# Dispose of the SharePoint objects
if ($web) {$web.Dispose()}
if ($site) {$site.Dispose()}

RemoveWorkspaceLink “http://myserver/sites/site1″ “Calendar1″
RemoveWorkspaceLink “http://myserver/sites/site2″ “Calendar2″

I’ve written this as a function so that you can update multiple calendars at the time. If you saved this as a .ps1 file and then run it, the 2 calendars referenced at the bottom would be updated. Alternatively you could . source the file and use the function interactively, or just hard code the $siteUrl and $calendarName variables each time you run it.

The option is removed immediately you have run the script with no iisreset or application pool recycle required.

So with the script is run this is what you see with the Meeting Workspace option removed:


This works well for hiding it on individual calendar lists, but doesn’t affect any other existing calendars or ones created afterwards.

I’ve since found a way to update all calendars in a site collection.

Bulk Loading Photos From Sims Into SharePoint

January 6th, 2011 Richard No comments

I now have a way to script bulk loading of photos from Sims into SharePoint, for example to enable the use of the Learning Gateway My Children web part.

The script is in 2 parts. First extract the photos from Sims using our free Photo Export tool

PhotoExport.exe simsuser simspassword outputFolder /names:mapping.csv

where mapping.csv is a csv file mapping admission numbers to Active Directory login names

The use the PowerShell script in my last blog entry Using PowerShell to Bulk Upload Files to SharePoint to upload the images to SharePoint.

You could even set up a scheduled task to automatically upload them on a predefined schedule.

Using PowerShell to Bulk Upload Files to SharePoint

January 6th, 2011 Richard 14 comments

While building a school’s Learning Gateway I needed to bulk upload all their student images into a picture library so that the My Children web part could display them. Since there were several hundred of them I wrote a little PowerShell script to perform this.

$siteUrl = "http://sharepoint/schools/test"
$listName = "Students Picture Library"

$site = New-Object Microsoft.SharePoint.SPSite($siteUrl)
$web = $site.OpenWeb()
$list = $web.Lists[$listName]
$fileCollection = $list.RootFolder.Files

$files = get-childItem -Exclude *.ps1

foreach ($file in $files)
    $stream = $file.OpenRead()
    $uploaded = $fileCollection.Add($file.Name, $stream, $TRUE)
    "Uploaded " + $file.Name

    if ($stream) {$stream.Dispose()}

if ($web) {$web.Dispose()}
if ($site) {$site.Dispose()}

In order to use this:

  1. Save as as .ps1 file in the same folder as the files to upload.
  2. Change the site url and name of the list at the beginning of the script to your values
  3. Make sure that only the files to upload and the ps1 file is in the folder
  4. Open PowerShell using Run As Administrator
  5. Navigate to the folder
  6. Run the .ps1 file

The script will then iterate through all files in the current folder and upload them to the given list, overwriting them if they already exist.

How To Stop Home Folders Being Renamed Documents in the Network Share

September 24th, 2010 Richard 29 comments

I’ve recently had a number of queries about why everyone’s home folders have been renamed to Documents in the network share they reside in.


This obviously makes finding a particular users home folder difficult, especially in schools where administrators and teachers regularly look in the home folders.

This is a feature of Windows Vista, Windows 7 & Server 2008. A desktop.ini file is created when the user first accesses their home folder to give it a friendly display name of Documents and a custom icon. This is to make it look pretty and stand out when viewed under your profile in Windows Explorer.

However, the side effect is as above. Whenever anyone else views the folder, and this will normally be in the context of the network location it is stored, their Explorer will also read the desktop.ini file to get display information and give the impression that there are multiple folders called Documents.

As it’s only the display name which is changed you can still navigate into the folder by typing in the name in the address bar, which will auto-complete properly, but it’s not ideal.

The desktop.ini file is a hidden system file so you won’t see it unless you have your setting set up to view system files so unless you know what’s happening it can seem very mysterious.

Microsoft have a knowledge base article about this at

In it, it suggests 3 options for stopping this behaviour.

1.    Put the home folder in a wrapper folder which is called the user’s username, but point the Active Directory attribute to the folder within it.

2.    Give the user exclusive rights to the folder.

3.    Deny read permission to the desktop.ini file in the home folder to other users. Then they won’t be able to read the display information and the name won’t change.

In a school environment, where there are legitimate reasons for other users to go into the students’ home folders option, 2 isn’t an option. Both 1 & 3 work nicely, but 3 seems cleaner to me as it doesn’t require any extra folders creating just to get round a display issue.

I’ve knocked up a quick PowerShell script to automate setting the permissions on the desktop.ini files. Note the groupName below should be changed to the name of an Active Directory group you want to be able to view the real folder names. Be careful that this group doesn’t include any back up process opoerators or backups could fail.

$folders = Get-ChildItem | where-object {$_.psiscontainer};

foreach ($folder in $folders)
    $ErrorActionPreference = "SilentlyContinue"
    $desktopIni = Get-ChildItem $folder -Filter desktop.ini -Force

    if ($desktopIni -ne $null)
         $Acl = (Get-Item $desktopIni.FullName -Force).GetAccessControl("Access")
         $Ar = New-Object `
         Set-Acl $desktopIni.FullName $Acl

All you need to do is save this script as a .ps1 file in the directory containing your home folders. If they are split for example along intake years, you’ll need to do this in each containing folder. So in the example above, you would save in \\fileserver\Intake2008. Then change groupName to the name of an Active Directory group containing the users you want to see the real names. Open up PowerShell and navigate to the directory containing the script file and then run it.

If you haven’t run PowerShell scripts before you’ll need to set the execution policy to allow it, I normally use RemoteSigned. Run

help set-executionpolicy


help about_execution_policies

in your PowerShell prompt for more information.

Update 05 April 2011

Removed the use of Get-Acl as Set-Acl then tries to set the owner. Talked about back up operators. Thanks to Jay Hutter for both of those.
Update 16 September 2011

Added $ErrorActionPreference = “SilentlyContinue” at the start. Otherwise an error is thrown when re-running as you don’t have access to the desktop.ini files you modified last time.