tag:blogger.com,1999:blog-2653081776865224152024-02-26T09:35:26.407-08:00SharePoint UKFrom Tahoe TohereDave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.comBlogger28125tag:blogger.com,1999:blog-265308177686522415.post-69298106280389920162014-08-22T11:17:00.000-07:002014-10-08T02:38:18.330-07:00SharePoint Solution Setup Package MSIAfter a few more hours of head banging VS2010 setup projects I decided there has to be an easier way.<br />
It doesn't help that the custom actions can only be dll, exe and vbs, or that the post build command interface is a bit lousy - when it works!<br />
<br />
I was toying with the idea of running a vbs to call the powershell to install and uninstall a wsp file, but we are dealing with 64bit and vbscript calls to ps files don't play nice with 64bit!<br />
<br />
So I did a little hunting around for a solution and found the wonderful PS2EXE on codeplex.<br />
<br />
The plan was to convert my ps1 files to exe's and then have my msi project call them as exe's...straightforward you would think....perhaps.<br />
<br />
So here's how I progressed :<br />
<br />
1. Make sure you put full paths into your ps1 files - you can't use contextual paths as the installer runs in the system32 context.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://dl.dropbox.com/u/49527080/sharepoint/msi/msi3.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="353" src="https://dl.dropbox.com/u/49527080/sharepoint/msi/msi3.jpg" width="640" /></a></div>
<br />
2. Covert your ps1 files to exe's using the PS2EXE<br />
<br />
3. Add your files into your VS setup project<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://dl.dropbox.com/u/49527080/sharepoint/msi/msi1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="150" src="https://dl.dropbox.com/u/49527080/sharepoint/msi/msi1.jpg" width="640" /></a></div>
<br />
4. Add your exe files created from PS2EXE into the custom actions sections<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://dl.dropbox.com/u/49527080/sharepoint/msi/msi2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="172" src="https://dl.dropbox.com/u/49527080/sharepoint/msi/msi2.jpg" width="640" /></a></div>
<br />
5. Make sure you mark your custom actions files as false for the installerclass<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://dl.dropbox.com/u/49527080/sharepoint/msi/msi4.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="428" src="https://dl.dropbox.com/u/49527080/sharepoint/msi/msi4.jpg" width="640" /></a></div>
<br />
6. Ensure your target platform is set to 64bit<br />
<div class="separator" style="clear: both; text-align: -webkit-auto;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://dl.dropbox.com/u/49527080/sharepoint/msi/msi5.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://dl.dropbox.com/u/49527080/sharepoint/msi/msi5.jpg" width="250" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
So when you run your setup.exe the final step of the install will execute your powershell files that have been converted to exe's.</div>
<div class="separator" style="clear: both; text-align: left;">
Although this is probably not the best solution for some powershell files, its perfect for solutions (wsp's).</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Hope this saves your msi frustrations!</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://dl.dropbox.com/u/49527080/sharepoint/msi/msi6.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="514" src="https://dl.dropbox.com/u/49527080/sharepoint/msi/msi6.jpg" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://dl.dropbox.com/u/49527080/sharepoint/msi/msi7.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="398" src="https://dl.dropbox.com/u/49527080/sharepoint/msi/msi7.jpg" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br />Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com1tag:blogger.com,1999:blog-265308177686522415.post-65458286023151197142014-06-12T11:25:00.000-07:002014-10-08T02:21:36.255-07:00SshhhharePointMany of my engagements with customers and indeed other consultancies invariably have an 'intranet' element within the requirements.<br />
<br />
I remember a while back when SP2010 was released and many of use realised that demonstrating the OOB user interface was not the best approach; where the customers response was invariably muted and unimpressed.<br />
<br />
So I have been considering how we approach SharePoint engagements and indeed how we could approach them with a more practical business approach rather than a technical one.<br />
<br />
Many of us are 'techies' - SharePoint solutions architects, SharePoint solutions developers and so on.<br />
Many of us are also heavily engaged in SharePoint presales and SharePoint customer demos.<br />
<br />
One thing we all have in common to some degree is that we are proud to be 'SharePoint' people....we love the product, love the architecture, love its nuances and all of the rich business functionality that it provides.<br />
<br />
So it comes as no surprise that when we engage with customers we engage with them with our SharePoint hat on.<br />
We are going to solve our customers business problems, inefficiencies and overheads with a SharePoint solution....and we tell them that.<br />
<br />
But should we take our SharePoint hat off?<br />
<br />
The phrase or word 'SharePoint' has many connotations depending on who you engage with. In some information management communities it is treated as the black death, in others it is the fix for world hunger, world peace....you get the idea!<br />
<br />
When a user fills in their timesheets then don't think 'My timesheet has been created by system X'.<br />
So it makes sense that when a user interacts with their intranet or information management system they don't consider what system it has been created on.<br />
<br />
What is important to the user is that it makes their lives easier, enables them to work more efficiently and to be more productive during their working day.<br />
<br />
What is important to the business is more efficient users = more efficient business = cost reduction through efficiency.<br />
<br />
So what is the best approach with a SharePoint solution for the client?<br />
<br />
We should be engaging with the client without SharePoint specifics...rather with solution specifics.<br />
<br />
Should the user care that it's SharePoint...absolutely not.<br />
Should the user know that it is SharePoint ...it shouldn't matter what it is.<br />
<br />
We develop our thoughts around a solution based upon SharePoint and that's a given as we are going to use SharePoint as our platform of choice.<br />
<br />
But we often communicate the solution in terms of SharePoint but is that really the best way to present a solution?<br />
<br />
Perhaps we should present the solution as a solution...I know that sounds obvious but in reality many of use stick our SharePoint hat on and start talking SharePoint solutions; SharePoint specifics. <br />
<br />
Obviously this may depend on the level of engagement, but how often does a records manager, a CEO or an information worker have to know the underlying technology?<br />
<br />
Sure the IT team will have a vested interest but engaging with the end users and information workers shouldn't require a SharePoint hat, in fact it may just muddy the waters.<br />
<br />
Is that really SharePoint?<br />
Does it really matter?<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com1tag:blogger.com,1999:blog-265308177686522415.post-76361474400179303072013-10-24T05:42:00.000-07:002013-10-01T08:36:41.008-07:00Defrag SharePoint DB IndexesBeen doing some research into the defrag rates of SharePoint content DB's in order to maximise performance<br />
<br />
I ran some sime commands to find out the level of defragmentation....<br />
<br />
DBCC SHOWCONTIG - this will show you the level of defragmentation in your DB's<br />
<br />
<br />
<br />
DBCC SHOWCONTIG scanning 'WorkflowAssociation' table...<br />
Table: 'WorkflowAssociation' (1490104349); index ID: 1, database ID: 7<br />
TABLE level scan performed.<br />
- Pages Scanned................................: 5<br />
- Extents Scanned..............................: 5<br />
- Extent Switches..............................: 4<br />
- Avg. Pages per Extent........................: 1.0<br />
- Scan Density [Best Count:Actual Count].......: 20.00% [1:5]<br />
- Logical Scan Fragmentation ..................: 80.00%<br />
- Extent Scan Fragmentation ...................: 80.00%<br />
- Avg. Bytes Free per Page.....................: 2001.2<br />
- Avg. Page Density (full).....................: 75.28%<br />
<br />
<br />
The following SQL will allow you to set the defrag limit and defrag all your tables.<br />
<br />
*Perform a 'USE <database name="">' to select the database in which to run the script.*/<br />-- Declare variables<br />SET NOCOUNT ON;<br />DECLARE @tablename varchar(255);<br />DECLARE @execstr varchar(400);<br />DECLARE @objectid int;<br />DECLARE @indexid int;<br />DECLARE @frag decimal;<br />DECLARE @maxfrag decimal;<br /><br />-- Decide on the maximum fragmentation to allow for.<br />SELECT @maxfrag = 30.0;<br /><br />-- Declare a cursor.<br />DECLARE tables CURSOR FOR<br /> SELECT TABLE_SCHEMA + '.' + TABLE_NAME<br /> FROM INFORMATION_SCHEMA.TABLES<br /> WHERE TABLE_TYPE = 'BASE TABLE';<br /><br />-- Create the table.<br />CREATE TABLE #fraglist (<br /> ObjectName char(255),<br /> ObjectId int,<br /> IndexName char(255),<br /> IndexId int,<br /> Lvl int,<br /> CountPages int,<br /> CountRows int,<br /> MinRecSize int,<br /> MaxRecSize int,<br /> AvgRecSize int,<br /> ForRecCount int,<br /> Extents int,<br /> ExtentSwitches int,<br /> AvgFreeBytes int,<br /> AvgPageDensity int,<br /> ScanDensity decimal,<br /> BestCount int,<br /> ActualCount int,<br /> LogicalFrag decimal,<br /> ExtentFrag decimal);<br /><br />-- Open the cursor.<br />OPEN tables;<br /><br />-- Loop through all the tables in the database.<br />FETCH NEXT<br /> FROM tables<br /> INTO @tablename;<br /><br />WHILE @@FETCH_STATUS = 0<br />BEGIN<br />-- Do the showcontig of all indexes of the table<br /> INSERT INTO #fraglist <br /> EXEC ('DBCC SHOWCONTIG (''' + @tablename + ''') <br /> WITH FAST, TABLERESULTS, ALL_INDEXES, NO_INFOMSGS');<br /> FETCH NEXT<br /> FROM tables<br /> INTO @tablename;<br />END;<br /><br />-- Close and deallocate the cursor.<br />CLOSE tables;<br />DEALLOCATE tables;<br /><br />-- Declare the cursor for the list of indexes to be defragged.<br />DECLARE indexes CURSOR FOR<br /> SELECT ObjectName, ObjectId, IndexId, LogicalFrag<br /> FROM #fraglist<br /> WHERE LogicalFrag >= @maxfrag<br /> AND INDEXPROPERTY (ObjectId, IndexName, 'IndexDepth') > 0;<br /><br />-- Open the cursor.<br />OPEN indexes;<br /><br />-- Loop through the indexes.<br />FETCH NEXT<br /> FROM indexes<br /> INTO @tablename, @objectid, @indexid, @frag;<br /><br />WHILE @@FETCH_STATUS = 0<br />BEGIN<br /> PRINT 'Executing DBCC INDEXDEFRAG (0, ' + RTRIM(@tablename) + ',<br /> ' + RTRIM(@indexid) + ') - fragmentation currently '<br /> + RTRIM(CONVERT(varchar(15),@frag)) + '%';<br /> SELECT @execstr = 'DBCC INDEXDEFRAG (0, ' + RTRIM(@objectid) + ',<br /> ' + RTRIM(@indexid) + ')';<br /> EXEC (@execstr);<br /><br /> FETCH NEXT<br /> FROM indexes<br /> INTO @tablename, @objectid, @indexid, @frag;<br />END;<br /><br />-- Close and deallocate the cursor.<br />CLOSE indexes;<br />DEALLOCATE indexes;<br /><br />-- Delete the temporary table.<br />DROP TABLE #fraglist;<br />GO</database>Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com1tag:blogger.com,1999:blog-265308177686522415.post-13809380044069277492013-05-02T11:27:00.001-07:002013-05-02T11:27:12.160-07:00SharePoint Records Repository & In Place Records Thoughts Part 2Following on from <a href="http://sharepoint-uk.blogspot.co.uk/2013/04/sharepoint-records-repository-in-place.html" target="_blank">Part 1</a><br />
<br />
Lets consider a simple example of in place v central records when it comes to aggregated content.<br />
<br />
So imagine we have an image that will constitute a record at some point within it's lifecycle.<br />
The sensible thing to do is create a content type for the image and define an appropriate information management policy etc.<br />
<br />
So we are ready for the image to be published and viewed within our organisation. We may go through some approval or workflows and finally when all the business processes have been met, we declare it as a record....fine, that's the correct thing to do.<br />
<br />
So we have a library containing our image content types and we use an image from the library in some content within our organisation - in this simple example we are using it within a publishing page layout.<br />
<br />
So here's our image in all it's glory.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://content.screencast.com/users/D4v3/folders/Jing/media/a32171f4-7cbc-4a06-b221-7efb6868df5f/ct_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="436" src="http://content.screencast.com/users/D4v3/folders/Jing/media/a32171f4-7cbc-4a06-b221-7efb6868df5f/ct_1.png" width="640" /></a></div>
<br />
And here is our image content type in its document library.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://content.screencast.com/users/D4v3/folders/Jing/media/92689b6d-c252-4628-877a-41dc84499577/ct_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="384" src="http://content.screencast.com/users/D4v3/folders/Jing/media/92689b6d-c252-4628-877a-41dc84499577/ct_2.png" width="640" /></a></div>
<br />
So we now want to declare this as a record...fine.<br />
<br />
In a central repository model we simple send to > records center and we are left with a nice link.<br />
Great its now a record in our central repository.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://content.screencast.com/users/D4v3/folders/Jing/media/01440b6e-6a96-47a4-a584-7c03214f1f0b/ct_3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="476" src="http://content.screencast.com/users/D4v3/folders/Jing/media/01440b6e-6a96-47a4-a584-7c03214f1f0b/ct_3.png" width="640" /></a></div>
<br />
And back to the home page.<br />
Oh!!!!!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://content.screencast.com/users/D4v3/folders/Jing/media/a3700da5-e5e2-4086-a230-6d89d2d2d2d5/ct_4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="460" src="http://content.screencast.com/users/D4v3/folders/Jing/media/a3700da5-e5e2-4086-a230-6d89d2d2d2d5/ct_4.png" width="640" /></a></div>
If we are using in place records management we can simple declare the record in situ.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://content.screencast.com/users/D4v3/folders/Jing/media/1a0129ae-a21a-45c4-b38b-fde2f15a3777/ct_4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="366" src="http://content.screencast.com/users/D4v3/folders/Jing/media/1a0129ae-a21a-45c4-b38b-fde2f15a3777/ct_4.png" width="640" /></a></div>
<br />
And our image will not be removed.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://content.screencast.com/users/D4v3/folders/Jing/media/902dbf5f-0a78-4e6d-9e28-2b2cf7bc4045/ct_5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="586" src="http://content.screencast.com/users/D4v3/folders/Jing/media/902dbf5f-0a78-4e6d-9e28-2b2cf7bc4045/ct_5.png" width="640" /></a></div>
Although this is a simple example it is an effective one.<br />
Any content within your organisation is potentially a record, be it images, documents, etc etc.<br />
As it is business content then it will probably come under the remit of some records management policy.<br />
<br />
So when planning your records management architecture it is worth bearing in mind how you will aggregate any records-based content to other/all areas of your farm.<br />
<br />
In place or central repository?<br />
Plan, plan, plan !!!!!<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com0tag:blogger.com,1999:blog-265308177686522415.post-8506128429014054062013-05-02T08:38:00.001-07:002013-05-02T08:38:34.298-07:00SharePoint Event Receivers & Expiration PolicyMore event receiver fun this week.<br />
<br />
I've been writing some synchronous event receivers this week, one of which has been causing a headache, name ItemDeleting.<br />
<br />
The event receiver acts correctly when users manually delete an item...great<br />
The event receiver also acts correctly when a workflow deletes an item...great<br />
<br />
If an item has an information management policy attached to it 'permanently delete' or 'move to recycle bin', the Expiration Policy timer job will kick in and delete the item.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://content.screencast.com/users/D4v3/folders/Jing/media/513b0471-d7c9-4611-81b3-c2a8ab6082f1/2013-05-02_1636.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="163" src="http://content.screencast.com/users/D4v3/folders/Jing/media/513b0471-d7c9-4611-81b3-c2a8ab6082f1/2013-05-02_1636.png" width="400" /></a></div>
<br />
<br />
<strong>BUT </strong>the event receiver will not be fired when the timer job executes!!!!!!<br />
<br />
<strong>Cause </strong>: when the Expiration Policy timer job deletes an item it actually does an SPItem.SystemUpdate(); rather than SPItem.Update();<br />
<br />
<br />
Worth bearing in mind if you need to capture an event driven from the Expiration policy timer job.Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com1tag:blogger.com,1999:blog-265308177686522415.post-71259182576517065892013-04-23T12:10:00.002-07:002013-04-23T12:17:11.787-07:00SharePoint Records Repository & In Place Records Thoughts Part 1Something I've been thinking about for a while now and finally decided to get something on record (see what I did there).<br />
<br />
Records management in SharePoint is an emotive subject and I'm not going to cover the rights and wrongs of RM implementation.<br />
<br />
I have had many discussions on the implementation of SharePoint records management with regards to In Place Records and a Central Repository approach, and while I agree each has it merits, one thing that many people don't consider is what actually constitutes a record and how do we manage a record once we realise that it's not just about documents.<br />
<br />
So firstly lets identify what a record actually is......<br />
<br />
Records Management ISO defines records as:<br />
<div>
<em>Information created, received, and maintained as evidence and information by an organization or person, in pursuance of legal obligations or in the transaction of business.</em></div>
<br />
ICA's definition of a record as:<br />
<em>recorded information produced or received in the initiation, conduct or completion of an institutional or individual activity and that comprises content, context and structure sufficient to provide evidence of the activity.</em><br />
<br />
In both the above definitions a record is defined as <strong>a piece of information</strong> but for some reason we all <br />
think of a record as a document or group of documents. e.g. word, pdf, cad, excel etc etc.<br />
<br />
This is where the SharePoint content types really do come to the fore. As we all know a content type can be any piece of <strong>information</strong> within a farm.<br />
<br />
So it's easy...lets create a content type for each piece of information (impractical but possible).<br />
<div>
Lets take a scenario.</div>
Great Corp have an intranet and like most intranets they have news on the homepage.<br />
<br />
Now this news may be an announcement content type or a custom content type, but very rarely is it a document, but it is a <strong>record</strong>.<br />
<br />
But hey that's fine we will create a Great Corp News content type and use that as our news information container.<br />
<br />
We'll even put our records managers hat on and give it an information policy, auditing, expiration and a workflow.<br />
<br />
See it's dead easy given the wonderful functionality that SharePoint gives us.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://content.screencast.com/users/D4v3/folders/Jing/media/5b95b24a-1df8-4394-a8e3-49302cf1449d/2013-04-23_1909.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="403" src="http://content.screencast.com/users/D4v3/folders/Jing/media/5b95b24a-1df8-4394-a8e3-49302cf1449d/2013-04-23_1909.png" width="640" /></a></div>
<br />
<div>
So now we can add the news, as a content type, to our homepage.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://content.screencast.com/users/D4v3/folders/Jing/media/c80e7492-e32c-4992-a438-2d6eac26d63d/2013-04-23_1911.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="308" src="http://content.screencast.com/users/D4v3/folders/Jing/media/c80e7492-e32c-4992-a438-2d6eac26d63d/2013-04-23_1911.png" width="640" /></a></div>
<br />
<br />
Ok so now lets imagine that this piece of news is important, in fact its vital and can be classed as a vital record.<br />
<br />
It may be a safety related piece of news or something similar which has to be managed following our formal records management process.<br />
<br />
So lets declare it as a record, it's the sensible thing to do.<br />
<br />
<strong>Scenario 1 - In Place Records</strong><br />
<br />
We can declare the news item (vital record) as a record using in place records management.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://content.screencast.com/users/D4v3/folders/Jing/media/eea77146-a04a-40f7-8d7c-59a8d4afb696/2013-04-23_1915.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="442" src="http://content.screencast.com/users/D4v3/folders/Jing/media/eea77146-a04a-40f7-8d7c-59a8d4afb696/2013-04-23_1915.png" width="640" /></a></div>
<br />
The vital record news item is now locked and cannot be edited or changed, which is absolutely correct.<br />
<br />
<strong>Scenario 2 - Central Records Repository</strong><br />
<strong></strong><br />
Ok so lets declare this news item as a record inside our central repository<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://content.screencast.com/users/D4v3/folders/Jing/media/2d8aaf46-c241-43b1-aea7-0cd478875041/2013-04-23_1919.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="164" src="http://content.screencast.com/users/D4v3/folders/Jing/media/2d8aaf46-c241-43b1-aea7-0cd478875041/2013-04-23_1919.png" width="640" /></a></div>
Oh wait a minute, we can only send document based records to our central repository.<br />
<br />
OK it's not the end of the world, we can use our content type information management policy, workflow or similar to move it to the records centre.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://content.screencast.com/users/D4v3/folders/Jing/media/bd390af5-99a2-4f92-947f-e9c8a5226dd8/2013-04-23_1926.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="http://content.screencast.com/users/D4v3/folders/Jing/media/bd390af5-99a2-4f92-947f-e9c8a5226dd8/2013-04-23_1926.png" width="608" /></a></div>
<br />
<br />
We will have to move it and leave a link. If we copy it we will have two identical records in two different places in our farm...not good!<br />
<br />
<strong>Gotcha</strong>....although the information management policy will let us set this rule, you cannot transfer a non document derived content type to the records centre!!!!<br />
<strong></strong><br />
<br />
<strong>In conclusion</strong><br />
<strong></strong><br />
I understand the reasons that many organisations want to use a central repository for all of their formal records. However you should consider the following:<br />
<br />
<ul>
<li>Much of your content within SharePoint will be list based and not necessarily document based.</li>
<li>Your information architecture policy should reflect this and you should identify the <strong>information</strong> that will constitute a <strong>record</strong>, not just the documents</li>
<li> Declaration of records should take into consideration the limitations of a central repository without code and add-ons.</li>
</ul>
<br />
In part 2 I'll look at the technical issues that have to be overcome for central and in place records management....<br />
<br />
Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com0tag:blogger.com,1999:blog-265308177686522415.post-619661002007665902012-11-01T14:06:00.000-07:002013-10-01T08:44:52.190-07:00WSS Emailing Itself -: x-mailer: Windows SharePoint Services (version 3)<span style="font-size: 100%;"><span style="font-family: trebuchet ms;">I had a case recently where a client wanted to send access request emails to an email enabled document library. We encountered the problem of WSS not being able to handle the x-mail header. </span><br /><span style="font-family: trebuchet ms;">A solution was to create a vbscript that fired when an email entered the 'Drop' folder of IIS mailroot and stripped out the problematic header.</span><br /><span style="font-family: trebuchet ms;">Initial testing proved successfull and this has now been implemented.</span></span><span style="font-size: 100%; font-style: italic;"><span style="font-family: trebuchet ms;">solution<br />1. copy Smtpreg.vbs into the c:\inetpub\AdminScripts - smtpreg is available to download from MS.<br /><br />2. create a vbs file from the script below and copy it to the AdminScripts folder (I named mine <span style="font-weight: bold;">wss</span>)<br /><br /><span style="color: #ff6600;"><SCRIPT LANGUAGE="VBScript"><br /><br /><br />Sub ISMTPOnArrival_OnArrival(ByVal iMsg, EventStatus )<br /><br />if iMsg.Fields("urn:schemas:mailheader:x-mailer") = "Windows SharePoint Services (version 3)" then<br />iMsg.Fields.Delete("urn:schemas:mailheader:x-mailer")<br />iMsg.Fields.Update<br />end if<br /><br />iMsg.DataSource.Save<br />EventStatus = 0<br />End Sub</span></span></span><br />
<br />
<br />
<br />
3. run the following commands to register the script<br />
<br />
cd c:\inetpub\adminscripts<br />
cscript smtpreg.vbs /add 1 OnArrival DeleteMsg CDO.SS_SMTPOnArrivalSink "mail from=*"<br />
cscript smtpreg.vbs /setprop 1 OnArrival DeleteMsg Sink ScriptName "c:\Inetpub\AdminScripts\<span style="font-weight: bold;">wss</span>.vbs"<br />
<br />
4. This will now catch all mail on arrival and remove the offending header.<br />
<br />
<br />Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com26tag:blogger.com,1999:blog-265308177686522415.post-17031952569769395202012-07-19T11:59:00.001-07:002012-07-19T11:59:37.925-07:00SharePoint Foundation 2013 SearchIt appears that the lightweight search (search server express) is included in SPF 2013 with some nice additional web parts in the results interface<br />
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_search_results.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="498" src="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_search_results.png" width="640" /></a></div>
<br />
It also includes the refinement webparts on the left - note the timeline slider bar...NICE!Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com0tag:blogger.com,1999:blog-265308177686522415.post-12004858299135284652012-07-19T11:40:00.003-07:002012-07-19T11:40:51.281-07:00SharePoint 2013 HTML Field SecurityAnother nice feature of SP2013 is the ability to restrict what contributors can embed in site pages.<br />
<br />
Under site collection settings there is an entry for HTML field security.<br />
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_embed_settings.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="341" src="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_embed_settings.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
We can dictate what domains are safe regarding embedded content</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_embed_add.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="211" src="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_embed_add.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
When a user tries to embed code in an editable region they will get the following error if the domain isn't set in the HTML field security</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_embed_error2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="83" src="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_embed_error2.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
However, note that the error tells the user of an alternate way to embed the code using the embed command.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
So now if the user chooses embed from the ribbon</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_embed_script.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="175" src="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_embed_script.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
It appears that the HTML security is bypassed!!!!!</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_embed_bypass.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="170" src="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_embed_bypass.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Definitely one to watch, especially if this still appears in the RTM version</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br />Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com0tag:blogger.com,1999:blog-265308177686522415.post-36107075304546322272012-07-19T10:34:00.000-07:002012-07-19T10:37:09.078-07:00SharePoint 2013 - New Task ListsThe task lists appears to remain much the same in SP2013<br />
However the user interface has changed somewhat!<br />
<br />
We now have a timeline that appears above the task list.<br />
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_Task_list.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="165" src="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_Task_list.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
We can also change the colours of the task list items, something that we had to use jQuery for in the past.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_Task_list_color.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="203" src="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_Task_list_color.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
We can also choose whether to display a task on the timeline<br />
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_Task_list_timeline.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="130" src="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_Task_list_timeline.png" width="400" /></a></div>
<br />
Another nice touch is the ability to indent tasks so that the list resembles MS Project<br />
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_Task_list_indent.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="207" src="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_Task_list_indent.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
And finally the ability to open with project and sync changes back to SharePoint</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_Task_list_project.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="203" src="https://dl.dropbox.com/u/49527080/sharepoint/spf2013TP/spf2013_Task_list_project.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
*This is taken from the preview version of SP2013 and may be subject to change!Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com0tag:blogger.com,1999:blog-265308177686522415.post-47577860347478575362012-06-04T03:28:00.003-07:002012-06-04T03:33:49.907-07:00Event Receivers redirect in tabular viewMore event handlers and more pain!<br />
<br />
Using a custom redirect on ItemDeleting works fine in tabular view with a SINGLE item selected.<br />
e.g. <span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"></span></span><br />
<span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">properties.Status = </span></span><span style="color: #2b91af; font-family: Consolas; font-size: x-small;"><span style="color: #2b91af; font-family: Consolas; font-size: x-small;"><span style="color: #2b91af; font-family: Consolas; font-size: x-small;">SPEventReceiverStatus</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">.CancelWithRedirectUrl;</span></span><br />
<span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">
</span></span><br />
<span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"> properties.RedirectUrl = </span></span><span style="color: #a31515; font-family: Consolas; font-size: x-small;"><span style="color: #a31515; font-family: Consolas; font-size: x-small;"><span style="color: #a31515; font-family: Consolas; font-size: x-small;">"/_layouts/DeleteStub/stubError.aspx?errMsg="</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"> + err; </span></span><br />
<br />
<br />
<br />
<br />
However when we select multiple items<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://dl.dropbox.com/u/49527080/sharepoint/multitab.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://dl.dropbox.com/u/49527080/sharepoint/multitab.png" /></a></div>
<br />
<span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"></span></span><br />
The event handler kicks in no problem but then the redirect fails miserably!!!<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="http://dl.dropbox.com/u/49527080/sharepoint/multierror.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://dl.dropbox.com/u/49527080/sharepoint/multierror.png" /></a></div>
<div align="left" class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Event handlers have moved from being funky to painful over the last 12 months!</div>
<div align="left" class="separator" style="clear: both; text-align: center;">
</div>Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com0tag:blogger.com,1999:blog-265308177686522415.post-45091082466148273692012-05-01T22:51:00.002-07:002012-05-01T22:51:26.188-07:00SQL Fragmentation - lightweight scriptThe following script will iterate through all of your databases and report on the average fragmentation of your indexes for each DB.<br />
Its less intrusive as it doesn't create any temporary tables and gives you a quick report on where fragmentation is most prevalent<br />
<br />
DECLARE @DatabaseID smallint <br />DECLARE @DatabaseName varchar(255) <br />DECLARE DatabaseCursor CURSOR FOR <br />SELECT dbid, name FROM master.dbo.sysdatabases <br />--WHERE name NOT IN ('master','model','msdb','tempdb','distrbution') <br />--ORDER BY 1 <br />
OPEN DatabaseCursor <br />
FETCH NEXT FROM DatabaseCursor INTO @DatabaseID, @DatabaseName<br />WHILE @@FETCH_STATUS = 0 <br />BEGIN <br />
-----------------------------------------------------<br />
SELECT @DatabaseName as Database_Name, avg(avg_fragmentation_in_percent) as Average_Fragmentation FROM sys.dm_db_index_physical_stats (NULL, NULL, NULL, NULL, NULL)<br /> where avg_fragmentation_in_percent > 30 and database_id = @DatabaseID<br /> <br />----------------------------------------------------- <br />
<br />
FETCH NEXT FROM DatabaseCursor INTO @DatabaseID,@DatabaseName<br />END <br />CLOSE DatabaseCursor <br />DEALLOCATE DatabaseCursorDave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com2tag:blogger.com,1999:blog-265308177686522415.post-9705199371947581782012-04-26T11:36:00.002-07:002012-04-26T11:36:33.707-07:00SharePoint SQL FragmentationHere a simple SQL script to show you the fragmentation of tables in your database....run it against any of the DB's in your SQL instance<br />
<br />
Note - it creates and drops a temporary table to hold the report (fraglist)<br />
I have set the threshold in this script to 30% fragmentation<br />
<br />
DBCC SHOWCONTIG <br />
<br />
<br />/*Perform a 'USE <database name="">' to select the database in which to run the script.*/<br />-- Declare variables<br />SET NOCOUNT ON;<br />DECLARE @tablename varchar(255);<br />DECLARE @execstr varchar(400);<br />DECLARE @objectid int;<br />DECLARE @indexid int;<br />DECLARE @frag decimal;<br />DECLARE @maxfrag decimal;</database><br />
-- Decide on the maximum fragmentation to allow for.<br />SELECT @maxfrag = 30.0;<br />
-- Declare a cursor.<br />DECLARE tables CURSOR FOR<br /> SELECT TABLE_SCHEMA + '.' + TABLE_NAME<br /> FROM INFORMATION_SCHEMA.TABLES<br /> WHERE TABLE_TYPE = 'BASE TABLE';<br />
-- Create the table.<br />CREATE TABLE #fraglist (<br /> ObjectName char(255),<br /> ObjectId int,<br /> IndexName char(255),<br /> IndexId int,<br /> Lvl int,<br /> CountPages int,<br /> CountRows int,<br /> MinRecSize int,<br /> MaxRecSize int,<br /> AvgRecSize int,<br /> ForRecCount int,<br /> Extents int,<br /> ExtentSwitches int,<br /> AvgFreeBytes int,<br /> AvgPageDensity int,<br /> ScanDensity decimal,<br /> BestCount int,<br /> ActualCount int,<br /> LogicalFrag decimal,<br /> ExtentFrag decimal);<br />
-- Open the cursor.<br />OPEN tables;<br />
-- Loop through all the tables in the database.<br />FETCH NEXT<br /> FROM tables<br /> INTO @tablename;<br />
WHILE @@FETCH_STATUS = 0<br />BEGIN<br />-- Do the showcontig of all indexes of the table<br /> INSERT INTO #fraglist <br /> EXEC ('DBCC SHOWCONTIG (''' + @tablename + ''') <br /> WITH FAST, TABLERESULTS, ALL_INDEXES, NO_INFOMSGS');<br /> FETCH NEXT<br /> FROM tables<br /> INTO @tablename;<br />END;<br />
-- Close and deallocate the cursor.<br />CLOSE tables;<br />DEALLOCATE tables;<br />
-- Declare the cursor for the list of indexes to be defragged.<br />DECLARE indexes CURSOR FOR<br /> SELECT ObjectName, ObjectId, IndexId, LogicalFrag<br /> FROM #fraglist<br /> WHERE LogicalFrag >= @maxfrag<br /> AND INDEXPROPERTY (ObjectId, IndexName, 'IndexDepth') > 0;<br />
-- Open the cursor.<br />OPEN indexes;<br />
-- Loop through the indexes.<br />FETCH NEXT<br /> FROM indexes<br /> INTO @tablename, @objectid, @indexid, @frag;<br />
WHILE @@FETCH_STATUS = 0<br />BEGIN<br /> PRINT 'TABLE FRAGMENTATION (0, TABLE:' + RTRIM(@tablename) + ',<br /> ' + RTRIM(@indexid) + ') - fragmentation currently '<br /> + RTRIM(CONVERT(varchar(15),@frag)) + '%';<br /><br />
FETCH NEXT<br /> FROM indexes<br /> INTO @tablename, @objectid, @indexid, @frag;<br />END;<br />
-- Close and deallocate the cursor.<br />CLOSE indexes;<br />DEALLOCATE indexes;<br />
-- Delete the temporary table.<br />DROP TABLE #fraglist;<br />GODave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com0tag:blogger.com,1999:blog-265308177686522415.post-23862924586712278862012-04-26T11:23:00.001-07:002012-04-26T11:30:27.333-07:00JQuery for SharePoint made simplerHere's some simple JQuery to help you avoid looking for those annoying GUID's<br />
<br />
var list = []; <br />
var peoplePicker1;<br />
var peoplePicker2;<br />
var currentObject;<br />
<br />
$(document).ready(function() {<br />
<br />
// use this ^ for wildcard hiding/showing all items that begin with "xxx"<br />
$('[title^="xxx"]').closest('tr').hide();<br />
$('[title^="xxx"]').closest('tr').show();<br />
<br />
$('DIV[id^="sectionSection2"]').hide();<br />
<br />
// will need this to hide date/time fields<br />
$('nobr:contains("Hire Car")').closest('tr').hide();<br />
<br />
// use for text fields and drop down lists<br />
var x = $('[title$="Authoriser"]').val();<br />
<br />
// use for radio and checkboxes<br />
// where title$ is the choice option<br />
$('[title$="Enter Choice #1"]').click(function() {<br />
alert('Please ensure you complete the Tracking section');<br />
<br />
// get the radio button id<br />
var tmp = $(this).children('input').attr('id');<br />
<br />
// check its value<br />
alert($("input[id="+tmp+"]:checked").val()); <br />
var checked = $("input[id="+tmp+"]:checked").val(); <br />
if(checked == 'on')<br />
{<br />
// do something<br />
}<br />
});<br />
<br />
// use for people pickers<br />
// add each people picker to an array and assign it to a var<br />
// start loop<br />
$(".ms-inputuserfield").each(function(){<br />
list.push($(this).text());<br />
currentObject = $(this); <br />
});<br />
// end loop<br />
peoplePicker1 = list[0];<br />
peoplePicker2 = list[1];<br />
currentObject.attr('disabled','disabled');<br />
<br />
var currentUser = $().SPServices.SPGetCurrentUser({<br />
fieldName: "Title",<br />
debug: false<br />
});<br />
<br />
// check if the user is an admin user<br />
function isAdmin(user)<br />
{<br />
var adminUser1 = "System Account";<br />
var adminUser2 = "john smith";<br />
var adminUser3 = "john doe";<br />
var adminUser4 = "dave nixon";<br />
var adminUser5 = "fred smith";<br />
if(user == adminUser1 || user == adminUser2 || user == adminUser3 || user == adminUser4 || user == adminUser5)<br />
{<br />
return "admin";<br />
}<br />
else<br />
{<br />
return "not admin";<br />
}<br />
<br />
}<br />
function CheckForAttachment()<br />
{<br />
var elm = document.getElementById("idAttachmentsTable");<br />
if(elm == null || elm.rows.length == 0)<br />
{<br />
alert("No e-training form attached");<br />
return false;<br />
}<br />
else { return true; }<br />
}<br />
function PreSaveAction()<br />
{<br />
return CheckForAttachment();<br />
}<br />
<br />
<br />
<br />
<br />
});Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com0tag:blogger.com,1999:blog-265308177686522415.post-73862100980195518992012-04-26T11:15:00.000-07:002012-04-26T11:28:53.217-07:00International SharePoint Conference - LondonFirst a big thanks to Steve Smith for another excellent gig.
<br />
<br />
While I agree there weren't too many new aspects to SharePoint 2010 and the sessions, there were some great angles on the risks and issues, development and case studies.
<br />
<br />
My favourite picks:<br />
1. Bill English and and Andrew Woodwards business tracks.
<br />
2. Jess Meats case study on her own troubles with SharePoint
<br />
3. Wictor Wilens BCS/Dev track
<br />
4. Neil Hodgkinsons Search and SQL track.<br />
<br />
I thought Jess's honesty on her particular implementation of a SharePoint rollout was refreshing - sometimes it's good to see that despite all the best practices in the world, sharepoint can still provide a business function even if it's rolled out 'wrongly'.Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com0tag:blogger.com,1999:blog-265308177686522415.post-51107349220112584982012-02-18T06:45:00.000-08:002012-02-18T06:49:51.940-08:00Event Handlers - redirecting and httpcontextI've been developing some event handlers, specifically on itemdeleting events and once again some SP quirks are making things difficult.<br />
<br />
So lets imagine we want a simple event handler that intercepts itemdeleting, cancels the delete and redirects the user to a custom page.<br />
<br />
the code is very simple<br />
<br />
<i>public override void ItemDeleting(SPItemEventProperties properties)<br />
{<br />
try<br />
{<br />
string url = properties.WebUrl.ToString();<br />
string listname = properties.ListTitle.ToString();<br />
using (SPSite site = new SPSite(url))<br />
{<br />
site.AllowUnsafeUpdates = true;<br />
using (SPWeb web = site.OpenWeb())<br />
{<br />
web.AllowUnsafeUpdates = true;<br />
SPList myList = web.Lists[listname];<br />
if (myList.BaseType == SPBaseType.GenericList)<br />
{<br />
if (list_allow_delete == "no")<br />
{<br />
properties.Status =SPEventReceiverStatus.CancelWithRedirectUrl;<br />
properties.RedirectUrl = "/_layouts/customError.aspx";<br />
</i> <br />
<br />
simple really...but there are quirks!!!<br />
<br />
1. When a user deletes the item using the ribbon menu in the library or item they get successfully redirected to the custom page. <br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjojBAp_jCIfPsBvufc529iqz5A6ppGTk8A410NTSBc3g_rhQWjkNG6vMR7esRaEBrK6E91mwE7IAUgOdYHFwDImThAopqwE32wprW3Ykgd8NLKsJCKjI1f1LNycwJpM12JCvCf2beKx4Yp/s1600/ea1.jpg" imageanchor="1" style="clear: left; : left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="156" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjojBAp_jCIfPsBvufc529iqz5A6ppGTk8A410NTSBc3g_rhQWjkNG6vMR7esRaEBrK6E91mwE7IAUgOdYHFwDImThAopqwE32wprW3Ykgd8NLKsJCKjI1f1LNycwJpM12JCvCf2beKx4Yp/s400/ea1.jpg" width="400" /></a></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdQgnEQ4ypHmCRAUg9BhQJDX8qb0kPgdS0doTOT8u7rcmgT_Azr0zNxuWdTGp1QEtRmKk80cjXvsNCmSLaYHDuVJcTU0Gg7pH_P1tGBHH1DfyT27rj3qfQ3vPrJpCZnsn3JPypJVN1DSy3/s1600/ea2.jpg" imageanchor="1" style="clear: left; float: ; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="185" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdQgnEQ4ypHmCRAUg9BhQJDX8qb0kPgdS0doTOT8u7rcmgT_Azr0zNxuWdTGp1QEtRmKk80cjXvsNCmSLaYHDuVJcTU0Gg7pH_P1tGBHH1DfyT27rj3qfQ3vPrJpCZnsn3JPypJVN1DSy3/s400/ea2.jpg" width="400" /></a></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyQZG0Pi4umEC2wdu_-VsE8IJV9E_XroG62BNZ_QSFJOTfAmxps6gQsEj2y07lgW9mjCJvgO-r7Clbq3zG7ahBIfnxoVOX5kvPOpXQSkNR6jWsZDH4mr10Eyys9-JMkgf5Jt8BBMQoWojn/s1600/ea3.jpg" imageanchor="1" style="clear: left; : ; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="218" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyQZG0Pi4umEC2wdu_-VsE8IJV9E_XroG62BNZ_QSFJOTfAmxps6gQsEj2y07lgW9mjCJvgO-r7Clbq3zG7ahBIfnxoVOX5kvPOpXQSkNR6jWsZDH4mr10Eyys9-JMkgf5Jt8BBMQoWojn/s400/ea3.jpg" width="400" /></a></div><br />
2. If the user deletes the item from the context menu they do not get redirected to the custom error page, instead the standard error message is displayed.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhME3AnCltJIxLlo305tYxKepRNReWO-k66glxlqaFICi7sDGh_-ejhGOLTUQSCz3lX_6FxjdJXzk9ERZNNMQPOe3k8JxEBXJCY1iRkX-O9_lR4cz_vhD-JtLAdSsjMSPs2wSHJ1HJaTmA/s1600/ea4.jpg" imageanchor="1" style="clear: left; float: ; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="93" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhME3AnCltJIxLlo305tYxKepRNReWO-k66glxlqaFICi7sDGh_-ejhGOLTUQSCz3lX_6FxjdJXzk9ERZNNMQPOe3k8JxEBXJCY1iRkX-O9_lR4cz_vhD-JtLAdSsjMSPs2wSHJ1HJaTmA/s400/ea4.jpg" width="400" /></a></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjF8W-8tLYL7I7NnbpT_rwwswxYCVm8n3lLvs3wDEZPkoDJPdx5MXoXFaFIzMjyE9UxXvaTPdgjyJnvSoJkFBY5cs8cEh62XfQbnWQaY8WW4_0HinCc7m3maFD1q_kS7eUzf4fic5vzofxU/s1600/ea5.jpg" imageanchor="1" style="clear: left; float: ; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="168" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjF8W-8tLYL7I7NnbpT_rwwswxYCVm8n3lLvs3wDEZPkoDJPdx5MXoXFaFIzMjyE9UxXvaTPdgjyJnvSoJkFBY5cs8cEh62XfQbnWQaY8WW4_0HinCc7m3maFD1q_kS7eUzf4fic5vzofxU/s400/ea5.jpg" width="400" /></a></div><br />
Bummer!<br />
<br />
So the first thing that comes to mind is the httpcontext so we ensure the context in the constructor<br />
<br />
some more simple code - <br />
<i>public class DeleteStubEH : SPItemEventReceiver<br />
{<br />
/// <summary><br />
/// An item is being added.<br />
/// </summary><br />
/// <br />
HttpContext current;<br />
<br />
public DeleteStubEH () <br />
{<br />
current = HttpContext.Current;<br />
<br />
}<br />
</i><br />
<br />
If we check the context as we run through the code we can see a quirk.<br />
<br />
If the user uses the ribbon to delete then the httpcontext remains throughout the code.<br />
If the user users the context menu to delete then the httpcontext is lost!!!!<br />
<br />
Ok, lets create a new context object to ensure we have an httpcontext object<br />
<br />
if (current == null)<br />
{<br />
<br />
HttpRequest request = new HttpRequest("", web.Url, "");<br />
current = new HttpContext(request, new HttpResponse(new StringWriter()));<br />
current.Items["HttpHandlerSPWeb"] = web;<br />
}<br />
<br />
The result - still no redirection to our custom error page!!!!!<br />
<br />
So I attempted a work around using the old redirect utility.<br />
<br />
SPUtility.Redirect("/customError.aspx", SPRedirectFlags.RelativeToLayoutsPage, current);<br />
<br />
Still doesn't work!!!!<br />
<br />
I'm not sure if this is a context menu bug or not but its certainly annoying!<br />
I will continue my search for a 'cure'Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com0tag:blogger.com,1999:blog-265308177686522415.post-69539157368541412192011-12-29T08:03:00.000-08:002011-12-29T08:04:26.135-08:00Gantt Views and SharePoint CrawlsI have been doing some cleanup on my 2010 dev environment and noticed the following error in my crawl log - "The crawler could not communicate with the server. Check that the server is available and that the firewall access is configured correctly"<br />
<br />
Immediately I thought there was a comms or authentication issue but further investigation into the event logs provided more info.<br />
<br />
Exception information: <br />
Exception type: SPException <br />
Exception message: This view requires at least Microsoft Internet Explorer 7.0, Mozilla FireFox 3.0, or Apple Safari 3.0. <br />
<br />
It appears that the Gantt view is inaccesible to the crawler, or more specifically the user-agent the crawler uses.<br />
<br />
If we look at the reg key for the user-agent it seems that the correct user-agent version is being used<br />
<br />
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office Server\14.0\Search\Global\Gathering Manager\Mozilla/4.0 (compatible; MSIE 4.01; Windows NT; MS Search 6.0 Robot)<br />
<br />
So although the Gantt view is verifying that the correct user-agent is being used to render the view, the gathering manager doesn't seem to be passing its user-agent properties through during the crawl.Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com1tag:blogger.com,1999:blog-265308177686522415.post-69145480706679508532011-11-15T03:46:00.000-08:002011-11-15T03:56:30.285-08:00SharePoint In Place RM - Unified viewOne of the biggest complaints of in place records management is the inability to get a unified view of all the records in the system.<br />
<br />
Obviously this isn't a problem in a central records center but as more people are moving towards 'in place' certain gaps are being identified.<br />
<br />
Thankfully we have the API, specifically this:<br />
<br />
public static bool IsRecord(<br />
SPListItem item<br />
)<br />
<br />
So if we recurse all the site collections, webs and lists we should begin to get an idea of the records and where they sit.<br />
<br />
Maybe a dictionary to hold the info (name, version etc etc)<br />
<br />
Perhaps a treeview to render the classification (site based or term set)<br />
<br />
So lets wrap that in a web part and a treeview for navigation.<br />
<br />
This navigation is based on the term set.<br />
<br />
<embed src="http://www.box.net/embed/6qrbg64tmatieiu.swf" width="466" height="400" wmode="opaque" type="application/x-shockwave-flash" allowFullScreen="true" allowScriptAccess="always"><br />
<br />
Clicking the tree node will open all the records in that term set<br />
<br />
<embed src="http://www.box.net/embed/yiujkip0by7ygpm.swf" width="466" height="400" wmode="opaque" type="application/x-shockwave-flash" allowFullScreen="true" allowScriptAccess="always"><br />
<br />
It's a good start and i will continue to develop it.Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com0tag:blogger.com,1999:blog-265308177686522415.post-56942039012731726832011-11-14T13:27:00.000-08:002011-11-15T00:33:06.356-08:00IPSV Term Store for SharePointFollowing on from the LGCS here's the IPSV<br />
<br />
Please note this has nearly 8000 terms in the csv and will take a long time to import into the term store.<br />
<br />
Useful for those still wanting to use this huge vocabulary in SharePoint 2010<br />
<br />
<a href="http://www.box.net/s/kyqrxqdgcil6rudzvpfv">IPSV Term Set</a><br />
<br />
<embed src="http://www.box.net/embed/85quj8a2i69njkb.swf" width="600" height="400" wmode="opaque" type="application/x-shockwave-flash" allowFullScreen="true" allowScriptAccess="always">Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com0tag:blogger.com,1999:blog-265308177686522415.post-63660279547805984162011-11-14T11:38:00.000-08:002011-11-14T12:35:10.471-08:00LGCS Term Store for SharePoint<div>As SharePoint is beginning to grab a hold within the UK public sector I thought I would make available the LGCS term store...hope it saves you time!<br />
<br />
<a href="http://www.box.net/s/z1uz8jm4rtn2lceqt8g9" target="_blank">LGCS Term Store - download</a><br />
<br />
</div><embed src="http://www.box.net/embed/nn1zmzblszyvf8u.swf" width="700" height="400" wmode="opaque" type="application/x-shockwave-flash" allowFullScreen="true" allowScriptAccess="always">Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com0tag:blogger.com,1999:blog-265308177686522415.post-60129020813261636152011-11-10T10:27:00.000-08:002011-11-10T10:39:10.798-08:00Fast Search Annoyance<div><div><div><div>FAST search has some nice quirks for the end user.</div><div>One of the most popular is the thumbnail preview for MS Office documents.</div><div> </div><div>One of the restrictions on the thumbnails is that they will only show if the crawled content is a SharePoint site - bummer!</div><div> </div><div>However there is a gotcha that you should watch.</div><div>If you have a document in a site and the same document in a non-sharepoint site (fileshare, web site tec), then it will not thumbnail.</div><div> </div><div>You will have to use the facet on the left to ensure that the source is a SharePoint site.</div><div> </div><div> <a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhR2rYozlht1QOMSwAYzR8zIGbF3hCPipgV_6_SP8yFqWq9FZAR7NboQ22qf4Yc4ENxp5UaMm-avoxsfnHyxBzaUbWzYt47p5JvMpgiiaLLgCv3ykJ1NPV1tVW-bPe2MU-dVoYNIh-uyH9o/s1600/fast1.jpg"><img style="width: 400px; height: 253px; cursor: pointer;" id="BLOGGER_PHOTO_ID_5673437915161698562" border="0" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhR2rYozlht1QOMSwAYzR8zIGbF3hCPipgV_6_SP8yFqWq9FZAR7NboQ22qf4Yc4ENxp5UaMm-avoxsfnHyxBzaUbWzYt47p5JvMpgiiaLLgCv3ykJ1NPV1tVW-bPe2MU-dVoYNIh-uyH9o/s400/fast1.jpg" /></a></div><div> </div><div>Now once we facet it down to the sharepoint site we get the required thumbnail</div><div> </div><div> <a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqzrcGFrHttxg9ARG9dCPSAwakgO8Cz-OAzSwWIK3DAOhEby8OqG7FiXrzXklgQb24wnCnEUvfjpzztOdC9JzBeROrLCFekZ60i1e-wBkIuvrYBAYMwNAC4tQE17EubaYT7s6lenpVm86i/s1600/fast2.jpg"><img style="width: 400px; height: 242px; cursor: pointer;" id="BLOGGER_PHOTO_ID_5673438177239305666" border="0" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqzrcGFrHttxg9ARG9dCPSAwakgO8Cz-OAzSwWIK3DAOhEby8OqG7FiXrzXklgQb24wnCnEUvfjpzztOdC9JzBeROrLCFekZ60i1e-wBkIuvrYBAYMwNAC4tQE17EubaYT7s6lenpVm86i/s400/fast2.jpg" /></a></div><div> </div></div></div></div>Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com0tag:blogger.com,1999:blog-265308177686522415.post-62154644794831820972011-10-31T09:54:00.000-07:002011-10-31T10:06:25.713-07:00jQuery 'contains' oddity<div>Imagine you are hiding a field in SharePoint<br /><br /><strong><em>$('nobr:contains("Email")').closest('tr').hide();<br /></em></strong><br />The 'contains' function should act as a wild card - so if you have a bunch of fields beginning with 'Email' then you would imagine the above script will hide them all.<br /><br />It appears - and this is a SharePoint only quirk - that if your string has more than one space e.g. Email My Manager it <em>intemittently</em> misses the string and doesn't pick it up for hiding.</div><div> </div><div>Still trying to work this one out.....</div><div> </div><div>My tip would be to use the full string in the <em>contains</em> element</div><div> </div><div>Odd!</div><div> </div><div> </div>Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com0tag:blogger.com,1999:blog-265308177686522415.post-19310959397649990452011-10-25T14:40:00.000-07:002011-10-25T14:53:40.595-07:00jQuery readonly drop downsNormally in SharePoint we would render a field or column as readonly by using the simple 'readonly' attribute.<br /><br />********************** readonly field ***********************************<br />$("input[title='Some Field Name']").attr('readonly','readonly');<br /><br />This is Ok for input fields but jQuery doesn't support the readonly attribute for drop down lists so you may be tempted to use the disable attribute<br /><br />*********************** disable a field **********************************<br />$("select[title='Some Field Name']").attr('disabled','disabled');<br /><br />However disabling a select control means that when you click Ok the actual value is not posted in the form and consequently the select value is not passed into the SharePoint columnDave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com1tag:blogger.com,1999:blog-265308177686522415.post-34040638070194298082009-07-14T09:33:00.000-07:002009-07-14T10:48:12.941-07:00SharePoint List Summaries & Reports with XMLOne of the drawback of SharePoint lists is the ability to actually roll-up, report and summarize the data.<br /><br /><br /><br />Sure we can open datasheet view and use the office web components but what if we want a summary of all the data as soon as we open the list.<br /><br />This can be easily achieved with a little XML and a dash of SharePoint Designer!<br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJKRO2x1R4li8-FtGMkbErrq_lxuRGbYAoyqx0cIwhpHZwbHmwVjk5Tp2G5_1-__xMNFWAQrq6tG3gQsaOabzHoY8xC6ZgbUiQ0EWAOHvZ6wkEq4mHMz8kNN7DeH3Hw9FfmKwUlAik8PX_/s1600-h/sr2.gif"><img id="BLOGGER_PHOTO_ID_5358357111899591858" style="WIDTH: 508px; CURSOR: hand; HEIGHT: 134px" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJKRO2x1R4li8-FtGMkbErrq_lxuRGbYAoyqx0cIwhpHZwbHmwVjk5Tp2G5_1-__xMNFWAQrq6tG3gQsaOabzHoY8xC6ZgbUiQ0EWAOHvZ6wkEq4mHMz8kNN7DeH3Hw9FfmKwUlAik8PX_/s400/sr2.gif" border="0" /></a><br /><br />In this list we have a rollup summary below showing calculations and a little progress bar for the project progress.<br /><br />Here's how you do it:<br /><br />1. Using SharePoint designer, insert a data view web part under the List by selecting Data View > Insert Data View from the main menu.<br /><br />2. Expand the Shareoint Lists in the Data Source Library Task Pane and select the list or library that contains the information you wish to display. From the drop down select 'Show Data' to populate the Data Preview tab.<br /><br />3. From the list of columns, select the ones that you wish to display and select ‘Insert selected fields as… multiple item view' from the drop down menu at the top of the window.<br /><br />4. Now lets look at the code generated for the DataView....<br /><br /><br />a. The following line shows the data fields that we are going to work with<br /><br /><br /><br /><span style="color:#ff6600;"><datafields>@Title,Title;@Resource,Resource;@Effort,Effort;@Project_x0020_Activity,Project Activity;@Planned,Planned;@Planned_x0020_Cost,Planned Cost;@Actual_x0020_Cost,Actual Cost;@Profit,Profit;@Rate,Rate;@ID,ID;@ContentType,Content Type;@Modified,Modified;@Created,Created;@Author,Created By;@Editor,Modified By;@_UIVersionString,Version;@Attachments,Attachments;@File_x0020_Type,File Type;@FileLeafRef,Name (for use in forms);@FileDirRef,Path;@FSObjType,Item Type;@_HasCopyDestinations,Has Copy Destinations;@_CopySource,Copy Source;@ContentTypeId,Content Type ID;@_ModerationStatus,Approval Status;@_UIVersion,UI Version;@Created_x0020_Date,Created;@FileRef,URL Path;</datafields></span><br /><span style="color:#ff6600;"></span><br /><span style="color:#ff6600;"></span><br /><span style="color:#000000;">b. Now look for the following lines</span><br /><span style="color:#ff6600;"></span><br /><span style="color:#ff6600;"><br />xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1"><br /><th class="ms-vh" width="1%" nowrap="nowrap"></th><br /><br /><td class="ms-vh" nowrap=""><br /><?xml:namespace prefix = xsl /><xsl:text escaping="yes" preserve="yes" ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime">&amp;nbsp;</xsl:text><span style="color:#000000;"><br /><br />We are going to add our bespoke data immediately after these lines</span><br /></span><span style="color:#ff6600;"></span><br /><br /><span style="color:#000000;">c. Declare our variables and any calculations we want to add</span><br /><span style="color:#ff6600;"><br /><br /><span ><xsl:variable select="format-number(/dsQueryResponse/Rows/Row[@Rate='1000'], '#####')" name="a"><br /><xsl:variable select="sum(/dsQueryResponse/Rows/Row[@Rate='1000']/@Planned)" name="planned_pm"><br /><xsl:variable select="sum(/dsQueryResponse/Rows/Row[@Rate='1000']/@Effort)" name="effort_pm"><br /><xsl:variable select="sum(/dsQueryResponse/Rows/Row[@Rate='800']/@Planned)" name="planned_con"><br /><xsl:variable select="sum(/dsQueryResponse/Rows/Row[@Rate='800']/@Effort)" name="effort_con"><br /><xsl:variable select="53 - ($effort_pm + $effort_con)" name="project_remaining"><br /><xsl:variable select="($effort_pm + $effort_con)" name="project_cost_days"><br /><xsl:variable select="($effort_pm * 1000) + ($effort_con * 800)" name="project_cost_value"><br /><xsl:variable select="format-number($project_cost_days div 53 *100, '##')" name="project_cost_pc"></span></xsl:variable></xsl:variable></xsl:variable></xsl:variable></xsl:variable></xsl:variable></xsl:variable></xsl:variable></xsl:variable><br /><xsl:variable select="format-number(/dsQueryResponse/Rows/Row[@Rate='1000'], '#####')" name="a"><xsl:variable select="sum(/dsQueryResponse/Rows/Row[@Rate='1000']/@Planned)" name="planned_pm"><xsl:variable select="sum(/dsQueryResponse/Rows/Row[@Rate='1000']/@Effort)" name="effort_pm"><xsl:variable select="sum(/dsQueryResponse/Rows/Row[@Rate='800']/@Planned)" name="planned_con"><xsl:variable select="sum(/dsQueryResponse/Rows/Row[@Rate='800']/@Effort)" name="effort_con"><xsl:variable select="53 - ($effort_pm + $effort_con)" name="project_remaining"><xsl:variable select="($effort_pm + $effort_con)" name="project_cost_days"><xsl:variable select="($effort_pm * 1000) + ($effort_con * 800)" name="project_cost_value"><xsl:variable select="format-number($project_cost_days div 53 *100, '##')" name="project_cost_pc"><span style="color:#ff6600;"></span><br /><br /><br /><span style="color:#000000;">d. Create our table to hold the values and then add our variables</span><br /><br /><span style="color:#ff6600;"><br /><table class="ms-propertysheet" border="0" bgcolor="white" width="100%"><br /><tr><td valign="top"><br /><table class="ms-vb"><br /><tr><td><b>Project Management</b></td></tr><br /><tr><td>Planned PM Days: </td><td> <xsl:value-of select="$planned_pm"/></td></tr><br /><tr><td>Actual PM Days: </td><td> <xsl:value-of select="$effort_pm"/></td></tr><br /><tr><td>Profit PM Days: </td><td> <xsl:value-of select="$planned_pm - $effort_pm"/></td></tr><br /><tr><td>Profit PM Value: </td><td> <xsl:value-of select="($planned_pm - $effort_pm) * 1000"/></td></tr><br /></table><br /></td><td valign="top"><br /><table class="ms-vb"><br /><tr><td><b>Consultancy</b></td></tr><br /><tr><td>Planned Consultant Days: </td><td> <xsl:value-of select="$planned_con"/></td></tr><br /><tr><td>Actual Consultant Days: </td><td> <xsl:value-of select="$effort_con"/></td></tr><br /><tr><td>Profit Consultant Days: </td><td> <xsl:value-of select="$planned_con - $effort_con"/></td></tr><br /><tr><td>Profit Consultant Value: </td><td> <xsl:value-of select="($planned_con - $effort_con) * 800"/></td></tr><br /></table><br /></span></span><br /><p><span style="color:#ff6600;"><span style="color:#ff6600;"></span></span> </p><p><span style="color:#ff6600;"><span style="color:#ff6600;"><span style="color:#000000;">And the pretty looking progress bar!</span></p><br /><p><span style="color:#ff6600;"><</td><td valign="top"><br /><table class="ms-vb"><br /><tr><td><b>Summary</b></td></tr><br /><tr><td>Project Remaining: </td><td> <xsl:value-of select="$project_remaining"/></td></tr><br /><tr><td>Project Days Taken: </td><td> <xsl:value-of select="$project_cost_days"/></td></tr><br /><tr><td>Project Cost Taken: </td><td> <xsl:value-of select="$project_cost_value"/></td></tr><br /><tr><td>Project Profit : </td><td> <xsl:value-of select="($planned_pm - $effort_pm) * 1000 + ($planned_con - $effort_con) * 800" /></td></tr><br /><br /><br /></table><br /></span><br /><br /><span style="color:#000000;">5. And that's pretty much it!</span><br /><br /><span style="color:#000000;">A mixture of SPD and a little xml calculation and you can achieve a quick solution to fill the gap in functionality that the list doesn't give us.<br /></span><br /><span style="color:#000000;">My next post will illustrate how to create and manipulate xml variables in MOSS Lists<br /></span><br /><br /><br /></span></span><span style="color:#ff6600;"></span>Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com0tag:blogger.com,1999:blog-265308177686522415.post-75570735620370286462009-07-13T23:45:00.000-07:002009-07-14T09:27:47.484-07:00Modifying MOSS Search Results with XSLT<div>I finally got round to modifying the way MOSS returns it's search results.<br /><br /><br />Not satisfied with a single line of results I wanted to be able to show the results in tabular form with multiple rows to give the user a better experience and to actually inform them which item of data in the results corresponded to which item of metadata.<br /><br /><br /><br />This is what I wanted to achieve<br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuYGe_aK1u02jBKtR1V42TqEd8AfKl7xacA6vQDDf5GBKs73b5F63DabazphVA4pdcwB8ZIduBJRz9163-U37NCp5eozx8E8IFg79IuPFU47gm9xfe-whnBmCseMMhUXlUi87-UWAEd5Ee/s1600-h/sr1.gif"><img id="BLOGGER_PHOTO_ID_5358353319797020610" style="WIDTH: 400px; CURSOR: hand; HEIGHT: 70px" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuYGe_aK1u02jBKtR1V42TqEd8AfKl7xacA6vQDDf5GBKs73b5F63DabazphVA4pdcwB8ZIduBJRz9163-U37NCp5eozx8E8IFg79IuPFU47gm9xfe-whnBmCseMMhUXlUi87-UWAEd5Ee/s400/sr1.gif" border="0" /></a><br /><br />So how is this done?....XSLT !<br /><br /><br /><br />1. Modify your core search results webpart<br /><br />This is covered completely in Tobias's Blog <a href="http://www.zimmergren.net/archive/2008/03/15/moss-2007-customize-the-search-result-using-xslt.aspx">Here</a><br /><br /><br /><br /><br />2. Creating your XSLT<br /><br />So now we know what properties are available we can decide which ones to add to our XSLT.<br />So lets dissect one -<br /><br /><span style="color:#ff6600;">The first section is the declarative xsl</span><br /><br /><xsl:stylesheet 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"><br /><xsl:output method="html" indent="no"/><br /><xsl:decimal-format NaN=""/><br /><xsl:param name="FileName" /><br /><xsl:param name="dvt_apos">'</xsl:param><br /><br /><br /><span style="color:#ff6600;">The second section parses the search results - this returns all the default columns<br /></span><span style="color:#ff6600;">NOTE the lines highlighted in</span> <span style="color:#009900;">GREEN</span><br /><br /><br /><xsl:variable name="dvt_1_automode">0</xsl:variable><br /><xsl:template match="/"><br /><xsl:call-template name="dvt_1"/><br /></xsl:template><br /><xsl:template name="dvt_1"><br /><xsl:variable name="dvt_StyleName">RepForm1</xsl:variable><br /><xsl:variable name="Rows" select="/All_Results/Result" /><br /><span style="color:#33cc00;"><table border="0" width="100%"><br /><xsl:call-template name="dvt_1.body"><br /><xsl:with-param name="Rows" select="$Rows" /><br /></xsl:call-template><br /></table><br /></span></xsl:template><br /><xsl:template name="dvt_1.body"><br /><xsl:param name="Rows" /><br /><xsl:for-each select="$Rows"><br /><xsl:call-template name="dvt_1.rowview" /><br /></xsl:for-each><br /></xsl:template><br /><xsl:template name="dvt_1.rowview"><br /><br /><br /><span style="color:#ff6600;">The following section actually renders the results to the page.</span></div><br /><br /><div><span style="color:#ff6600;">This section is the code that is parsed to the page in the</span> <span style="color:#33cc00;">GREEN</span> <span style="color:#ff6600;">table above</span></div><br /><br /><p><span style="color:#ff6600;">The data items from the search are highlighted in </span><span style="color:#cc33cc;">PURPLE</span></p><br /><br /><div><br /><tr><br /><td width="60%" colspan="" class="ms-vb"><br /><table width="100%" border="0"><br /><tr><br /><td width="20"><br /><img src="_layouts/images/CMSEditSourceDoc.GIF"></img><br /></td><br /><td width="20%"><br /><b>Title:</b><br /></td><br /><td><br /><span style="color:#cc33cc;"><xsl:value-of select="title" /><br /></span></td><br /></tr><br /><tr><br /><td width="20"><br /><img src="_layouts/images/memberother.gif"></img><br /></td><br /><td width="20%"><br /><b>Author:</b><br /></td><br /><td><br /><span style="color:#cc33cc;"><xsl:value-of select="author" /><br /></span></td><br /></tr><br /><tr><br /><td width="20"><br /><img src="_layouts/images/LINKTOPAGE.GIF"></img><br /></td><br /><td width="20%"><br /><b>Link:</b><br /></td><br /><td><br /><a href="{url}" target="_blank"><br /><span style="color:#cc33cc;"><xsl:value-of select="title" /></span><br /></a><br /></td><br /></tr><br /><tr><br /><td width="20"><br /><img src="_layouts/images/bizdatacontentsource.gif"></img><br /></td><br /><td width="20%"><br /><span style="color:#000000;"><b>Description:</b><br /></span></td><br /><td width="70%"><br /><xsl:if test="description != ''"><br /><span style="color:#cc33cc;"><xsl:value-of select="description" /></span><br /></xsl:if><br /><xsl:if test="description = ''"><br />No Description Added<br /></xsl:if><br /><br /></td><br /></tr><br /></table><br /></td><br /><br /><td width="30%" colspan="" class="ms-vb"><br /><table width="100%" border="0"><br /><tr><br /><td width="20"><br /><img src="_layouts/images/CHNGCOL.GIF"></img><br /></td><br /><td width="40%"><br /><b>Document Owner:</b><br /></td><br /><td><br /><span style="color:#cc33cc;"><xsl:value-of select="documentowner" /></span><br /></td><br /></tr><br /><tr><br /><td width="20"><br /><img src="_layouts/images/ICODCC.GIF"></img><br /></td><br /><td width="40%"><br /><b>Document Status:</b><br /></td><br /><td><br /><span style="color:#cc33cc;"><xsl:value-of select="documentstatus" /></span><br /></td><br /></tr><br /><tr><br /><td width="20"><br /><img src="_layouts/images/CAT16.GIF"></img><br /></td><br /><td width="40%"><br /><b>Document Category:</b><br /></td><br /><td><br /><span style="color:#cc33cc;"><xsl:value-of select="documentcategory" /><br /></span></td><br /></tr><br /><tr><br /><td width="20"><br /><img src="_layouts/images/VERSIONS.GIF"></img><br /></td><br /><td width="40%"><br /><b>Document Version:</b><br /></td><br /><td><br /><span style="color:#cc33cc;"><xsl:value-of select="documentversion" /></span><br /></td><br /></tr><br /></table><br /></td><br /></tr><br /><tr><br /><td width="100%" colspan="2"><br /><font color="dodgerblue"><br /><b>Notes:</b> This item was <b>modified</b> on <<span style="color:#cc33cc;">xsl:value-of select="write"</span> /><br /> This item is <b>ranked</b> at <xsl:value-of select="rank" />/1000<br /> This item <b>size</b> is <<span style="color:#cc33cc;">xsl:value-of select="size"</span> />B<br /><br/><br/> <b>Highlight Summary</b> : <<span style="color:#cc33cc;">xsl:value-of select="hithighlightedsummary"</span> /><br /></font><br /></td><br /></tr><br /><tr><br /><td width="100%" colspan="2"><br /><hr class="ms-consolehr"></hr><br /></td><br /></tr><br /><xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1"><br /><tr><br /><td width="100%" colspan="2" class="ms-vb"><br /><span ddwrt:amkeyfield="" ddwrt:amkeyvalue="string($XPath)" ddwrt:ammode="view" /><br /></td><br /></tr><br /><br /></xsl:if><br /></xsl:template><br /></xsl:stylesheet> </div><br /><br /><div></div><br /><br /><div>Although this is a simple table, I hope this provides you a primer into how to modify your search results.</div><br /><br /><div></div>Dave Nixonhttp://www.blogger.com/profile/02929662632182345878noreply@blogger.com0