2010-11-19

SharePoint Client Model from Powershell

I have seen a few people attempt to use the client access model from powershell, but they have mostly failed. The reason being, powershell does not allow extension methods. You can get most of the way, but when you try to call Load() or ExecuteQuery() it fails. I really like being able to do things in powershell scripts, as they are super easy to edit/change when you need. Surely i could get the client model to work from scripts.

I knew that powershell allows you compile and execute c# inline, hopefully i could use that feature. It was pretty easy to throw together a test, as it was just c# i was using.

The next problem i encountered; was powershell not loading the client access assemblies. No matter what i tried, i could only get powershell to load them IF the dlls were in the same directory as the powershell executable. Well for me that is not an ideal solution, i like to be able to copy a directory somewhere, and it just works.

What i found was a way you can override the powershell assembly loading
http://stackoverflow.com/questions/2664028/how-can-i-get-powershell-added-types-to-use-added-types

Then it was just a matter of intergrating it with the rest of the script.

Add-Type -Language CSharpVersion3 -TypeDefinition @' 
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace Internal.Powershell {
public static class AssemblyResolver {
private static Dictionary<string, string> _assemblies = new Dictionary<string,string>(StringComparer.CurrentCultureIgnoreCase);
static AssemblyResolver() {
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(delegate(object sender, ResolveEventArgs args) {
var assemblyName = new AssemblyName(args.Name);
if (_assemblies.ContainsKey(assemblyName.Name)) {
return Assembly.LoadFrom(_assemblies[assemblyName.Name]);
}
return null;
});
}
public static void AddAssemblyLocation(string path) {
_assemblies.Add(Path.GetFileNameWithoutExtension(path), path);
}
}
}
'@
[Internal.Powershell.AssemblyResolver]::AddAssemblyLocation("..\..\lib\Microsoft.SharePoint.Client.Runtime.dll")
[Internal.Powershell.AssemblyResolver]::AddAssemblyLocation("..\..\lib\Microsoft.SharePoint.Client.dll")

$ReferencedAssemblies = @(
"Microsoft.SharePoint.Client.Runtime",
"Microsoft.SharePoint.Client"
)
$TypeDefinition = @"
using System;
using System.Collections.Generic;
using System.Net;
using System.Linq;
using System.IO;
using System.Text;
using Microsoft.SharePoint.Client;
namespace Internal.Powershell {
public static class SharePointClient {
public static void Main() {
using (ClientContext client = new ClientContext("http://url")) {
client.AuthenticationMode = ClientAuthenticationMode.Default;
client.Credentials = new NetworkCredential("username", "password", "domain");
var web = client.Web;
client.Load(web,
item => item.Title,
item => item.Description);
client.ExecuteQuery();
Console.WriteLine(web.Title);
Console.WriteLine(web.Description);
}
}
}
}
"@
Add-Type -ReferencedAssemblies $ReferencedAssemblies -TypeDefinition $TypeDefinition -Language CSharpVersion3
[Internal.Powershell.SharePointClient]::Main()

2010-11-18

SharePoint 2010 Team Site All Features

I needed to duplicate a Team Site definition, including all the feature staplings, posting it here in case anyone needs it

Team Site (STS#0) Features

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\SiteTemplates\sts\xml\ONET.XML

BasicWebParts
Three-state Workflow Feature
TeamCollab
MobilityRedirect
WikiPageHomePage

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\FEATURES\BaseSiteStapling\basesitestapling.xml

BaseSite
-LocalSiteDirectoryControl
-PortalsLayouts
-WebPartAdderGroups
ReceiverAssembly="Microsoft.SharePoint.Portal, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
ReceiverClass="Microsoft.SharePoint.Portal.SPSWebPartAdderFeatureReceiver"
-DocumentRoutingResources
-RecordResources
BaseWeb
-RelatedLinksScopeSettingsLink
-SlideLibrary
AssetLibrary
EnchancedTheming
Reporting
LocationBasedPolicy
MetaDataNav
Rating

Page.ParseControl with SharePoint Sandbox

There are many posts explaining that you cannot use visual web parts with the sharepoint sandbox. So this means you have to build your controls by hand, which is not that fun. Thinking I was smart, I tried to use the Page.LoadControl method to parse a string of controls. This way i could author the html easily.

Turns out though, that doesn't work. You get this error message in your webpart.






System.ArguementNullException: Value cannot be null. Parameter name: virtualPath at System.Web.VirtualPath.Create()

Which basically means that the process that executes the sandbox code is not a full ASP.NET pipeline, or doesn't have all the context/access object it needs. This is probably as security feature too.

Oh well, back to coding the control tree by hand.

Package SharePoint Project without SharePoint

For my current project, i was required to develop a sandbox web part. Normally i would just develop it in visual studio in my sharepoint vm. Working in the sharepoint vm though is not that fun, it can't use your local computer's full resources. Visual studio seems to lag when IIS takes all the memory.

The process I was using was:
1. Compile in VS
2. Package in VS
3. De-activate in Browser
4. Upload in Browser
5. Activate in Browser
6. Test in Browser

It would work a whole lot better if I could do that locally. If it was possible. With MOSS 2007 you could not open the sharepoint project on a machine without sharepoint, basically because vseex would not install. But now you can, as you can deploy the sharepoint components to a machine that does not have sharepoint installed.

When i tried to package initially though, it failed with a generic package failed error

By chance i figured out that if you delete the csproject.user file, visual studio 2010 will package the sharepoint wsp. When you dont have a csproject.user opening the project will show this error, which is what you want.








The Site URL property of the project has not been set. In the Properties window, enter the URL for the local SharePoint server.

2010-11-07

SharePoint Designer Custom Action in Dialog

SharePoint designer has a great way to create custom actions. There are many help posts out there on how to do that.
http://blog.furuknap.net/adding-custom-actions-in-sharepoint-designer-2010
You have three options to select "Navigate to form", "Initiate workflow" and "Navigate to URL"
The trouble with these actions and options (well the ones on the View Ribbon) is that they do not open in the dialog box

There a heaps more posts on creating custom actions that open in dialogs
http://www.chakkaradeep.com/post/Using-the-SharePoint-2010-Modal-Dialog.aspx
http://www.vinodunny.com/blog/post/Application-Page-Ribbon-Dialogs-on-SharePoint-2010.aspx
http://jomit.blogspot.com/2009/12/dialog-platform-in-sharepoint-2010-how.html

The problem with those though, is that the action must be defined before hand.
I really like how sharepoint designer allows you to configure the url on the fly.
There must be a way to combine the two ways.

I was hoping that the "Navigate to URL" option would be a href.
So i tried a simple javascript:alert("hi") for an action.
Sure enough i got an alert box.
From there it was just a matter of figuring out the showModalDialog command, and putting it on one line.

This action is great to use with the StartWorkflow component http://spc3.codeplex.com/

For View Ribbon actions
javascript:SP.UI.ModalDialog.showModalDialog({url:"{SiteUrl}/_layouts/Com.CodePlex.SPC3/StartWorkflow.aspx?List={ListId}&ItemID={SelectedItemId}&Workflow=WorkflowName",dialogReturnValueCallback: function(dialogResult, returnValue) { SP.UI.ModalDialog.RefreshPage(SP.UI.DialogResult.OK) }})

And for Display Form Ribbon actions
{SiteUrl}/_layouts/Com.CodePlex.SPC3/StartWorkflow.aspx?List={ListId}&ItemID={ItemId}&Workflow=WorkflowName