Archive for the 'powershell' Category

SharePoint Powershell Move-SPSite error: Invalid object name

Attempting to move a SharePoint site using Powershell cmdlet Move-SPSite and getting the following error:

Invalid object name ‘WSS_Content.dbo.AllSites’.

This error occurs because the database schema between the source database and the target database is different.  In my case, the source database was hosted on SQL Server 2008 R2, and the destination database was on SQL Server 2012 SP3.  I solved the problem as follows:

  1. Create a new content database on the source SQL Server.
  2. Use Move-SPSite cmdlet to move your SharePoint site into the new DB.
  3. Using SQL Server Management Studio, back up the new content DB to a file and copy it to the destination SQL Server.
  4. Restore the database on the destination SQL Server.Move-SPSite

How to export and import lists and libraries from a SharePoint 2010 site using Powershell

Let’s imagine this scenario:

You have an old SharePoint 2010 site and you need to copy its content to another SharePoint farm.  The site is heavily customized and moving it using traditional methods (backup/restore, export/import, save site as a template) are not going to work well.  Plus you only want content – no need to bring in all of that custom branding baggage.

You can copy the content using PowerShell and two scripts shown below.

Script # 1:   Export all lists and libraries from the source site.


add-pssnapin microsoft.sharepoint.powershell

# specify the site URL to export

$web = Get-SPWeb "http://sharepointURL/sites/site1/web1"

# specify output folder to store exported lists

$path = "c:\admin\export\"

foreach($list in $web.lists)

{

"Exporting " + $list.RootFolder.URL

export-spweb $web.URL -ItemUrl $list.RootFolder.URL -IncludeUserSecurity -IncludeVersions All -path ($path + $list + ".cmp") -nologfile

}

The output of this script should be a number of CMP files in the output directory.  Review these files and remove the lists that should not be imported (such as various Gallery lists).

Script # 2:  Import CMP files into the destination site.


add-pssnapin microsoft.sharepoint.powershell

# specify target SharePoint site to import into

$site = "http://sharepoint/sites/test1"

# specify folder containing exported lists

$folder = "C:\Admin\Import\"

$Files = Get-ChildItem $folder

foreach ($file in $files)
{

$name = $file.Name

"Importing: " + "$folder$name"

import-spweb $site -path ("$folder$name") -includeusersecurity -nologfile

}

PowerShell script to monitor server disk space and send out email alerts

When you’re managing a large SharePoint installation, storage issues are going to be a major concern.   Whether it’s ULS logs, IIS logs,  SQL databases and transaction logs – whatever it is, when left to its own devices, SharePoint can consume a lot of space very quickly, and before you know it, your disks will be running out of space.

I found a cool PowerShell script by Colin Smith called Disk Space Monitor (see it here:  http://powershell.com/cs/media/p/1617.aspx).  For whatever reasons, I had problems getting the email component to work properly, and I also wanted to tweak the email message format.   One thing led to another, and I ended up re-writing a few other sections of Colin’s script to better suit my needs.  The final product appears below  – it reads a list of servers, checks the free space on each server, and sends out an email summary to a list of users you specify. 

How to use this script:

Step 1.  Create a simple text file with a list of your servers to audit, single column, single-spaced, like this:

server1

server2

server3

server4

Let’s call the list “list.txt”.  Save the file.

Step 2. Create a batch file (let’s call it “start.bat”) and enter the following code in it.  Make sure to enter your own path for the server list as well as the output log file.


REM  Usage:  powershell %~dp0DiskSpaceMonitor.ps1  <computer list file path>   <output log path>
powershell  %~dp0DiskSpaceMonitor.ps1 C:\Scripts\DiskSpaceMonitor\list.txt   C:\Scripts\DiskSpaceMonitor\output.txt

 

Step 3. Create a PowerShell script file in the same directory as “start.bat”,  let’s call it “DiskSpaceMonitor.ps1”, and enter the following code in it.  Make sure to specify your own list of users to email and your SMTP server name or IP address.  Save the file, and execute “start.bat”.

# This script performs the following actions:

#  1) Read a list of servers
#
#  2) For each server on the list, get disk drive information - drive letter, drive size, free space, percent free
#
#  3) Email the report to users specified by the $users variable
#
$users = "user1 @ domain.com", "user2 @ domain.com " , "user3 @ domain.com"

$server = "SMTP server name or IP address"

$port = 25

$list = $args[0]

$output = $args[1]

$computers = get-content $list

echo "SharePoint Storage Report" > $output
echo " " >> $output
echo "Note: Free space below 30% is labeled with *** " >> $output
echo " " >> $output
echo " " >> $output
echo "ServerName    Drive Letter Drive Size Free Space Percent Free" >> $output
echo "----------    ------------ ---------- ---------- ------------" >> $output
foreach ($line in $computers)
{
 $computer = $line 
 
 $drives = Get-WmiObject -ComputerName $computer Win32_LogicalDisk | Where-Object {$_.DriveType -eq 3}
 foreach($drive in $drives)
 {

 $id = $drive.DeviceID
 $size = [math]::round($drive.Size / 1073741824, 2)
 $free = [math]::round($drive.FreeSpace  / 1073741824, 2)
 $pct = [math]::round($free / $size, 2) * 100
 
 if ($pct -lt 30) { $pct = $pct.ToString() + "% *** " }

 else {  $pct = $pct.ToString() + " %" }

echo "$computer   $id  $size  $free  $pct"  >> $output

$pct = 0 

 }

}
foreach ($user in $users)
{

$to      = $user

$from    = "<a href="mailto:diskspacemonitor@domain.com">diskspacemonitor@domain.com</a>"

$subject = "Connect Storage Report"

foreach ($line in Get-Content $output)

{

$body += “$line `n”

}

# Create mail message

$message = New-Object system.net.mail.MailMessage $from, $to, $subject, $body

#Create SMTP client

$client = New-Object system.Net.Mail.SmtpClient $server, $port

# Credentials are necessary if the server requires the client # to authenticate before it will send e-mail on the client's behalf.

$client.Credentials = [system.Net.CredentialCache]::DefaultNetworkCredentials

# Try to send the message

try {      

$client.Send($message)      

"Message sent successfully"

# reset variables

$body = ""

}

# Catch an error

catch {

"Exception caught in CreateTestMessage1(): "

}

}

# End of Script

 

How to enumerate user profiles and their properties in SharePoint 2010 using PowerShell

When administering a large SharePoint 2010 deployment, there are times when you may need to take an inventory of the user profiles in your profile store – perhaps to find users with a common property or characteristic, run some comparisons of your SharePoint profiles to Active Directory, or do some other administrative task.

Here’s a simple PowerShell script that enumerates all user profiles in the context of your SharePoint site and emits some of their properties, such as Display Name, AccountName, and workEmail.

Note:  The account which will be executing this script needs to have Full Control access to the User Profile Service application.   Follow these two steps:

1) Go to  Central Administration > Manage service applications > select (highlight) your user profile application > click on Administrators button on the ribbon and add your account.

2) Go to  Central Administration > Manage service applications > select (highlight) your user profile application > click on Permissions button on the ribbon and add your account with Full Control – make sure to check the “Full Control” checkbox!


[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server.UserProfiles")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
# Enter your SharePoint site URL here...
$site = new-object Microsoft.SharePoint.SPSite("http://...");

$ServiceContext = [Microsoft.SharePoint.SPServiceContext]::GetContext($site);

$ProfileManager = new-object Microsoft.Office.Server.UserProfiles.UserProfileManager($ServiceContext)

$AllProfiles = $ProfileManager.GetEnumerator()

write-host "Display Name ;  AccountName ; Email ; "

foreach($profile in $AllProfiles)
{

$DisplayName = $profile.DisplayName

$AccountName = $profile[[Microsoft.Office.Server.UserProfiles.PropertyConstants]::AccountName].Value

$workEmail = $profile[[Microsoft.Office.Server.UserProfiles.PropertyConstants]::workEmail].Value

write-host $DisplayName, ";", $AccountName, ";" , $workEmail, ";"

}
write-host "Finished."

$site.Dispose()

A full list of SP 2010 user profile properties is available on MSDN here:

http://msdn.microsoft.com/en-us/library/microsoft.office.server.userprofiles.propertyconstants_members.aspx

Locating files and pages with URLs that are too long for SharePoint

As you may already know, SharePoint has a limitation on how long a page or file path (or URL) can be.  This was an issue with SharePoint 2007 -Joel Oleson blogged about it back in June 2007:

“When storing files the structure and files (entire path including sites, folders, and file name) cannot add up to more than 260 characters or they will see an error message or form validation error with the explanation around the URL length. “ 

Official Microsoft documentation states that the same limit holds for SharePoint 2010:

“SPSite.MaxFullUrlLength Field

Represents the maximum number of characters that can be used in the absolute URL for a site collection.

Remarks
——————————————————————————–

The value of this constant is 260.

The MaxFullUrlLength field is static and cannot be called on an instance object. To call this field, use SPSite.MaxFullUrlLength.”

Source:

http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spsite.maxfullurllength.aspx)

When you’re moving, upgrading, or migrating SharePoint sites, you may run into problems with URLs that are too long for SharePoint.  You may see failures or errors when executing STSADM commands such as “stsadm -o export” or “stsadm -o import”.

I wrote a PowerShell script (see below) that allows you to take an inventory of all files in your web application and flag those files where the path (or URL) is longer than 260 characters.

You can call this script from a command line as follows:


powershell   C:\Inventory.ps1  "http://sharepointURL" >   C:\output.txt

 

Source code


 # This script enumerates all files at the specified URL,
 # and outputs full URL for each file,
 # along with the length of the URL.

# define EnumPages function

function EnumPages
{
param ($URL, $objFolder)

 # enumerate files in the root folder

 foreach ($file in $objFolder.Files)
 {

 $result = "OK"
 $output = $URL + "/" + $objFolder.URL + "/" + $file.Name

# evaluate string length
 if ($output.length -ge 260) { $result = "TOO LONG" }

# write output

 write-host $output, ";" , $output.length, ";" $result, ";"
 }
 # enumerate subfolders

 foreach ($subfolder in $objFolder.SubFolders)
 {

 EnumPages $URL $subfolder
 }

 }

 # begin script body
[System.Reflection.Assembly]::Load("Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c") | out-null

 $siteURL = $args[0]

# create a new SPSite object

$site=new-object Microsoft.SharePoint.SPSite($siteURL)

 # enumerate files in the Rootweb

 foreach ($file in $site.Rootweb.Files)
 {

$result = "OK"

 $output = $site.Rootweb.URL + "/" + $file.Name 

 if ($output.length -ge 260) { $result = "TOO LONG" }

  write-host $output, ";", $output.length, ";" , $result

 }

 # enumerate folders in the Rootweb

 foreach ($folder in $site.Rootweb.Folders)
 {

 EnumPages $site.Rootweb.URL $folder

 }

 # enumerate subsites

 foreach ($web in $site.Allwebs)
 {

  # enumerate files in the root web

  foreach ($file in $web.Files)
  {

$result = "OK"

$output = $web.URL + "/" + $file.Name 

 if ($output.length -ge 260) { $result = "TOO LONG" }

 write-host $output, ";", $output.length, ";" , $result

  }

  # enumerate folders

  foreach ($folder in $web.Folders)
  {

  EnumPages $web.URL $folder

  }

   }

$site.Dispose(); ##ENFORCED DISPOSAL!!!    

 


Create and delete SharePoint list views with PowerShell

Here’s how you can create and delete views in a SharePoint list or library using PowerShell (Is there anything that can’t be done through a PowerShell script?)

The script below creates a view called “TestView”.  It expects three command-line arguments:  site collection URL, the name of the view to create, and the list GUID.  The view that’s created is an exact replica of the “All Items” view (you can certainly modify the code as needed).  Here’s how you would call this script from the command line:


powershell  CreateView.ps1 "your_site_collection_URL" "TestView" "List GUID 6865306f-60e0-4889-addd-4fb9862e72e0"

Script code (use the button in the top right corner to copy it to the clipboard):


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

# reading command line arguments

$siteURL = $args[0]

$strViewName = $args[1]

$ListGUID = $args[2]

# enter your CAML query for the view here...

$strQuery = "<Where><Gt><FieldRef Name='ID'/><Value Type='Counter'>0</Value></Gt></Where>"

 # create a new SPsite object and recursively go through all webs

# until a matching list GUID is found

$site=new-object Microsoft.SharePoint.SPSite($siteURL)

foreach ($web in $site.AllWebs)
{
 

foreach ($list in $web.Lists)
{

$ListTempGUID = $list.ID.ToString()
  

if ($ListTempGUID.Contains($ListGUID))
{

write-host "**********************************************"
write-host "Match found. Preparing to create a view: ", $strViewName
write-host "List Title: ", $list.Title
write-host "List GUID: ", $list.ID

$fields = $list.Views["All Items"].ViewFields.ToStringCollection()

$result = $list.Views.Add($strViewName, $fields, $strQuery, 100, $True, $False , "HTML", $False)

write-host "View ", $strViewName , " was created successfully."

break

}
}

} 

write-host "Done."

$site.Dispose(); ##ENFORCED DISPOSAL!!!

    

So far, so good?  Well, now that you’ve created a view, how do you delete it?  Follow the same logic, only instead of using the Add method of SPViewCollection object, we’ll be using the Delete method.

Same command line arguments as before:  site collection URL, name of the view, and list GUID.

Calling script from the command line:


powershell  DeleteView.ps1 "your_site_collection_URL" "TestView" "List GUID 6865346f-60e0-4889-addd-4fb3862572e0"

 


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

# reading command line arguments...

$siteURL = $args[0]

$strViewName = $args[1]

$ListGUID = $args[2] 
# creating a new site object and recursively searching through its lists

# until a matching list GUID is found

$site=new-object Microsoft.SharePoint.SPSite($siteURL)

foreach ($web in $site.AllWebs)
{
 

foreach ($list in $web.Lists)
{

$ListTempGUID = $list.ID.ToString()
  

if ($ListTempGUID.Contains($ListGUID))
{
foreach ($view in $list.Views)
{

If ( $view.Title.Contains($strViewName))
{

write-host "**********************************************"
write-host "Match found. Preparing to DELETE a view: ", $view.Title
write-host "List Title: ", $list.Title
write-host "List GUID: ", $list.ID

# you can insert a pause here if you like...

$list.Views.Delete($view.ID)

write-host "View ", $view.Title , " has been deleted successfully."

break

}
}

break

}

}

}
write-host "Done."

$site.Dispose(); ##ENFORCED DISPOSAL!!! 
 

Finally,  how do you find out the GUID of your list?  It’s fairly straightforward – you just need to access the SPList.ID property of your list.  Here’s a simple script that will output the GUIDs of all lists in your site collection:


[System.Reflection.Assembly]::Load("Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c") | out-null
# write column headings

write-host "List URL ; Web URL ; Web Title ; List Title; List GUID ;"

# create a site object and recursively list all of its list objects and their details
 $site=new-object Microsoft.SharePoint.SPSite("http://your_site_collection_URL)  

  foreach ($web in $site.AllWebs)
 {
  foreach ($list in $web.Lists)
 {
 write-host $list.DefaultViewURL, ";", $web.URL , ";",  $web.Title , ";" , $list.Title , ";" , $list.ID

 }

 }

$site.Dispose(); ##ENFORCED DISPOSAL!!!

Testing access to SharePoint pages

Let’s say you have a long list of SharePoint pages that need to be tested to verify that they’re permissioned correctly.  One way to do it is to take a non-privileged account (end user) and attempt to connect to each of the URLs.  If the page is locked down, you’ll get a page titled “Access denied”; otherwise, the page will load normally.

I recently responded to a thread on SharePoint TechNet about a similar issue and ended up writing a PowerShell script to address it.

The script below will read a text file containing a list of URLs (make sure to modify the source file path with your own path), and then call a function for each URL.  This function will open a new instance of IE, navigate to the URL, wait for the page to load, and then grab the title of the page.  If the user doesn’t have access to the page, the page title will contain “Access denied”; otherwise, the page title will be returned.  Run this script under the credentials of one of your end users.  If you’re trying to open individual documents (Word, Excel, etc.), you may need to modify the script so that it launches correct application (and closes it when done).


# This script will read a text file containing a list of URLs and attempt to connect to each URL.  Successful connection will return the page's title; otherwise, the script will return Access denied error.

# OpenIE function starts here...
# This function launches a new instance of IE and then navigates to the specified URL

function OpenIE($url)
{

if ($url -notlike "http://*")
{

$url = "http://" + $url

}
$ie = new-object -com "InternetExplorer.Application"

$ie.Visible = $true

$ie.Navigate($url)

# wait for IE to load the page

While( $ie.Busy )
{
[System.Threading.Thread]::Sleep(100)
}

# grab page title - if access is denied, the page title will say so

$Title = $ie.Document.Title

$ie.Quit()

return $Title

}

 

# *** Main script routine starts here ***
# specify your source file path here...

$SourceFilePath = "C:\Shared\list.txt"

write-host "Starting script..."

# read the source file into an array of strings, iterate through each one

$list = Get-Content $SourceFilePath

foreach ($item in $list)
{

$result = OpenIE($item)

write-host $item, ";" , $result

}

write-host "Finished."


RSS Information Week Headlines

  • An error has occurred; the feed is probably down. Try again later.

RSS SharePoint Team Blog

  • An error has occurred; the feed is probably down. Try again later.

RSS InfoPath Team Blog

  • An error has occurred; the feed is probably down. Try again later.

RSS Joel Oleson Blog

  • An error has occurred; the feed is probably down. Try again later.

RSS Susan Hanley’s KM Blog

  • An error has occurred; the feed is probably down. Try again later.

Blog Stats

  • 344,936 hits