Thursday, December 1, 2011

PowerShell script for creation of Custom Event Source and Event Log

Copy the PowerShell script below and save it as EventSourceCreation.ps1 for creation of Event Source and Event Log:

#Write-Host "Remove event source SharePointEventSource"
Remove-EventLog -Source SharePointEventSource
#Write-Host "SharePointEventSource removed"

#Write-Host "Create event source SharePointEventSource"
New-EventLog -LogName "SharePoint Event Source" -Source SharePointEventSource
#Write-Host "Event source SharePointEventSource created"

Once event source has been created, go to Run => eventvwr and you will see that the new
"SharePoint Event Source" has be created under the Application and Services Logs, see snapshot below:

To automatically run the above script as a batch utility, copy and paste the code below and save it as a .bat file extension:

cd /d %~dp0
powershell -noexit -file ".EventSourceCreation.ps1" "%CD%"
pause

Can write custom logging in SharePoint using the SPDiagnosticsService class to log messages and exceptions against the above custom source created namely: SharePointEventSource

Run the script and enjoy :)

Thursday, November 10, 2011

Programmatically find SharePoint 2010 Web Control references in your code-behind files


Programmatically find SharePoint 2010 Web control references in the code-behind files like .aspx.cs for Page Layouts or Custom Application Pages and .ascx.cs for User Controls and Visual Webparts.

I tried to get a handle to the RichHtmlField control in SharePoint using the standard .NET way like this:
Control ctrl = this.FindControl("controlID") as Control;

Sadly it did not work.

So had to write a generic FindControlRecursive methods to get a reference to any SharePoint Web Control used in Page Layouts, Application Pages, Visual WebParts, User Controls etc. See the function call and the generic functions. Copy the code and use it to your advantage.

Function call:

RichHtmlField pageContent = FindControlRecursive(this.Page, "pageContent") as RichHtmlField;

Generic Methods:

         private static Control FindControlRecursive(Page page, string controlID)
        {
            foreach (Control controlToSearch in page.Controls)
            {
                Control controlToReturn = FindControlRecursive(controlToSearch, controlID);

                if (controlToReturn != null)
                {
                    return controlToReturn;
                }
            }

            return null;
        }
     

        private static Control FindControlRecursive(Control rootControl, string controlID)
        {
            if (String.Equals(rootControl.ID, controlID))
            {
                return rootControl;
            }

            foreach (Control controlToSearch in rootControl.Controls)
            {
                Control controlToReturn = FindControlRecursive(controlToSearch, controlID);

                if (controlToReturn != null)
                {
                    return controlToReturn;
                }
            }

            return null;
        }

Hope it helps. Happy Programming.

Wednesday, September 21, 2011

Powershell script to print Managed Metadata termsets in a .csv file

Here is the powershell script to retrieve all Managed metadata term sets for a SharePoint 2010 site collection and print them into a .csv file

1. Copy the code below and modify the variables highlighted in yellow below, save the following as PrintManagedMetadataTerms.ps1 file:

Add-PsSnapin "Microsoft.SharePoint.PowerShell"

$site = Get-SPSite "http://dev-sp-2010:1000/sites/sharepointfix/"
$termStoreName = "Managed Metadata Service"
$termStoreGroupName = "SharePointFixPortal"

set-variable -option constant -name out -value "C:\PrintAllManagedMetaDataTermSets.csv"

$session = new-object Microsoft.SharePoint.Taxonomy.TaxonomySession($site)
$termStore = $session.TermStores[$termStoreName]
$termStoreGroup = $termStore.Groups[$termStoreGroupName]

# Prints all Managed Metadata Termsets in the .csv file at the configured location
foreach($termsets in $termStoreGroup.TermSets)
{
"Termset Name: " + $termsets.Name + ", Description: " + $termsets.Description + ", Group: " + $termsets.Group + ", ID: " +$termsets.Id + ", Available for Tagging: " + $termsets.IsAvailableForTagging + ", Is Open for Term Creation : " + $termsets.IsOpenForTermCreation | Out-File $out -append;

foreach($terms in $termsets.GetAllTerms())
{
"Term Name:" + $terms.Name | Out-File $out -append
}
}

$site.Dispose()

Echo "Finished!"
Echo "Managed metadata termsets printed at:" $out

Remove-PsSnapin "Microsoft.SharePoint.Powershell"

2. To automatically run the above .ps1 script as a batch utility, Copy and paste code below and save it with a .bat file extension

cd /d %~dp0
powershell -noexit -file ".\PrintManagedMetadataTerms.ps1" "%CD%"
pause

Run the above .bat file, on the receipt of success message, traverse to the configured path to find the .csv file with all the managed metadata printed values.

Sunday, July 31, 2011

SharePoint 2010 List Item Event Receiver - Native Stack Error 0x81020089

When creating List Item Event Receivers, we added the ItemDeleting event to prevent List Items from being deleted:

public override void ItemDeleting(SPItemEventProperties properties)
{
    properties.Cancel = true;
    properties.Status = SPEventReceiverStatus.CancelWithRedirectUrl;
    properties.ErrorMessage = "Bugs can only be resolved not deleted!";

    //You may also redirect to a custom error URL page:
    //SPUtility.Redirect(web.Url + Constants.ERROR_PAGE_URL + errorMessage, SPRedirectFlags.DoNotEndResponse, HttpContext.Current);
}

You would think that the above piece of code will show an appropriate validation message while deleting a list item, but instead it throws a native call stack error.

We identified that these code lines do not work very well with List Item event receivers:

properties.Cancel = true;  and
properties.Status = SPEventReceiverStatus.CancelWithRedirectUrl;

As a result we see a Native Stack Error Message:

We modified the ItemDeleting Event receiver code and it started working fine:

public override void ItemDeleting(SPItemEventProperties properties)
{
    properties.Status = SPEventReceiverStatus.CancelNoError;
    properties.ErrorMessage = "Bugs can only be resolved not deleted!";

     //You may also redirect to a custom error URL page:
    //SPUtility.Redirect(web.Url + Constants.ERROR_PAGE_URL + errorMessage, SPRedirectFlags.DoNotEndResponse, HttpContext.Current);
}


Elements.xml file for the List Item Event Receiver is as follows:

<?xml version="1.0" encoding="utf-8" ?> 
- <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
- <Receivers ListTemplateId="100">
- <Receiver>
  <Name>CustomItemDeleting</Name> 
  <Type>ItemDeleting</Type> 
  <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly> 
  <Class>SharePointFix.Project.ItemDeletingEvent</Class> 
  <SequenceNumber>10001</SequenceNumber> 
  </Receiver>
  </Receivers>
  </Elements>

Receiver ListTemplateId = 100, ensures that the validation works for both Pages library and Custom SharePoint Lists.

Friday, July 22, 2011

Powershell script to deploy multiple solutions (.wsp) to your SharePoint 2010 web application

The Powershell script below iterates through each .wsp files in your physical folder, installs and deploys them globally into all web-applications thus automating the solution deployment process.

Copy the PowerShell scriptlet below and paste it in a notepad and save it with a .ps1 extension in any of the directories in your hard disk.

NOTE: Do not forget to place all your solution files i.e..wsp files in the same directory as your .ps1 directory.
======================================================================

Add-PsSnapin Microsoft.SharePoint.PowerShell

#Do not modify anything in the script from here onwards
function Get-ScriptDirectory
{
 $Invocation = (Get-Variable MyInvocation -Scope 1).Value
 Split-Path $Invocation.MyCommand.Path
}

function Deploy-Solution{
param(
[string]$physicalPath,
[string]$name)

$SolutionName = $name
$SolutionPath = Join-Path ($physicalPath) $SolutionName
echo "Extracting information from $physicalPath"

#Admin service
$AdminServiceName = "SPAdminV4"
$IsAdminServiceWasRunning = $true;

if ($(Get-Service $AdminServiceName).Status -eq "Stopped")
{
    $IsAdminServiceWasRunning = $false;
    Start-Service $AdminServiceName
   Write-Host 'SERVICE WAS STOPPED, SO IT IS NOW STARTED'
}

#Uninstall
Write-Host 'UNINSTALLING SOLUTION ...'

$Solution = Get-SPSolution | ? {($_.Name -eq $SolutionName) -and ($_.Deployed -eq $true)}

if ($Solution -ne $null)
{
    if($Solution.ContainsWebApplicationResource)
    {
        Uninstall-SPSolution $SolutionName -AllWebApplications -Confirm:$false
    }
    else
    {
        Uninstall-SPSolution $SolutionName -Confirm:$false
    }
}

while ($Solution.JobExists)
{
    Start-Sleep 2
}

Write-Host 'SOLUTION HAS BEEN UNINSTALLED SUCCESSFULLY.'

Write-Host 'REMOVING SOLUTION ...'

if ($(Get-SPSolution | ? {$_.Name -eq $SolutionName}).Deployed -eq $false)
{
    Remove-SPSolution $SolutionName -Confirm:$false

Write-Host 'SOLUTION HAS BEEN REMOVED SUCCESSFULLY.'
}

Write-Host 'ADDING SOLUTION ...'

Add-SPSolution $SolutionPath  | Out-Null

Write-Host 'SOLUTION HAS BEEN ADDED SUCCESSFULLY.'

Write-Host 'DEPLOYING SOLUTION ...'

$Solution = Get-SPSolution | ? {($_.Name -eq $SolutionName) -and ($_.Deployed -eq $false)}

#use '-force' paramater to install all commands in this if statement

if(($Solution -ne $null) -and ($Solution.ContainsWebApplicationResource))
{
Install-SPSolution $SolutionName –AllwebApplications -GACDeployment -Force -Confirm:$false
}
else
{
Install-SPSolution $SolutionName -GACDeployment -Force -Confirm:$false
}

while ($Solution.Deployed -eq $false)
{
    Start-Sleep 2
}

Write-Host 'SOLUTION HAS BEEN DEPLOYED SUCCESSFULLY.'

if (-not $IsAdminServiceWasRunning)
{
    Stop-Service $AdminServiceName
}
}

#Get Current Physical Path
$currentPhysicalPath = Get-ScriptDirectory

#Iterate through all .wsp files in the current Physical Path to deploy solution
get-childitem $currentPhysicalPath -include *.wsp -recurse | foreach ($_) {Deploy-Solution $currentPhysicalPath $_.name}

#Remove SharePoint Snapin
Remove-PsSnapin Microsoft.SharePoint.PowerShell

Echo Finish

====================================================================


Automate the above .ps1 script as a batch utility, Copy and paste code below and save it with a .bat file extension, change the script file name in the highlighted yellow section below to your .ps1 name.

cd /d %~dp0
powershell -noexit -file ".AutomateDeploymentScript.ps1" "%CD%"
pause

Run the batch file and enjoy the automated deployment process:)

Tuesday, May 17, 2011

SharePoint Central Administration Content Database in Suspect Mode

What will be your first reaction when your Central Administration in SharePoint 2010 stops abruptly and its Content/Config database switches itself automatically to Suspect mode for no apparent reason, that too after a very stressful and super-hard working day.

Common human reaction is to get scarred, pissed-off, drop the F-bombs on SharePoint 2010, drink lots of coffee, get irritated and shout on friends and family... :)

I checked the ULS logs, Event Viewer logs, tried Application Pool recycles, Website Start/Stops, IIS Resets, even re-booted the server, even ran the SP 2010 Config Wizard. Sadly, none of them worked. By now I started thinking that my SP 2010 farm is corrupt and needs to be re-configured/re-installed from scratch. A very painful thought in itself.

But as I further researched on this weird content database suspect issue, found this post on the forum which got me started: http://social.msdn.microsoft.com/forums/en-US/sqldisasterrecovery/thread/48cf82c9-2179-46f3-b009-11416a90d248/

However, I had to do a lot of R&D to get the actual SQL commands working.

Go to your SQL Server and ensure either your Central Admin Content Database or Config Database, if it is in Suspect mode, then this post is for you, see snapshot below:







So either a Central Admin Content database or a Config database can abruptly go into the suspect mode without any apparent logical reason. In my case, SharePoint Central Admin Content Database went into the Suspect mode.

To resolve the issue, follow steps in the following order as mentioned:

1. Go to your MSSQL\Data files that reside under: C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA


2. Identify your Central Admin Content Database name in my case it got screwed up and was in the suspect: mode: so this is my content database name SharePoint_AdminContent_38c5cc2d-aeec-4dc2-b7a5-65457250ae2c


NOTE: Please take a backup of the corrupted .mdf and .ldf files, before following other steps.

3. Open your SQL Server Management Studio ->, New Query and it opens up your SQL Query editor, copy and paste the query below and change the highlighted to your database name:

Use master

--Verify whether Database has any issues
EXEC sp_resetstatus "SharePoint_AdminContent_38c5cc2d-aeec-4dc2-b7a5-65457250ae2c.mdf"

---Alter database and put it on Emergency Mode
ALTER DATABASE "SharePoint_AdminContent_38c5cc2d-aeec-4dc2-b7a5-65457250ae2c" SET EMERGENCY
DBCC checkdb('SharePoint_AdminContent_38c5cc2d-aeec-4dc2-b7a5-65457250ae2c')

--Set the database in the Single User mode
ALTER DATABASE "SharePoint_AdminContent_38c5cc2d-aeec-4dc2-b7a5-65457250ae2c" SET SINGLE_USER WITH ROLLBACK IMMEDIATE

--Repair the database and allow data loss
DBCC CheckDB('SharePoint_AdminContent_38c5cc2d-aeec-4dc2-b7a5-65457250ae2c',REPAIR_ALLOW_DATA_LOSS)

--Set the database back to Multi-User mode
ALTER DATABASE "SharePoint_AdminContent_38c5cc2d-aeec-4dc2-b7a5-65457250ae2c" SET MULTI_USER

--Ensure Database is reset
EXEC sp_resetstatus 'SharePoint_AdminContent_38c5cc2d-aeec-4dc2-b7a5-65457250ae2c'

Execute all the commands in your SQL Query Editor and there you go, Go back to your SQL Management Studio and you can see that the (Suspect) mode issue against the Content/Config database is fixed and the database got fully repaired and restored.

To verify the same, hit your Central Administration and it starts working just fine...

NOTE: This post is true for any Content Database/Config Database in your SharePoint 2010 farm and not subject to only the Central administration web application. It will work equally well, if any of your current Web Application/Site Collection Content database gets corrupted and switches into the Suspect mode.

I hope it helps,

Tuesday, May 10, 2011

Powershell script to Enable Developer Dashboard

Here is the Powershell script to Enable Developer Dashboard in SharePoint 2010

Add-PsSnapin Microsoft.SharePoint.PowerShell
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Administration")

##Turn On: for on-Demand Mode

$service = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
$addsetting =$service.DeveloperDashboardSettings
$addsetting.DisplayLevel = [Microsoft.SharePoint.Administration.SPDeveloperDashboardLevel]::OnDemand
$addsetting.Update()

##Turn On

$service = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
$addsetting =$service.DeveloperDashboardSettings
$addsetting.DisplayLevel = [Microsoft.SharePoint.Administration.SPDeveloperDashboardLevel]::On
$addsetting.Update()

##Turn Off

$service = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
$addsetting =$service.DeveloperDashboardSettings
$addsetting.DisplayLevel = [Microsoft.SharePoint.Administration.SPDeveloperDashboardLevel]::Off
$addsetting.Update()


Mode of developer dashboard:
On – creates everytime the output at the end of the page content
Off – switch off developer dashboard and nothing is rendered
OnDemand – creates a DeveloperDashboard icon to make dashboard output visible as needed

Developer Dashboard is visible on the upper right hand corner:















Thursday, May 5, 2011

Find the Role/Permissions of a currently logged in user in SharePoint 2010

This method below, tries to Find Role/Permission for the currently logged-in user using SPRoleAssignment and SPRoleDefinition objects. Check it out to learn more about the object model for identifying roles using the SPRoleType enumerator

public void FindRolesForCurrentlyLoggedInUser(SPWeb web, SPUser user)
{
bool IsApprover = false;
bool IsReader = false;
bool IsDirectPermission = false;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(siteID))
{
using (SPWeb web = site.OpenWeb(webID))
{
//Check all Groups in the Current Web
foreach (SPGroup group in web.Groups)
{
try
{
//Check If Currently Logged In User has permissions in the all Web Groups
if (group.Users[user.LoginName].ID.ToString().Equals(user.ID.ToString()))
{
//Get Role Assignments
SPRoleAssignment currentUserRole = web.RoleAssignments.GetAssignmentByPrincipal(group as SPPrincipal);

//Go through all Role Definition Bindings
foreach (SPRoleDefinition role in currentUserRole.RoleDefinitionBindings)
{
//Check If Role Type == Reader - Do something
if (role.Type.Equals(SPRoleType.Reader))
{
}
//Administrators access - Full Control - Do something
else if (role.Type.Equals(SPRoleType.Administrator))
{
}
//Contributor access - Contribute - Do something
else if (role.Type.Equals(SPRoleType.Contributor))
{
}
//Web Designer access - Design rights- Do something
else if (role.Type.Equals(SPRoleType.WebDesigner))
{
}
//Limited access - Do something
else if (role.Type.Equals(SPRoleType.Guest))
{
}
//No access on Current Web- Do something
else if (role.Type.Equals(SPRoleType.None))
{
}
}
}

//Get Role Assignments for Current User - If he has been directly assigned permissions
try{SPRoleAssignment directPermission = web.RoleAssignments.GetAssignmentByPrincipal(user as SPPrincipal);}
catch(Exception){/*Best attempt to catch Exceptions*/}
}
catch (Exception)
{
/* Best Attempt to find the User In the Group. Do not throw any exception if a user does not exist in the Group */
}

}
}
}
});
}

Friday, April 22, 2011

Powershell script to Backup SharePoint 2010 Farm and Site Collections

To start a full farm backup,
Backup-SPFarm -BackupMethod Full -Directory "Destination-Directory"
-BackupThreads 5

When the above command is executed, a full farm backup will be performed with
five threads to perform the backup. You can specify up to 10 threads. However,
the fewer the backup threads, the easier it is to read the backup log file. You can
also specify "Differential" as the backup method to perform differential backup of
SharePoint farm. By default, this does not show the progress of backup
operation.

To see the progress as backup is performed:
Backup-SPFarm -BackupMethod Full -Directory "Destination-Directory"
-BackupThreads 5 –Verbose

To see a list of all items included in backup:
Backup-SPFarm –ShowTree

To perform a site collection backup:
Backup-SPSite -Identity "http://SharePointFix:101/" -Path "Path to Backup
file"

To perform on site collection backup using SQL snapshots:
Backup-SPSite -Identity "http://SharePointFix:101/" -Path "Path to Backup
file" –UseSqlSnapShot

There is no option in the central administration to perform backup using SQL
snapshots. This can be done using PowerShell only. Also, using SQL Snapshots
is the recommended way to perform a site collection backup. This will allow users
to continue to read / write site collection content while the backup is in progress.

References: Knowledge Base article from http://www.powergui.org/

Thursday, April 21, 2011

Powershell script to create nested subsites within a site collection

Our goal is to create 50 parent subsites and iteratively create 5 nested child subsites underneath each of them. So mathematically it is 50 subsites * 5 nested subsites per parent subsite = 250 nested sub-sites in total.

The powershell scriptlet below accepts Site Collection URL,  Site Collection Template, Site Collection Language, Sub-site Name and a Nested Sub-site name as configurable parameters, it then goes through each of them and creates nested sub-sites for that particular Site Collection.

Instructions:
1. Copy and Paste the code below and save it as CreateNestedSubSites.ps1, see highlighted yellow sections to change configurable values:

Add-PsSnapin Microsoft.SharePoint.PowerShell

## SharePoint DLL
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")

#Creating Sub Sites in top site collection.
Write-Output " "
Write-Output "Creating 250 Nested Sub-Sites"

$SiteCollectionURL = "http://localhost/sites/NestedSubSites"

$SiteCollectionTemplate = "BLANKINTERNETCONTAINER#0"

$SiteCollectionLanguage = 1033

$StaplingWeb = "StaplingWeb"

$StaplingNestedSubWeb = "NestedWeb"

## Iterate via 50 Subsites
for($i=0 ; $i -lt 50 ; $i++)
{
    $SiteUrl = ""
    $SubSiteName = ""
    $SiteUrl = $SiteCollectionURL + "/"
    $SubSiteName = $StaplingWeb + $i
    $SiteUrl = $SiteUrl += $SubSiteName

    Write-Host "Creating Sub-Site for " $SubSiteName
    New-SPWeb $SiteUrl -Template $SiteCollectionTemplate -Name $SubSiteName  -UseParentTopNav -Language $SiteCollectionLanguage
    Write-Host "Site Created for " $SubSiteName
   
    ## Create 5 Subsites underneath each of the 50 subsites
    for($j=0 ; $j -lt 5 ; $j++)
    {
        $NestedSubSiteUrl = ""
        $NestedSubSiteName = ""
        $NestedSubSiteName = $StaplingNestedSubWeb + $j
       
        $NestedSubSiteUrl = $SiteUrl + "/"
        $NestedSubSiteUrl = $NestedSubSiteUrl += $NestedSubSiteName
       
        Write-Host "Creating Nested Sub-Site for :" $NestedSubSiteName
        New-SPWeb $NestedSubSiteUrl -Template $SiteCollectionTemplate -Name $NestedSubSiteName  -UseParentTopNav -Language $SiteCollectionLanguage
        Write-Host "Nested Sub-Site created for :" $NestedSubSiteName
    }
}

Remove-PsSnapin Microsoft.SharePoint.PowerShell

2. To automatically run the CreateNestedSubSites.ps1 script as a batch utility, Copy and paste code below and save it with a .bat file extension

cd /d %~dp0
powershell -noexit -file ".\CreateNestedSubSites.ps1" "%CD%"
pause


Run the Script and enjoy :)

Tuesday, April 19, 2011

Powershell Script to create subsites within a site collection

The powershell scriptlet below accepts Site Collection URL,  Site Collection Template, Site Collection Language and Sub Site Names as configurable parameters, it then goes through each subsite array and creates subsites for that particular Site Collection.

Instructions:
1. Copy and Paste the code below and save it as CreateSubSite.ps1, see highlighted yellow sections to change configurable values:

Add-PsSnapin Microsoft.SharePoint.PowerShell

## SharePoint DLL
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")

#Creating Sub Sites in top site collection.
Write-Output " "
Write-Output "Creating Sub Sites"

$SiteCollectionURL = "http://localhost/sites/SPFix"

$SiteCollectionTemplate = "STS#0"

$SiteCollectionLanguage = 1033

$SubSites = @("Central Services", "Knowledge Base", "Service Center", "IT", "HR", "Finance")

for($i=0 ; $i -lt $SubSites.count ; $i++)
{
$SiteUrl = ""
$SiteUrl = $SiteCollectionURL + "/"
$SiteUrl = $SiteUrl += $SubSites[$i]
Write-Output " "
#Write-Output "Creating Site for " += $SubSites[$i]
Write-Output " "
New-SPWeb $SiteUrl -Template $SiteCollectionTemplate -Name $SubSites[$i]  -UseParentTopNav -Language $SiteCollectionLanguage
Write-Output " "
#Write-Output "Site Created for " += $SubSites[$i]
Write-Output " "
}

Remove-PsSnapin Microsoft.SharePoint.PowerShell

2. To automatically run the CreateSubSite.ps1 script as a batch utility, Copy and paste code below and save it with a .bat file extension

cd /d %~dp0
powershell -noexit -file ".\CreateSubSite.ps1" "%CD%"
pause

Run the Script and Enjoy :)

Thursday, April 7, 2011

Powershell Script to Delete Site Columns from SharePoint SiteCollection RootWeb


The code below accepts Site Collection URL and Site Columns List as configurable parameters, it then goes through each semi-colon separated Site Columns List and deletes it from the RootWeb of the Site Collection.

Instructions:
1. Copy and Paste the code below and save it as DeleteSiteColumns.ps1, see highlighted sections to change configurable values:

Add-PsSnapin Microsoft.SharePoint.PowerShell
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")

set-variable -option constant -name url  -value "http://localhost/" # Specify your Site collection URL
$siteColumnsList = "Display Name Column1;Display Name Column2;Display Name Column3" # Specify a list of Site Column Names to be deleted

$site = new-object Microsoft.SharePoint.SPSite($url)
$array = $siteColumnsList.Split(";")

foreach($colms in $array)
{
try
{
$column = $site.rootweb.Fields[$colms]
$site.rootweb.Fields.Delete($column)
Write-Host $column.Title "deleted successfully."
}
catch [System.Exception]
{
Write-Host $column.Title "deleted failed."
#Best Attempt to Remove Site Columns
}
}

$site.Dispose()

Remove-PsSnapin Microsoft.SharePoint.PowerShell
Echo Finish

2. To automatically run the .ps1 script as a batch utility, Copy and paste code below and save it with a .bat file extension


cd /d %~dp0
powershell -noexit -file ".\DeleteSiteColumns.ps1" "%CD%"
pause


Run the Script and Enjoy :)

Tuesday, March 8, 2011

Powershell script - Get all Site Columns for a SharePoint 2010 site collection

Here is the powershell script to retrieve all Site Columns for a SharePoint 2010 site collection and output the details into a .csv file

Copy the code below and change the Site Collection URL and Output Path as per your requirement, save the following as .ps1 file:

Add-PsSnapin Microsoft.SharePoint.PowerShell
## SharePoint DLL
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
# Description
#   Output all available Column Field GUIDs to AllColumnFields.csv

# Settings Start
set-variable -option constant -name url     -value "http://localhost"       # Site collection
set-variable -option constant -name out     -value "C:AllColumnFields.csv"           # Output file
# Settings End

$site   =    new-object Microsoft.SharePoint.SPSite($url)
$web    = $site.rootweb.Fields
echo "Generating File..."
ForEach ($id in $web)
{
'"' + $id.Title + `
'","' + $id.Id + `
'","' + $id.InternalName + `
'","' + $id.StaticName + `
'","' + $id.MaxLength + `
'","' + $id.Description + `
'","' + $id.Group + `
'","' + $id.TypeShortDescription + `
'"' | Out-File $out -append
}
$site.Dispose()
echo "Finished"
echo "File created at : " $out

Remove-PsSnapin Microsoft.SharePoint.PowerShell

It outputs all the Site Column details available in the Site Columns Gallery to a .csv file.

Sunday, February 27, 2011

SPSecurity.RunWithElevatedPrivileges Access denied issue

SPRunWithElevatedPrivileges allows you to run your SharePoint code in the context of the App Pool identity account.

Look at the piece of code below:


function void ListItemUpdate(Guid guId)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
SPSite site = SPContext.Current.Site;
SPWeb web = SPContext.Current.Web;
web.AllowUnsafeUpdates = true;

SPList list = web.Lists["Products"];
SPListItem item = list.Items[guId];
item["ProductName"] = "Apple iPhone 4";
item["ProductPrice"] = "199";

item.Update();

web.AllowUnsafeUpdates = false;
});
}

So when a user with Read access tries to execute the above code, he gets an Access denied error, even after the code having the RunWithElevated Privileges set.

Lets examine, look at the code highlighted in yellow above. SPContext.Current.Site and SPContext.Current.Web runs the List Item update code in the context of the currently logged in user and not in the context of the App Pool identity.

Solution: Solution is to re-open new SPSite and SPWeb objects within the SPSecurity delegate block, lets rewrite the above code and fix the issue:

function void ListItemUpdate(Guid guId)
{
Guid siteId = SPContext.Current.Site.Id;
Guid webId = SPContext.Current.Web.Id;

SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(siteId))
{
using (SPWeb web = site.OpenWeb(webId))
{
web.AllowUnsafeUpdates = true;

SPList list = web.Lists["Products"];
SPListItem item = list.Items[guId];
item["ProductName"] = "Apple iPhone 4";
item["ProductPrice"] = "199";
item.Update();

web.AllowUnsafeUpdates = false;
}
}
});
}

Running this piece of code fixes the Access denied issue and allows the code to run under AppPool identity.

Wednesday, February 23, 2011

SharePoint 2010 - Do not dispose guidance for SharePoint objects

Do not dispose the following listed SharePoint objects explicitly: (Applicable for both SharePoint 2010 and SharePoint 2007)

•SPContext.Current.Site

•SPContext.Current.Web

•SPContext.Site

•SPContext.Web

•SPControl.GetContextWeb(..)

•SPControl.GetContextSite(..)

•SPFeatureReceiverProperties.Feature.Parent

•SPItemEventProperties.ListItem.Web

•SPList.BreakRoleInheritance()

◦Do not call list.ParentWeb.Dispose()

•SPListEventProperties.Web

•SPListEventProperties.List.Web

•SPSite.RootWeb

◦Problems may occur when SPContext.Web has equality to the SPContext.Web.. make sure you dispose of SPSite and it will cleanup sub webs automatically

•SPSite.LockIssue

•SPSite.Owner

•SPSite.SecondaryContact

•SPWeb.ParentWeb

•SPWebEventProperties.Web

Few important changes for Dispose rules in SharePoint 2010:
•Microsoft.SharePoint.WebControls.SiteAdminsitrationSelector.CurrentItem
When used with WSS 3.0 you must call Dispose(), with SharePoint Foundation 2010 you don’t.

•Event Receivers and properties.OpenWeb()
WSS 3.0: When you call properties.OpenWeb() the returned SPWeb will need to call Dispose()
SharePoint Foundation 2010: Use the newly introduced SPItemEventProperties.Web property instead of SPItemEventProperties.OpenWeb() for better performance and to avoid the need to call Dispose().

Reference: http://blogs.msdn.com/b/rogerla/archive/2009/11/30/sharepoint-2007-2010-do-not-dispose-guidance-spdisposecheck.aspx

Sunday, February 20, 2011

XML and XSL transformation control for SharePoint 2010

The ASP.NET control control for SharePoint enable users to provide their XML and XSL files, spitting out the resulting HTML based on the two control parameters.

1. Copy and paste the code below in your custom SharePoint page:
<div>
<asp:Xml runat="server" id="xmlEmployee" DocumentSource="/_layouts/SPFix/Employee.xml" TransformSource="/_layouts/SPFix/Employee.xsl">
</asp:Xml>
</div>

2. The Document Source behavior takes an XML file path and Transform Source takes an XSL file path
3. You can see the resulting HTML spitted out to the browser when you hit your SharePoint custom page.

Quickest way is to try using SharePoint Designer as per the best practice you need to create a Visual Studio solution for your SharePoint pages.

Saturday, February 19, 2011

StringWriter and HTMLTextWriter objects to emit HTML in custom Webparts

You could also use StringWriter and HTMLTextWriter objects to write HTML to the Web part rather than the LiteralControl.

For example, the following code creates a simple StringBuilder object, then writes that through using the
StringWriter and HtmlTextWriter objects:

StringBuilder sb = new StringBuilder();
sb.AppendLine(“<table border=’0’><tr><td>”);
StringWriter spStrWriter = new StringWriter(sb);
HtmlTextWriter htmlTxtWriter = new HtmlTextWriter(spStrWriter);
Page.RenderControl(htmlTxtWriter);

Admittedly, the use of multiple literalcontrol objects is not the most elegant of ways to emit HTML
when rendering Web parts. See an example usage of Literal Controls mentioned below:

StringBuilder sb = new StringBuilder();
sb.AppendLine(“<table border=’0’><tr><td>”);
this.Controls.Add(new LiteralControl(sb.ToString()));

ASP.NET provides a rich framework for writing HTML out to the page, which includes the HtmlTextWriter class. We can leverage this while writing custom webparts

How to register Javascripts within SharePoint page programmatically

When you’re integrating script within a SharePoint page, you can use the ClientScriptManager object to add and manage scripts within a Web application. For example, the following code snippet shows a simple method that ensures only one instance of each script is added to a page:

public static void RegisterScript
(ref ClientScriptManager csm,
string key, string url)
{
if (!csm.IsClientScriptBlockRegistered(key))
csm.RegisterClientScriptInclude(key, url);
}

For more information on the ClientScriptManager, see http://msdn.microsoft.com/en-us/library/system.web.ui.clientscriptmanager.aspx.

Thursday, February 3, 2011

Visual Studio 2010 and FxCop Integration

Visual Studio 2010 Premium and Ultimate Editions already have FxCop installed by default under the Code Analysis section in the Build menu option, see snapshot below:


You can configure your own Rules by right clicking on your Project -> Properties -> Code Analysis -> Set the Rule Set option as shown in the snapshot below:


To run the Code Analysis section, right click on your Project -> Run Code Analysis as shown in the snapshot below:


You will see the Code Analysis Results in the Error List window as shown in the snapshot below:
(Check for both Errors and Warnings and fix them)


I hope this helps.

SPDispose Check utility - Integrate with Visual Studio 2010

SPDisposeCheck utility checks whether you have disposed the unmanaged SPSite and SPWeb objects correctly or not. Its a tool that every SharePoint developer needs to have integrated in their Visual Studio boxes.

I have prepared a list of Best Practices for Disposing SharePoint objects: http://www.sharepointfix.com/2008/12/best-practices-disposing-sharepoint.html

Guidelines to integrate SPDisposeCheck with Visual Studio Solution:

1. Download the SPDisposeCheck.exe utility from: http://download.microsoft.com/download/B/4/D/B4D279A0-E159-40BF-A5E8-F49ABDBE95C7/SPDisposeCheck.msi

2. Open your Visual Studio environment and follow the steps as specified:
a. Go to Tools -> External Tools -> Add
b. Enter Title as SPDisposeCheck
c. Command : C:\Program Files (x86)\Microsoft\SharePoint Dispose Check\SPDisposeCheck.exe
d. Arguments : $(TargetName)$(TargetExt)
e. Initial Directory : $(TargetDir)
f. Check mark the Output window checkbox and
g. Click on the Ok button

See snapshot below:


3. Open your Visual Studio solution project and Build it.

4. Select Tools -> SPDisposeCheck:


5. Open the Output window and you should be able to see a set of messages like this:


6. It also shows up the errors in the Visual Studio Error Messages section as follows:

7. You can even configure additional SPDispose Check settings within Visual Studio 2010 by selecting "SharePointDispose Check" link under Tools, see snapshot below:


Let me know if it helps.

Saturday, January 22, 2011

Enumerate site collections, subsites and activate feature using Power Shell

This script enumerates through all site collections for a given web application, then enumerates through all subsites within each site collection and activates the given web level feature, copy the script as mentioned below, change the highlighted sections and save it as IterateSiteSubsitesActivateWebLevelFeature.ps1 file:

 Powershell Script updated on Feb 10th, 2012.

Add-PsSnapin Microsoft.SharePoint.PowerShell

## SharePoint DLL
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")

$webApplicationURL = "http://dev-sp-2010:1000"
$featureFolderName = "PublishingWeb"

$webApp = Get-SPWebApplication $webApplicationURL

if($webApp -ne $null)
{
foreach($siteColl in $webApp.Sites)
{
   if($siteColl -ne $null)
   {
foreach($subWeb in $siteColl.AllWebs)
{
if($subWeb -ne $null)
{
# Print each Subsite
#Write-Host $subWeb.Url
                 
#Get Feature ID based on the Feature Name
$FeatureID = Get-SPFeature -Web $subWeb.Url | Where {$_.DisplayName -eq $featureFolderName}

if($FeatureID -ne $null)
{
#Check whether Feature to be activated is already activated for this subsite
if (Get-SPFeature -Web $subWeb.Url | Where {$_.ID -eq $FeatureID.Id})
{
Write-Host $featureFolderName "is already activated at :" $subWeb.Url
   }
else
{
#Enable-SPFeature -Identity $featureFolderName -Confirm:$false -Url $subWeb.url
Write-Host $featureFolderName "has been activated at :" $subWeb.url
}
}
$subWeb.Dispose()
}
else
{
Echo $subWeb "does not exist"
}
}
$siteColl.Dispose()
}
else
{
Echo $siteColl "does not exist"
}
}
}
else
{
Echo $webApplicationURL "does not exist, check the WebApplication name"
}

Remove-PsSnapin Microsoft.SharePoint.PowerShell

Echo Finish

 
To automatically run this script as a batch utility, use the following:
Copy code below, save it as a .bat file to run the powershell script

cd /d %~dp0
powershell -noexit -file ".\IterateSiteSubsitesActivateWebLevelFeature.ps1" "%CD%"
pause

I hope this helps. Also refer to the Microsoft TechNet post for an alternative webservice approach: http://blogs.msdn.com/b/vijay/archive/2009/10/01/how-to-list-all-the-sub-sites-and-the-site-collections-within-a-sharepoint-web-application-using-windows-powershell.aspx

Thursday, January 20, 2011

Creating Managed Metadata Termsets using PowerShell

Iterate through the XML file to dynamically create Managed Metadata Groups, Termsets and Terms using Powershell script.

Copy the XML mentioned below and save it as ManagedMetaDataTermSets.xml

<?xml version="1.0"?>
<termstore name="Managed Metadata Service">
  <group name="SharePoint Fix">
    <termset name="Region">
      <term name="North America">
        <term name="USA"></term>
        <term name="Canada"></term>
        <term name="Greenland"></term>
      </term>
      <term name="Technology">
        <term name="Technical Build and Delivery"></term>
        <term name="Technical Consultancy"></term>
        <term name="Technical Design"></term>
      </term>
      <term name="User Experience">
        <term name="Creative Design"></term>
        <term name="Information Architecture"></term>
      </term>
    </termset>
  </group>
</termstore>

The code mentioned below is RTM/Production Ready, you can find the original source code at Benn Robs site: http://sharepointtales.wordpress.com/2010/05/06/manipulating-the-terms-store-through-powershell/

Copy the code below and save it in a CreateTermSets.ps1 file: (replace the highlighted script block with your values)

Add-PsSnapin Microsoft.SharePoint.PowerShell

function SetTermsRecursive ([Microsoft.SharePoint.Taxonomy.TermSetItem] $termsetitem, $parentnode)
{
$parentnode.term
ForEach-Object {
## create the term
if($_ -ne $null)
{
$newterm = $termsetitem.CreateTerm($_.name, 1033)
Write-Host -ForegroundColor Cyan "Added term $_.name"
SetTermsRecursive $newterm $_
}
}
}
#Do not modify anything in the script from here onwards
function Get-ScriptDirectory
{
$Invocation = (Get-Variable MyInvocation -Scope 1).Value
Split-Path $Invocation.MyCommand.Path
}

#Solutions to Deploy
$XMLName = "ManagedMetaDataTermSets.xml"
$XMLPath = Join-Path (Get-ScriptDirectory) $XMLName

echo "Extracting information from the $XMLPath"

#Site Collection URL - Give your site collection url in quotation marks
$TaxonomySiteUrl = "http://localhost"

#Access the TermStore data
[xml]$TermStoreData = Get-Content ($XMLPath)

$site = Get-SPSite $TaxonomySiteUrl
$session = new-object Microsoft.SharePoint.Taxonomy.TaxonomySession($site)
$termstore = $session.TermStores[$TermStoreData.termstore.name]
$TermStoreData.termstore.group

ForEach-Object {
## create the group
if ($termstore.Groups[$_.name] -eq $null)
{
$group = $termstore.CreateGroup($_.name);
Write-Host -ForegroundColor Cyan "Added group $_.name"
$_.termset

ForEach-Object {
## create the termset
$termset = $group.CreateTermSet($_.name)
Write-Host -ForegroundColor Cyan "Added termset $_.name"
SetTermsRecursive -termsetitem $termset -parentnode $_
}
}
}

$termstore.CommitAll()
Copy code below, save it as a .bat file to automatically run the powershell script
cd /d %~dp0
powershell -noexit -file ".\CreateTermSets.ps1" "%CD%"
pause

I have created another PowerShell script that reads through the XML file and delete the respective termsets and group:

Add-PsSnapin Microsoft.SharePoint.PowerShell

#Do not modify anything in the script from here onwards
function Get-ScriptDirectory
{
 $Invocation = (Get-Variable MyInvocation -Scope 1).Value
 Split-Path $Invocation.MyCommand.Path
}

#Solutions to Deploy
$XMLName = "ManagedMetaDataTermSets.xml"
$XMLPath = Join-Path (Get-ScriptDirectory) $XMLName
echo "Extracting information from the $XMLPath"

#Site Collection URL - Give your site collection url in quotation marks
$TaxonomySiteUrl = "http://localhost"

#Access the TermStore data
[xml]$TermStoreData = Get-Content ($XMLPath)
$site = Get-SPSite $TaxonomySiteUrl
$session = new-object Microsoft.SharePoint.Taxonomy.TaxonomySession($site)
$termstore = $session.TermStores[$TermStoreData.termstore.name]

$TermStoreData.termstore.group |
 ForEach-Object {
  ## create the group
  if ($termstore.Groups[$_.name] -ne $null)
  {
    # $_.termset | ForEach-Object {
    #$termstore.Groups[$_.name].TermSet
    Write-Host -ForegroundColor Cyan "Deleted $termsetCollection"

 #Get the Term Store Group object
 $groupName = $termstore.Groups[$_.name]

 #Get Term Sets from the Group
 $groupName.TermSets | ForEach-Object {
   $_.Delete();
 }

# #Iterate through each
# foreach($termSet in $termstore.Groups[$_.name].TermSets)
# {
#  $termSet.Delete();
# }

 #Finally delete the Group
 $termstore.Groups[$_.name].Delete()
   }
  }
 $termstore.CommitAll()

I hope this helps.