HowTo: Copy discussions to a new discussion board

Scenario:
You want to copy all discussions from a discussion board to another

PowerShell script:

#Copy discussions to a new discussion board

$web = Get-SPWeb "http://sharepoint.com"
$sourceList = $web.GetList("http://sharepoint.com/Lists/OldDiscussions/AllItems.aspx")
$destinationList = $web.GetList("http://sharepoint.com/Lists/NewDiscussions/AllItems.aspx")

$sourceListItems = $sourceList.Folders

foreach($item in $sourceListItems)
{
 $title = $item['Title']
 write-host "Copying $title"
 #Get desired discussion by ID
 $sourceDiscussion = $sourceList.Folders | Where-Object {$_.ID -eq $item['ID']}

 #Add new discussion to destination list
 $destinationDiscussion = [Microsoft.SharePoint.Utilities.SPUtility]::CreateNewDiscussion($destinationList.Items, $sourceDiscussion.Title)

 #Copy field values
 $destinationDiscussion["Body"] = $sourceDiscussion["Body"]
 $destinationDiscussion["Author"] = $sourceDiscussion["Author"]
 $destinationDiscussion["Editor"] = $sourceDiscussion["Editor"]
 $destinationDiscussion["Modified"] = $sourceDiscussion["Modified"]
 $destinationDiscussion["Created"] = $sourceDiscussion["Created"]
 
 #Copy attachments
 $attachmentCollection = $sourceDiscussion.Attachments
 $folder = $web.GetFolder($attachmentCollection.UrlPrefix);
 foreach ($file in $folder.Files) {
  $fileName = $file.Name
  $bytes = $file.OpenBinary() 
  $filePath = "$webURL/$folder/$fileName"
  $destinationDiscussion.Attachments.Add([System.IO.Path]::GetFileName($filePath), $bytes);
 }  
 
 #Add discussion
 $destinationDiscussion.SystemUpdate($false)

 #Get all discussion messages
 $caml='<Where><Eq><FieldRef Name="ParentFolderId" /><Value Type="Integer">{0}</Value></Eq></Where>' -f $sourceDiscussion.ID
 $query = new-object Microsoft.SharePoint.SPQuery
 $query.Query = $caml
 $query.ViewAttributes = "Scope='Recursive'";
 $sourceMessages = $sourceList.GetItems($query)

 foreach ($sourceMessage in $sourceMessages) {
  #Add new message to discussion
  $destinationMessage = [Microsoft.SharePoint.Utilities.SPUtility]::CreateNewDiscussionReply($destinationDiscussion)
  
  #Copy field values
  $destinationMessage["Body"] = $sourceMessage["Body"]
  $destinationMessage["TrimmedBody"] = $sourceMessage["TrimmedBody"]
  $destinationMessage["Author"] = $sourceMessage["Author"]
  $destinationMessage["Editor"] = $sourceMessage["Editor"]
  $destinationMessage["Modified"] = $sourceMessage["Modified"]
  $destinationMessage["Created"] = $sourceMessage["Created"]

  #Copy attachments
  $attachmentCollection = $sourceMessage.Attachments
  $folder = $web.GetFolder($attachmentCollection.UrlPrefix);
  foreach ($file in $folder.Files) {
   $fileName = $file.Name
   $bytes = $file.OpenBinary() 
   $filePath = "$webURL/$folder/$fileName"
   $destinationMessage.Attachments.Add([System.IO.Path]::GetFileName($filePath), $bytes);
  }
  
  #Add message
  $destinationMessage.SystemUpdate($false)

 }

}
write-host 'Done'

Note:
If you have created additional column you will have to add them to the script. Also make sure the columns in the script are present in both discussion boards.

Fix: The local farm is not accessible. Cmdlets with FeatureDependencyId are not registered.

Scenario:
Trying to run a PowerShell script you get the following error:
The local farm is not accessible. Cmdlets with FeatureDependencyId are not registered.

Fix:
Run this PowerShell script:

Add-SPShellAdmin -username domain\user

Note:
Sometimes the fix is required although the Get-SPShellAdmin command returns the user as having shell admin privileges. It could be the case that not all the farm servers are in sync.

FIX: PowerShell Remoting fails

Scenario:
Your attempt to remote using PowerShell fails with this message:
Cannot access the local farm. Verify that the local farm is properly configured, currently available, and that you have the appropriate permissions to access the database before trying again.

Fix:
1. On the remote machine run the following PowerShell script:

#Enable Windows PowerShell Remoting 
Enable-PSRemoting -Force 
#Enable CredSSP support 
Enable-WSManCredSSP -Role Server -Force 
#Increase memory limit for remote shell 
Set-Item WSMan:\localhost\Shell\MaxMemoryPerShellMB 1000

2. On the client machine run the following PowerShell script:
#enable CredSSP on the client:  
Enable-WSManCredSSP -Role Client -DelegateComputer * -Force   
Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\Credssp\PolicyDefaults\AllowFreshCredentials -Name WSMan -Value WSMAN/*   
Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\Credssp\PolicyDefaults\AllowFreshCredentialsDomain -Name WSMan -Value WSMAN/*

Props:
Josh Gavant: PowerShell Remoting for SharePoint

Find all list templates used in a website


Scenario:
You need to determine the template used to create a list (or a library).

PowerShell script:

$web = get-spweb http://site:port/web
$web.lists | Format-Table -Property Title, BaseType, BaseTemplate -auto

Note:
The above script will list all BaseTypes and BaseTemplates used in the web

Export MOSS 2007 feature to *.wsp file

Scenario:
You need to extract an existing feature from MOSS 2007 into a *.wsp file to install it on another server (for example)

PowerShell script:

[System.Reflection.Assembly]::Load(“Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c”)
[System.Reflection.Assembly]::Load(“Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c”)
$farm = [microsoft.sharepoint.administration.spfarm]::Local
$feature = "solutionname.wsp"
$wsp = $farm.Solutions.Item($feature.SolutionFile)
$wsp.SaveAs("c:\$feature")

Note:
If you need to install PowerShell (Installation does not require a restart) you can download it from here: http://support.microsoft.com/kb/968930

Props:
The solution originally provided here: extract wsp file from configuration database

FIX: The site is not valid. The 'Pages' document library is missing

Scenario:
Trying to create a new page fails with this error:

Microsoft.SharePoint.Publishing.InvalidPublishingWebException: The site is not valid. The 'Pages' document library is missing.    
at Microsoft.SharePoint.Publishing.PublishingWeb.GetPublishingListWithCleanup(PublishingListType list, Boolean throwExceptionOnInvalidWeb)     
at Microsoft.SharePoint.Publishing.Internal.CodeBehind.BasePageSettingsPage.get_PageListRoot()     
at Microsoft.SharePoint.Publishing.Internal.CodeBehind.BasePageSettingsPage.SetParentUrlLabel()   
at Microsoft.SharePoint.Publishing.Internal.CodeBehind.BasePageSettingsPage.LoadValues()     
at Microsoft.SharePoint.Publishing.Internal.CodeBehind.CreatePagePage.LoadValues()     
at Microsoft.SharePoint.Publishing.Internal.CodeBehind.BasePageSettingsPage.OnLoad(EventArgs e)     
at Microsoft.SharePoint.Publishing.Internal.CodeBehind.CreatePagePage.OnLoad(EventArgs e)     
at System.Web.UI.Control.LoadRecursive()     
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

Fix: runt this PowerShell script:
$web = get-spweb http://site:port/web
$newId = $web.Lists["Pages"].ID
$web.AllProperties["__PagesListId"] = $newId.ToString()
$web.Update()

Upgrade SharePoint 2007 content database to SharePoint 2010

Scenario
You want to upgrade one or more SharePoint 2007 web sites to SharePoint 2010

How to
Create a copy of your SharePoint 2007 content database.

Run PowerShell script

Mount-SPContentDatabase -Name DBName -WebApplication http\\site:port -DatabaseServer DBServer -ClearChangeLog 

Note
You cannot add the content database through

Technet link:
http://technet.microsoft.com/en-us/library/ff607581.aspx

Delete all personal site collections

Scenario:
To save space, you want to delete all "personal" site collections from your local copy of the production content database.

PowerShell script:

 get-spsite -Limit ALL | where {$_.url -match "/personal/"} | ForEach-Object {Remove-SPSite -Identity $_.ID -Confirm:$false –GradualDelete}  

Note:
You can change the URL pattern to something else by replacing "/personal/" with your pattern.

Retract (uninstall and remove) SharePoint solution


Scenario:
You want to retract a solution already deployed to SharePoint. Normally you would use Visual Studio (r-click retract) for this but you don't have Visual Studio installed on the SharePoint server.

PowerShell Script:

$webUrl = "http://site:port"
$wspFileName = "myOldSolution.wsp"

function WaitForJobToFinish([string]$solutionName)
{ 
    $JobName = "*$solutionName*"
    $job = Get-SPTimerJob | ?{ $_.Name -like $JobName }
    if ($job -eq $null) {
        Write-Host 'Timer job not found'
    }
    else {
        Write-Host -NoNewLine "Waiting to finish job $JobFullName"

  $JobFullName = $job.Name
        while ((Get-SPTimerJob $JobFullName) -ne $null) {
            Write-Host -NoNewLine .
            Start-Sleep -Seconds 2
        }
        Write-Host  "done"
    }
}

# Add SharePoint Snapin
Add-PsSnapin Microsoft.SharePoint.PowerShell -erroraction SilentlyContinue
$webApp = Get-SPWebApplication $webUrl

$solution=Get-SPSolution -Identity $wspFileName -ErrorAction:SilentlyContinue
# Check whether the solution exists in the Solutions Store.
if ($solution -ne $null) {
 # Check whether the solution is already deployed.
 if ($solution.Deployed) {
  write-Host "Retracting" $solution.Name -ForegroundColor Yellow
  if ($solution.ContainsWebApplicationResource) {
   Uninstall-SPSolution -identity $solution.Name -allwebapplication -confirm:$false
  }
  else {
   Uninstall-SPSolution -identity $solution.Name -confirm:$false
  }

  WaitForJobToFinish $solution.Name
 }

 # Remove solution from store.
 Write-Host "Removing" $solution.Name -ForegroundColor Yellow          
 Remove-SPSolution –Identity $solution.Name -confirm:$false
}

Find all pages using a specific Web Part

Scenario:
You are looking for all pages where a specific Web Part is used

PowerShell Script:

Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.WebPartPages")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Publishing")

$wpName = "Register css web part";
$siteUrl = "http://site:port"
$libraryName = @("Pages");
$site = Get-SPSite $siteUrl;

foreach($spweb in $site.AllWebs)
{
 $url = $spweb.Url;
 foreach($library in $libraryName) {
  $list = $spweb.Lists[$library]
  foreach($listItem in $list.Items) {
   $WebPageUrl = $listItem.Url
   if ($WebPageUrl) {
    if ($spwebpart.Title -and $listItem.File.CheckOutType -ne "None") {
     Write-Host "Skipping checked out page $url/$WebPageUrl" -ForegroundColor Cyan
    }
    $spWpManager = $spweb.GetLimitedWebPartManager($WebPageUrl, [System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared);
    foreach($spWebPart in $spWpManager.Webparts) {
     if($wpName -eq $spWebPart.Title) {
      Write-Host "Found '$wpName' on $url/$WebPageUrl" -ForegroundColor Yellow
     }
    }
   }
  }
 }
 $spweb.Dispose();

 if($spWpManager -ne $null) {  
  $spWpManager.Dispose();
 }  
}

FIX: The local farm is not accessible. Cmdlets with FeatureDependencyId are not registered

Scenario:
You try to run a PowerShell script and the script fails with this message:
The local farm is not accessible. Cmdlets with FeatureDependencyId are not registered

Cause:
When you run this cmdlet to add a user to the SharePoint_Shell_Access role, you must have membership in the securityadmin fixed server role on the SQL Server instance, membership in the db_owner fixed database role on all affected databases, and local administrative permission on the local computer.

Fix:
Run this script in PowerShell:

Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue; 
Add-SPShellAdmin -UserName Domain\UserName;

More on Add-SPShellAdmin:
http://technet.microsoft.com/en-us/library/ff607596.aspx

Activate or deactivate timer job feature using PowerShell

Scenario:

  • You want to activate your newly deployed feature to install a timer job
  • You want to deactivate the feature and remove the job
  • You want to deploy an update to the existing timer job feature
Message:
The application attempted to perform an operation not allowed by the security policy. To grant this application the required permission please contact your system administrator or change the application's trust level in the configuration file.

Note:
I was able to Deactivate the feature from the SharePoint UI, as a farm admin, but the Activate still failed for me.

Solution:
Use the following PowerShell commands:

 Disable-SPFeature -Identity "TimerJobName" -url http://site:port  
or
 Enable-SPFeature -Identity "TimerJobName" -url http://site:port  

To determine your feature's name you can use (which can be tricky sometimes) use this command:
 Get-SPFeature | where-object {$_.DisplayName -match "MyPattern"} | Select DisplayName  

Delete a web part from all pages in a site collection

Scenario:
One of your custom web parts becomes obsolete and you decide to remove from all pages where is is used.

Powershell Script:

 Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue  
 [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.WebPartPages")  
 [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Publishing")  
 $wpName = "Register CSS web part";  
 $siteUrl = "http://site:port"  
 $libraryNames = @("Pages");  
 $site = Get-SPSite $siteUrl;  
 $checkedOut = @()  
 foreach($spweb in $site.AllWebs)  
 {  
      $url = $spweb.Url;  
      Write-Host "Processing $url"  
      foreach($lib in $libraryNames)  
      {  
           $list=$spweb.Lists[$lib]  
           foreach($item in $list.Items)  
           {  
                $WebPageUrl = $item.Url  
                if ($WebPageUrl.length > 0)  
                {  
                     Write-Host "Processing page $WebPageUrl"  
                     $spWpManager = $spweb.GetLimitedWebPartManager($WebPageUrl, [System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared);  
                     $webparts = @()  
                     if ($item.File.CheckOutType -ne "None")  
                     {  
                          $checkedOut = $checkedOut + $WebPageUrl + ","  
                     }  
                     foreach($spwebpart in $spWpManager.Webparts)  
                     {  
                          if($spwebpart.Title -eq $wpName)  
                          {  
                               $webparts = $webparts + $spwebpart.ID    
                          }  
                     }  
                     foreach($webpartId in $webparts)   
                     {  
                          Write-Host "Deleting " + $spwebpart.Title + " from " + $item.Name  
                          $spWpManager.DeleteWebPart($spWpManager.Webparts[$webpartId])  
                     }  
                }  
           }  
      }  
      if ($checkedOut -ne @()) {  
           Write-Host "The following pages were checked out and could not be processed: $checkedOut" -foreground yellow   
           }  
      $spweb.Update();  
      $spweb.Dispose();  
      $checkedOut = @()  
      if($spWpManager -ne $null)  
      {    
           $spWpManager.Dispose();  
      }    
 }  

Clear Recycle Bin using Powershell

Scenario: 
You want to clear ALL recycle bins in your site collection (both at the web level and at the site collection level)

PowerShell Script:

 $url = “http://site:port“;  
 Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue;  
 $siteCollection = Get-SPSite($url);  
 $siteCollection.RecycleBin.DeleteAll();  
 $siteCollection.Dispose();