Saturday, July 3, 2010

Playing with PowerShell and timerjobs

The goal for this blog post is to display how easy it is to manage and update SharePoint timerjob through PowerShell.

For this demo I created a Timerjobtest class that inherits from SPJobDefinition with an empty and an overloaded constructor that takes a SPWebApplication as argument and custom property call Message.

clip_image002

The first thing I do is restart the timer service (SPTimerV4) to ensure I’m working with the same version of my DLL as the timer service has loaded.

Then I delete all old versions of my Timerjobtest timerjob, load my custom DLL so I can work with it in my PowerShell script, after that I create a SPSchedule object used later.

Documentation on a valid schedule object:
The type must be a valid SharePoint Timer service (SPTimer) schedule in the form of any one of the following schedules:
- Every 5 minutes between 0 and 59
- Hourly between 0 and 59
- Daily at 15:00:00
- Weekly between Fri 22:00:00 and Sun 06:00:00
- Monthly at 15 15:00:00
- Yearly at Jan 1 15:00:00

Now for some of the core functionality of this script where I’m create an object of my custom SPJobDefinition. The syntax is like this [Fully-Qualified Class Name] $myvarb = New-Object "Fully-Qualified Class Name" -ArgumentList argArry. A nice blog post on creating PowerShell object from .net class is this one http://www.lcbridge.nl/vision/2010/powershell.htm. Then I update the newly created timerjob object, with the schedule object and set a custom property and then I call the update method on the timer job object. At last a get the timer job back from SharePoint and select the custom property Message and then get the timer job again, to run the timerjob ones.

The scripts look like this:

#clear the console, for debug purposes
cls

#Restart the timer service
Restart-Service SPTimerV4

#Delete the old timerjob
Get-SPTimerJob | where { $_.TypeName -eq "Timerjobtest.Timerjobtest" } | % { $_.Delete() }

#Load my custom assembly, so it can be used in my script
[System.Reflection.Assembly]::Load("Timerjobtest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5bfcf02a97af8d35")

#Creating a SPSchedule object from a string
[Microsoft.SharePoint.SPSchedule] $schedule = [Microsoft.SharePoint.SPSchedule]::FromString("Every 10 minutes between 0 and 59")

#Crating an object of my custom SPJobDefinition
[Timerjobtest.Timerjobtest] $timerjobtest = New-Object "Timerjobtest.Timerjobtest" -ArgumentList (Get-SPWebApplication "http://win-ugka6ujlm21/")

#Sets the base properties of SPJobDefinition
$timerjobtest.Schedule = $schedule;
$timerjobtest.Name = "Timerjob test"
$timerjobtest.Title = "Timerjob test"

#Sets my custom property
$timerjobtest.Message = "powershell rocks!!!"

#Updates the timerjob
$timerjobtest.Update($true)

#Gets the Message property value from my timerjob
Get-SPTimerJob -Identity "Timerjob test" | Select "Message"

#Find my timerjob and run it ones
Get-SPTimerJob -Identity "Timerjob test" | Start-SPTimerJob

Happy PowerShelling

Sunday, May 23, 2010

SharePoint User Group Meeting

The 24th of June will the Danish SharePoint User Group (SPBG) organize a user group meeting, about Deployment Governance. Read more here (in Danish)

Thursday, April 15, 2010

Tuesday, April 6, 2010

Playing around with the ModalDialog framework

I played a bit around with the SharePoint 2010 modal dialog framework. My idea was to create a popup box where I could change the current webs title, both in the HTML DOM and persist the new title by updating the SPWeb.Title property. The first thing I needed was a link (a tag) that called some JavaScript that would create the popup window. So my link look like this <a href="javascript:createPop();" accesskey="a">createPop</a>. Just a normal link to execute a JavaScript function. The function call is creating a new JavaScript object of the type SP.UI.DialogOptions.

function createPop()
{
var options = {
url: '/SitePages/renameWeb.aspx',
tite: 'Rename current web',
allowMaximize: false,
showClose: true,
width: 800,
height: 600,
dialogReturnValueCallback: CloseCallback };
SP.UI.ModalDialog.showModalDialog(options);
}

I set the respective property and call SP.UI.ModalDialog.showModalDialog http://msdn.microsoft.com/en-us/library/ff410058(office.14).aspx. One of the things to be aware of is the value of dialogReturnValueCallback property, the value is the name of the function that will be called after the popup window is closed.

CloseCallback looks like this:
function CloseCallback(dialogResult, returnValue)
{
alert('dialogResult ' + dialogResult + '\nreturnValue ' + returnValue);

if(dialogResult == SP.UI.DialogResult.OK)´
{
SP.UI.Notify.addNotification('You clicked OK or save');
document.title = returnValue;
}

if(dialogResult == SP.UI.DialogResult.cancel)
SP.UI.Notify.addNotification('You clicked cancel!');
}

The function takes two arguments, first argument is the result of the "submit" dialog box e.g. If the dialog box is submitted with an OK or Cancel. The second argument is the result value, in my example the new title of the web.
But the real magic is on the page that is call by createPop().
On the renameWeb.aspx there is one textbox and three buttons.

<div>
<input type="text" id="newWebTitle" accesskey="t" />
<input type="button" value="Save" accesskey="o" onclick="updateTitle();"/>
<input type="button" value="Show current web info" accesskey="i" onclick="getWebProperties();"/>
<input value="Close" accesskey="c" onclick="ClosePopup();" name="close" title="Close" type="button" />
</div>

The first button is the submit button, that calls the JavaScript function updateTitle();

function updateTitle() {
var ctx = new SP.ClientContext.get_current();
this.web = ctx.get_web();
web.set_title(document.getElementById('newWebTitle').value);
this.web.update();
ctx.executeQueryAsync(Function.createDelegate(this, this.onUpdate), Function.createDelegate(this, this.onFail));
}

This function create a new ClientContext object http://msdn.microsoft.com/en-us/library/ff408569(office.14).aspx and a new web (server site SPWeb) object http://msdn.microsoft.com/en-us/library/ee550397(office.14).aspx , then set the title property of the web and call the update method. Last the function calls the executeQueryAsync http://msdn.microsoft.com/en-us/library/ff411085(office.14).aspx method on the context object to execute the batch that has build up. If the executeQueryAsync is executed without errors the onUpdate function is called.

function onUpdate(sender, args) {
alert('title updated');
SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.OK, document.getElementById('newWebTitle').value);
}

This function makes an alert message and then calls the commonModalDialogClose metode http://msdn.microsoft.com/en-us/library/ff409682(office.14).aspx, the first parameter is an enum http://msdn.microsoft.com/en-us/library/ff409060(office.14).aspx and the second parameter is the value to return. In this example the value from the textbox.

When the middle button is clicked the function getWebProperties is called. This function creates a ClientConext from the current web and if it loads without errors then the function onSuccess is called.

function getWebProperties() {
var ctx = new SP.ClientContext.get_current();
this.web = ctx.get_web();
ctx.load(this.web);
ctx.executeQueryAsync(Function.createDelegate(this, this.onSuccess), Function.createDelegate(this, this.onFail));
}

This function shows an alert box with the current webs info.

function onSuccess(sender, args) {
alert('web title:' + this.web.get_title() + '\n ID:' + this.web.get_id() + '\n Created Date:' + this.web.get_created());
}

The last button calls the ClosePopup function. This function calls the commonModalDialogClose function.

function ClosePopup()
{
SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.cancel, 'Cancelled clicked');
}

function onFail(sender, args) {
alert('failed to get list. Error:'+args.get_message());
}