Posted by: vamshikgovind | 12/23/2010

Powershell script for WSP deployment

The power shell commands to install solutions and activate the features are :
Add-SpSolution
Install-SPSolution
Enable-SPFeature

But what if there are a lot of wsps to be installed and each wsp had two or more features? That is a lot of adding, installing and activating !!!! I was faced with a similar situation recently, so I had written a small script to automate the whole process.

I used an inputs.xml file to define the solutions to be deployed and the features to be activated in each solution.

Input xml

The install script loops though each of the solution tag , adds it to the solution gallery, installs it either globally or to a web application based on the parameters and then activates it on the relevant site.

Add-PSSnapin Microsoft.sharePoint.PowerShell 

## Start Logging
$LogTime = Get-Date -Format dd-MM-yyyy_h-mm
$LogFile = “Log_InstallScript-$LogTime.txt”
start-Transcript -path $LogFile -Force

## Parsing the Input XML
write-host “Parsing the input file…”
[System.Xml.XmlDocument] $xd = new-object System.Xml.XmlDocument
$file = resolve-path (“Inputs.xml”)
$xd.load($file)
$InstallNode = $xd.selectSingleNode(“/Install”)
$RootWebUrl = $InstallNode.getAttribute(“Url”)
write-host “Deployment Target :” $RootWebUrl
$Solutions = $xd.selectNodes(“/Install/Solution”)
if($Solutions.count -gt 0)
{
foreach($Solution in $Solutions)
{
$SolutionName = $Solution.getAttribute(“Name”)
$SolutionPath = $Solution.GetAttribute(“Path”)
$SolutionType = $Solution.GetAttribute(“Type”)

write-host “Adding solution: ” $SolutionName
Add-SpSolution -LiteralPath “$SolutionPath\$SolutionName”
Start-Sleep -s 15

write-host “Installing solution: “$SolutionName
if($SolutionType -eq “Global”)
{
Install-SPSolution -Identity $SolutionName -GACDeployment -Force
}
else
{
Install-SPSolution -Identity $SolutionName -WebAppliaction $RootWebUrl -GACDeployment -Force
}
Start-Sleep -s 30

$Features = $Solution.SelectNodes(“Feature”)
if($features.count -gt 0)
{
foreach($Feature in $Features)
{

$FeatureName = $Feature.GetAttribute(“Name”)
$FeatureId = $Feature.GetAttribute(“ID”)
$Web = $Feature.GetAttribute(“Web”)

Write-Host “Enabling Feature :” $FeatureName “on ” $RootWebUrl/$Web
Enable-SPFeature -Identity $FeatureId -url “$RootWebUrl/$Web”
}
}
write-host “Completed deploying :” $SolutionName
}
}
else
{
write.host “No solutions found for deployment.”
}

## Stop Logging
Stop-Transcript

I have also written an un-installation script to de-activate the features, un-install and then remove the solutions in the reverse order.

Add-PSSnapin Microsoft.sharePoint.PowerShell

## Start Logging
$LogTime = Get-Date -Format dd-MM-yyyy_h-mm
$LogFile = “Log_InstallScript-$LogTime.txt”
start-Transcript -path $LogFile -Force

## Parsing the Input XML
write-host “Parsing the input file…”
[System.Xml.XmlDocument] $xd = new-object System.Xml.XmlDocument
$file = resolve-path (“Inputs.xml”)
$xd.load($file)
$InstallNode = $xd.selectSingleNode(“/Install”)
$RootWebUrl = $InstallNode.getAttribute(“Url”)
write-host “Deployment Target :” $RootWebUrl
$Solutions = $xd.selectNodes(“/Install/Solution”)
if($Solutions.count -gt 0)
{
for($x=$Solutions.count-1;$x -ge 0; $x–)
{

$Solution = $Solutions[$x]
$Features = $Solution.SelectNodes(“Feature”)
if($features.count -gt 0)
{
for($y=$Features.count-1;$y -ge 0;$y–)
{

$Feature = $Features[$y]
$FeatureName = $Feature.GetAttribute(“Name”)
$FeatureId = $Feature.GetAttribute(“ID”)
$Web = $Feature.GetAttribute(“Web”)

Write-Host “Disabling Feature :” $FeatureName “on ” $RootWebUrl/$Web
Disable-SPFeature -Identity $FeatureId -url “$RootWebUrl/$Web”
}
}

$SolutionName = $Solution.getAttribute(“Name”)
$SolutionPath = $Solution.GetAttribute(“Path”)
$SolutionType = $Solution.GetAttribute(“Type”)

$SolutionTocheck = Get-SPSolution -identity $SolutionName -ErrorAction:SilentlyContinue
if ($SolutionToCheck)
{
if ($SolutionToCheck.Deployed)
{
write-host “Retracting Solution: ” $SolutionName
if ($SolutionToCheck.ContainsWebApplicationResource)
{
Uninstall-SPSolution -identity $SolutionToCheck -allwebapplications -Confirm:$false
}
else
{
Uninstall-SPSolution -identity $SolutionToCheck -Confirm:$false
}
}
while ($SolutionToCheck.Deployed)
{
start-sleep -s 15
write-host “Waiting for Retraction to Complete”
}
start-sleep -s 15
write-host “Deleting Solution: ” $SolutionName
Remove-SPSolution $SolutionToCheck -Confirm:$false
}
}
}
else
{
write.host “No solutions found.”
}

## Stop Logging
Stop-Transcript

Remove-PsSnapin Microsoft.SharePoint.PowerShell

Posted by: vamshikgovind | 11/07/2010

Custom asset picker field in SharePoint 2010

Recently I had to build a custom url type field for my project, that uses an asset picker control to select the url of the asset (page or image in my case) . I have developed a lot of custom field types in Moss 2007, and was very confident I could do it in 4 hours. Apparently, the way the field values are rendered in SharePoint 2010 has changed… and my ignorance cost me more than a day to finish the field type :( .

If you have already created custom field types in Moss 2007 and now tried to install it onto SharePoint 2010 environment, you will realise that, the control might not be  rendering as expected. This is because, SharePoint 2010 does things differently !!!

Here is a quick explanation of how I have created my custom field type:

  1. Create a custom field type class.
  2. Create a custom field control class.
  3. Create a field definition xml  and save it into 14 hive/templates/xml/fldtypes_xxx.xml.
  4. Create a field rendering template xml and save it into 14 hive/ templates/ layouts/ xsl/ fldtypes_xxx.xsl.

Custom field type :

public class CustomURLSelectorFieldClass : SPFieldUrl
{
public CustomURLSelectorFieldClass(SPFieldCollection fields, string fieldName)
: base(fields, fieldName)
{
}
public CustomURLSelectorFieldClass(SPFieldCollection fields, string typeName, string displayName)
: base(fields, typeName, displayName)
{
}
public override BaseFieldControl FieldRenderingControl
{
get
{
BaseFieldControl control = new CustomURLSelectorControlClass();
control.FieldName = base.InternalName;
return control;
}
}
public override object GetFieldValue(string value)
{
return value;
}
}

Create Control:

public class CustomURLSelectorControlClass : BaseFieldControl
{
protected AssetUrlSelector urlSelector;
protected TextBox urlText;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
// Set the value if this is a postback.
if ((this.Page.IsPostBack) && (base.ControlMode == SPControlMode.Edit || base.ControlMode == SPControlMode.New))
{
SPFieldUrlValue mcv = new SPFieldUrlValue();
mcv.Url= urlSelector .AssetUrl;
mcv.Description = urlText.Text;
this.ListItemFieldValue = mcv;
}
}

protected override void CreateChildControls()
{
base.CreateChildControls();
// Add the asset picker when in edit or new mode.
if (base.ControlMode == SPControlMode.Edit || base.ControlMode == SPControlMode.New)
{
urlSelector = new AssetUrlSelector();
urlText = new TextBox();
this.Controls.Add(urlSelector);
this.Controls.Add(new LiteralControl(“<br/>”));
this.Controls.Add(urlText);
}
}

public override void Validate()
{
if (ControlMode == SPControlMode.Display || !IsValid)
{
return;
}
base.Validate();
if (Field.Required)
{
if ((this.Value == null))
{
this.ErrorMessage = Field.Title + ” must have a value.”;
IsValid = false;
return;
}
else if (this.Value != null)
{
SPFieldUrlValue mcv = (SPFieldUrlValue)this.Value;
if (mcv.Description.Length == 0)
{
this.ErrorMessage = Field.Title + ” must have a title”;
IsValid = false;
return;
}
if (mcv.Url.Length == 0)
{
this.ErrorMessage = Field.Title + ” must have a url.”;
IsValid = false;
return;
}
}
}
}

public override object Value
{
get
{
SPFieldUrlValue URLValue = new SPFieldUrlValue();
URLValue.Description = urlText.Text;
URLValue.Url = urlSelector.AssetUrl;
return URLValue;
}
set
{
SPFieldUrlValue URLValue = (SPFieldUrlValue)value;
urlText.Text = URLValue.Description;
urlSelector.AssetUrl = URLValue.Url;
}
}
}

Create the field definition xml file:

Usually we will have the render  patterns defined in this xml, that defines how the control will be rendered in various modes. In SharePoint 2010, they are moved to another file. Though some blogs suggest that having the tags

<Field Name=”AllowBaseTypeRendering“>TRUE</Field>
<Field Name=”CAMLRendering“>TRUE</Field>

will allow you to define the rendering patterns in the same xml, I was never able to get this working !! So I have them defined in another file as mentioned in the next step.

<?xml version=”1.0″ encoding=”utf-8″ ?>
<FieldTypes>
<FieldType>
<Field Name=”TypeName”>CustomURLSelectorFieldClass</Field>
<Field Name=”ParentType”>URL</Field>
<Field Name=”TypeDisplayName”>Custom URL Selector</Field>
<Field Name=”TypeShortDescription”>Custom URL Selector</Field>
<Field Name=”UserCreatable”>TRUE</Field>
<Field Name=”FieldTypeClass”>
XXXXX.CustomURLSelectorFieldClass, XXXX, Version=1.0.0.0, Culture=neutral, PublicKeyToken=10e1ca627a44ef9d
</Field>
</FieldType>
</FieldTypes>

Create the field’s rendering template xsl file:

<xsl:stylesheet xmlns:x=”http://www.w3.org/2001/XMLSchema” xmlns:d=”http://schemas.microsoft.com/sharepoint/dsp” version=”1.0″ exclude-result-prefixes=”xsl msxsl ddwrt” xmlns:ddwrt=”http://schemas.microsoft.com/WebParts/v2/DataView/runtime” xmlns:asp=”http://schemas.microsoft.com/ASPNET/20″ xmlns:__designer=”http://schemas.microsoft.com/WebParts/v2/DataView/designer” xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” xmlns:msxsl=”urn:schemas-microsoft-com:xslt” xmlns:SharePoint=”Microsoft.SharePoint.WebControls” xmlns:ddwrt2=”urn:frontpage:internal”>
<xsl:template match=”FieldRef[@FieldType='CustomURLSelectorFieldClass']” mode=”URL_body”>
<xsl:param name=”thisNode” select=”.” />
<xsl:variable name=”url” select=”$thisNode/@*[name()=current()/@Name]” />
<xsl:variable name=”desc” select=”$thisNode/@*[name()=concat(current()/@Name, '.desc')]” />
<xsl:choose>
<xsl:when test=”$url=””>
<xsl:if test=”$desc=””>
<xsl:value-of select=”$desc”/>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<a href=”{$url}” >
<xsl:choose>
<xsl:when test=”$desc=””>
<xsl:value-of select=”$url”/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select=”$desc”/>
</xsl:otherwise>
</xsl:choose>
</a>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Posted by: vamshikgovind | 06/13/2010

Install and configure TFS 2010, SharePoint 2010

Firstly, Many thanks to Brian and Codeplex for the cool powershell script that can do the unatttended Sharepoint 2010 installation. you can find the scripts here : http://autospinstaller.codeplex.com/.

Here is what I have done:

  1. Install SQL server, and patch up the server with the latest service packs and hotfixes.
  2. Configure Analysis Services
  3. Configure the Reporting server to run in native mode ( very important if you want TFS reports to work)
  4. Install SharePoint
  5. Install TFS
  6. Configure SSS on Sharepoint.
  7. Configure TFS with the enterprise application ID.

For steps 6 and 7 I have followed this blog : http://blogs.msdn.com/b/zhengtu/archive/2010/02/03/setup-sss-for-vsts-2010-dashboards.aspx.

After following this steps , if you encounter any errors viewing the reports here is a great blog that can help you to troubleshoot: http://blogs.msdn.com/b/granth/archive/2009/12/03/tfs2010-troubleshooting-sharepoint-dashboards-data-source-problems.aspx

Few more interesting links:http://social.msdn.microsoft.com/Forums/en-US/tfsadmin/thread/4acefd21-725d-4107-ba9c-bdfa8fe54012

http://social.msdn.microsoft.com/Forums/en-US/tfsadmin/thread/6d427919-97e6-45e3-a109-4fd0978e6d05

When you are trying to use SharePoint meta data as document properties in MS Word 2003 to display the information, you may find that the date fields are displayed  in this format : 1995-10-22 00:00:00 .

As per the KB article http://support.microsoft.com/kb/304387, this seems to be a known issue with MS Office 2003.

To change the date format, I had to follow the following steps.

1. Press Alt + F9 to reveal the code MS Word uses to display the field value. It should look something like this: { DOCPROPERTY “FIELD NAME” \* MERGEFORMAT }

2. Change it as : { DOCPROPERTY “FIELD NAME”  \@ “D-M-YYYY” \* MERGEFORMAT}.  the text “D-M-YYYY” can be any valid date format string.

3. Save the document.

4. Press Alt + F9 again to go back to the normal mode of the document.

5. Select the field and press F9 to refresh the formatted value.

Categories

Follow

Get every new post delivered to your Inbox.