in

SharePoint Blogs

The Best Place for SharePoint-related Blogs

echef

From the cluttered (and clustered) brain of Josef Nielsen... A great place for Food, Friends, and... uh... SharePoint of course!
  • Adding "Jump to ID#" to a list view...

    So there have been a few times where a user has wanted to jump to a specific record number in larger lists... This little bit is nice on the top of the page.  Add a content editor web part to the top of your page and add the following code in the source editor:

    <script language="javascript">
    function SubmitSearchForm()
        {
            var IdToGet = document.getElementsByName("IdSearchField")(0);
            if(IdToGet)
                window.location.href="dispform.aspx?Id=" + IdToGet.value;
        }
    </script>

    <table cellpadding="5">
    <tr>
    <td>Enter the ID number to filter on</td>
    <td><input type="text" name="IdSearchField" value=""/><input type="button" value="Go" onclick="java-script:SubmitSearchForm()"/></td>
    </tr>
    </table>

    Take out the "-" in java-script above (Blog blocks it as a script otherwise)... :)


  • Email Enabled List Alias Management

    Ever notice that there is not way to centrally manage or get information about email aliases?  Oh that annoys me!  So I did what any self respecting geek would do, and I started taking it apart...  Here are a couple SQL utility scripts to help you get more out of your SharePoint!  Standard Disclaimer - Don't mess around with the DB... You can break stuff!  Now, here's the goods:

    -- SQL Script to find out where an Email Alias is in use

    -- Written by Josef Nielsen, 2008
    -- nielsenjl_at_ldschurch.org
    --
    http://www.sharepointblogs.com/echef

    -- Run this script against the Farm Configuration DB
    SELECT [Alias], [Deleted], [SiteMap].[Path], [Objects].[Name], [ListId]
      FROM [WSS_Farm_Config].[dbo].[EmailEnabledLists]
        INNER JOIN [SiteMap] ON [EmailEnabledLists].[SiteId] = [SiteMap].[Id]
        INNER JOIN [Objects] ON [SiteMap].[DatabaseId] = [Objects].[Id]
    -- Change this value to the Alias you are looking for
    WHERE [Alias] = 'MyEmailAlias'  -- This is the Name part of Name@SharePoint.server.com

    -- Run this script against the Content DB that the Site resides on
    SELECT [tp_Title], [tp_ServerTemplate], [tp_ItemCount], [tp_Description], [tp_EmailInsertsFolder], [tp_EmailAlias], [tp_Fields], [tp_ContentTypes], [tp_DefaultWorkflowId]
    FROM [WSS_ContentDB_01].[dbo].[AllLists]
    --Replace the GUID Below with the GUId of the List you are looking for
    WHERE [tp_Id] = 'A4BB3401-3161-430A-B330-42143C3DE879'

     

    So, what do you get out of this?  Well, the first script, run against your Config DB will give you the managed path and site collection name where that alias is in use.  It will also tell you which content DB contains that site collection.  It also gives you a GUID for the List.

    In the second script, add the GUID you got for the list and run it against the Content DB that was also specified by the first script.  This will give you the friendly name of the list that uses this alias, as well as a few other yummy bits of data about this list.

    Enjoy!

  • Pre-populating Form Fields for a New Item

    So for surveys and such I thought it would be nice to pre-populate a SharePoint List "new" form with some data from the link... This makes it very nice for surveys and such from users.  In this case it was to automate and remove error from some user feedback for our helpdesk.  So what I did was make the URL contain an extra parameter for a field value, then I added some JavaScript to the NewItem.aspx page in that list.  This script is specific to one field one (as you can tell by the long auto-ID).  Here is the script I used:

        function getURLParam()
        {
            var strReturn = "null";
            var strHref = window.location.href;
            //find the "Ticket" parameter
            if ( strHref.indexOf("?") > -1 )
            {
                var strQueryString = strHref.substr(strHref.indexOf("?")+1);
                var aQueryString = strQueryString.split("&");
                for ( var iParam = 0; iParam < aQueryString.length; iParam++ )
                {

                  //find the Task Parameter
                  if (aQueryString[iParam].indexOf("Ticket=") > -1 )
                  {
                    var aParam = aQueryString[iParam].split("=");
                    strReturn = aParam[1];
                    break;
                  }
                }


                //insert parameter to Task Field

    document.aspnetForm.ctl00_m_g_2a4ef5db_f38c_4101_b1e9_bd5bce3e5a04_ctl00_ctl04_ctl01_ctl00_ctl00_ctl04_ctl00_ctl00_TextField.value = strReturn;
             }
        }
    _spBodyOnLoadFunctionNames.push("getURLParam");

    Notice the execute line, using _spBodyOnLoadFunctionNames.  This is required to get the script to execute after all the content has been populated.  The URL to feed this function would look something like this:

    http://sharepointserver.company.pri/sites/feedback/lists/tickets/NewItem.aspx?Source=http%2A%2F%2Fsharepointserver%2Ecompany%2Epri%2Fsites%2Ffeedback%2FPages%2FThannkYou%2Easpx&Ticket=123456

    Two things to note... first, the "Source" parameter needs to be Escaped (using "%" codes for all symbols), and second, that it doesn't have to be where you came from... It is actually where you go to when you click OK or Cancel.  In this case, I'm sending the user to a Thank You page since they have filled out the feedback.  This can be anything, including a custom page with code to close the browser window if you want.

  • Scripting the "Connect to Outlook" function

    You've got to love the "Actions, Connect to Outlook" function in SharePoint lists... Handy for offline viewing of data, nicer GUI for detail entry, etc.  Wouldn't it be nice to automate the connection of these things for a team or a project, or even a division or company?

    You can force these connections via script...  They are URL based using the "stssync://" protocol, which depends on the Office WSS services, a shared component of the desktop Office Suite.  You can find the specific call to connect a library to Outlook (much easier to let SharePoint format it that create from scratch) on any of the AllItems.aspx default list pages for a library or list that is "Outlook Friendly", including Tasks, Calendars, and Document Libraries.   View your page source (on an IE browser, as this is not available in other browsers) and looking for the following:

    <ie:menuitem id="zz23_OfflineButton"

    There is a lot more to this element, which is jammed on a very long line containing about 6 of these <ie:menuitem> elements.  Specifically out of this element you want to get the "onMenuClick" action, which is a javascript call to "ExportHailStorm".  You will need a copy of this function in your script as well, as this is the function that creates the stssync call.  It is located in the init.js file, located in 12\templates\layouts\1033 folder (for US versions)...

    The call to ExportHailStorm should look something like the code below, although I've added line breaks to make it readable. 

    ExportHailStorm(
       'documents',
       'http:\u002f\u002fsharepoint.company.com\u002fteam\u002fsitename\u002fsandbox',
       '{ac5b6eaf-744a-4f73-a2e1-6e35b81f109e}',
       'Sandbox',
       'Test Files',
       '\u002fteam\u002fsitename\u002fsandbox\u002fTest\u002520Files',
       '','\u002fteam\u002fsitename\u002fsandbox\u002fTest Files');"

    You can use these parameters with the MS code in init.js for ExportHailStorm to make your own script with multiple connections for Outlook.  Each call to ExportHailStorm ends in a window.location.href call to the newly created link, which for a document library will look something like this:

    stssync://sts/?ver=1.1&type=documents&cmd=add-folder&base-url=http:\u002f\u002fsharepoint.company.com\u002fteam\u002fsitename\u002fsandbox&list-url=\u002fteam\u002fsitename\u002fsandbox\u002fTest\u002520Files&guid={ac5b6eaf-744a-4f73-a2e1-6e35b81f109e}&list-name=Test\u520Files&site-name=Sandbox

    These strings can be captured and put in to a simple vbscript or powershell script or even a bat file (run iexplore.exe <url>) and executed in a post setup command, a login script, or embedded in a web page on the intranet (ie, click here to connect standard outlook folders)...

  • MSCS Watcher released

    For a few years now I have been making due with a simple notification system for MSCS fail-over clusters that implemented either a script, or later, an application that started as the last resource in the cluster to send an email letting me know the cluster group is online.  The biggest problem with this is that it doesn't let you know when you have unrecoverable failures.  It also is a pull-type polling device, on;y firing at intervals or when it starts up.

    I decided to fix this.  There currently is not much (if anything) that allows Cluster notification for the MS platforms in the OpenSource arena, so I jumped in a started a simple, yet useful project to make just that.  The end result is the MSCS Watcher.  It is a .Net 2.0 OpenSource project that utilizes the MSCluster WMI objects, specifically the EventResourceStateChange object.  I also used the Cluster Automation API to grab the current state of the cluster for reporting in the SMTP notifications.  This is the first cut at a push-style cluster monitor for me, a complete re-write of the previous MSCSWatcher I had made for personal use.  The pervious version also included SQL tables for historical and current state data. I've removed those from this version to simplify things, but I'm thinking of taking another cut at it in the future and putting it back in.

    Originally I was trying to write an event handler for the events raised from the API for ClusSrv, but this involved writing a Wrapper for C++ events, and I just didn't have the time to get in to that right now...  I ended up using a ManagementEventWatcher to grab the WMI events thrown by the cluster service.  My first thoughts for the actual notification was to allow it to fire an executable, to help try it in to other monitoring tools.  I decided to discard that idea when I realized it really didn't do me much immediate good.  Instead, I decided to have it simply fire off an SMTP message.  That stuck with my goal of keeping it simple.

    The basic functionality of this thing is that it runs as a service (I recommend clustering it on all nodes in your cluster) and waits around for any of the resources in the cluster to change their state. (ie online to failed, offline to onlinepending, etc.).  When a state change event is detected, the service records the change and does a scan of the cluster group that holds that resource.  It then does a little logic to avoid sending extra messages and if it determines the circumstances are right, it sends a summery of the cluster group that owns the resource that triggered the event.

    I decided that it is such a pain that there really isn't much out there either in the form of OpenSource utilities for Clusters or sample code to work with them that I would just give the whole thing away... So it is out on CodePlex now... If you use MS Clustering and don't know when your cluster fails over, go grab a copy and try it out :)

    http://www.codeplex.com/mscswatcher

  • MS-SPC2008 - Day 3

    Day three was quite a long one, filled with some great content.  The day started out with a Keynote by Greg LeMond, the American Cyclist who won the Tour de France 3 times in the late-80's.  He shared the amazing story of who he got to the top, only to fall and struggle back up to the top.  His story is a great one, and shows his determination and character.  A great summery of life he gave is that you never hit the last finish line.  those looking the the finish line as the end, will hit an end.  Those who always look to the next finish line will continue to progress.  He gave some great insights on the current state of the Tour de France as well.

    Joel Oleson and Bob Fox (with a guest appearance by Todd Klindt) started off the morning's technical forums with a great presentation on the benefits and features available when using SharePoint 2007 on Windows and SQL 2008.  Joel did most of the talking, including some bad jokes :), while Bob drove.  Joel hinted strongly (with a "wink, wink") that this is the last version of SharePoint that will support 32-bit environments.  He said that the performance gains of the 64-bit environment were so great, that there really was no reason anyone should be staying with 32-bit server environments anymore.  Key Windows 2008 features shown off were the Server Manager, which replaces Computer Management, the Event Viewer, which now has alerting and additional functionality, and the task scheduler.  Another major key feature touted was the performance improvements over previous Windows versions.  Both the SMB core and the TCP stack have been overhauled to give major performance improvements on file transfers.  This is up to 500% in some cases (from what the slides showed anyway)!  IIS7 improvements showed a 10% gain in requests that could be served, which is pretty substantial in and of itself.  Todd Klindt was invited up to show off a couple key benefits in SQL 2008.  Earlier, Tom Rizzo had quickly shown us SQL redundancy, but Todd focused on Admin immediately justifiable gains.  The two he showed off were native encryption, to increase the protection of data physically, and native compression, which will save about 20-35% on disk and time in backups.  Not quite as good as the benefits RedGate will give you, but pretty darn good for Out-of-the-Box.  The demos were interspersed with jokes about Bob 1.0, Eric Shupps' hat, and joking promises that AC would buy the first round at his SharePoint by Day, SharePint by Nite event that evening.

    One would think that would fill an entire day... but wait... There's more!  Heather Solomon did a two-part branding show in the main ballroom (Huge! - 4 monster projections screens!).  I missed the first, as I couldn't pass up an opportunity to watch Bob at work, but I stopped in for the second.  Heather's a great resource who really knows her stuff, and she passed out some great hints and tips on getting started in branding SharePoint sites.  Her strongest tips were to either hire someone or learn CSS inside and out.  It is VERY useful in branding SharePoint.  For those learning CSS, she recommended a few of the O'Reilly books and the Zen Garden CSS site.  Other hints she dropped were to make sure you use Contextual Selectors in your CSS and QA, QA, QA... You never know what other bit of SharePoint might share that 1 style (out of over 4000!), so make sure you test fully.

    I stopped in on Todd Klidnt's STSADM session to see if I could learn a few new tricks... I'm pretty good with a command line, but I've heard Todd knows his stuff... Although the session started off a bit slow (mostly because of a big lunch that had everyone snoozing), Todd showed off just what you could do with that one command-line utility (with over 180 commands in it!).  Some of the things I gleaned were around Backup and Recovery (I don't use the native backup, I use AvePoint's DocAve product), the DatabaseRepair operation for cleaning up orphaned objects (I'm having this problem right now), and some of the new functionality in the MergeContentDBs operation, which can be used to merge or separate Content Databases.

    Last for the day, I parked in Ted Pattison's Solution Deployment session.  I thought my brain was full before!  Ted showed off some great utilities and practices for building solutions, including a great tool he helped design called STSDEV, which has built in templates and MSBuild scripts for creating your .ddf and Manifest.xml, and more importantly, updating them as you work and compile!  I'm downloading a copy for myself as I type this...  He also showed some great examples of how to manually create feature receivers with OnFeatureDeactivated methods to manual undo changes you Feature may have made.  Features do not uninstall the artifacts they install, nor will they overwrite existing files (ie installed, source updated, retracted, then reinstalled).  His demo code is posted here, and shows some great examples.

    Turns out that I've been pushing the torn ligaments in my foot a bit much this trip, and I'm having trouble walking, so I'm spending today reviewing my notes, downloading tools, practicing some of the tricks I've gleaned, and catching up on some of my workload!  There looked to be some good presentations today, including a couple on using the new MS Extranet Solution Accelerator and of course Dustin's SPD presentation, which is always good! 

  • MS-SPC2008 Day 2

    So, the second day's down, and was a pretty good day... I did find out that the Vendor hall wasn't as good as I though, and they have been closing it during the sessions, which I suppose makes sense, but is annoying if you want to skip a session and check out some products... Oh well.  I caught a couple good sessions today, starting with Todd Bleeker's Workflow from SPD to VS.  It was a fast and furious session, and he didn't get a chance to complete the entire process, but he did get to show us some critical transformation steps, including an inside step that is not currently documented anywhere from Microsoft (although Paul Schaeflein will be blogging this very extensively)... this is the parent node that has to be added to the xml file for the Initiation Page...  Specifically this is the <Instantiation_FieldML> tag for the Fields block and the <Initiation_FieldML> tag for the Parameters block.  I look forward to seeing what Paul documents for this process...

    I tried hitting a session from some of the Rangers on Performence, but the session before it over-ran by about 30 minutes (yes, not 3 or 5 minutes, but 30 minutes!)... By the time I got in there, the place was packed from people who just stayed from the previous session and folks that came in on the over-run and took seats... With it being standing room only, I bowed out and took the time to catch up on some work... It looked like it would be a good session, nothing revolutionary, but still good content.  Not sure if thy hit Web Gardens, but I know they talked about BLOB caching and output caching, both of which are two edged swords that can really help, or waste memory, depending on your usage profile.

    I grabbed a repeat performance from both Andrew Connell and Todd Baginski, who both have given these presentations a number of times... As usual, they both hit the mark with their content... Andrew's topic was deploying solutions in a publishing environment, but it really was repeatable, dependable development process in SharePoint.  He blazes through it pretty quick as he is very familiar with the content, and covers a lot of ground.  I've put some of his practices in to play from the last time I caught his presentation, but wanted the refresher for dealing with content types and site columns in features.  He was unfortunately struggling with a rough cough, but his voice held through... Hope your feeling better AC!

    Todd has a great presentation on BDC utilization and how easy it is, which I caught months ago, but haven't used.  As usual, Todd is a great presenter with a lot of knowledge, and is always willing to share that knowledge, even offline through emails.  Todd wrapped his entire demo site up in a site template that he is posting on his site... Go check it out even if you missed the conference... He's included sample code and everything...

    I ended with a session by Bill English from Mindsharp on Search.  He gave some great diagrams and discussion on Search on the theory behind making things searchable.  He focused on why taking the time to build a taxonomy is important, as well as the role of social computing (MySites) in finding information.  It was primarily a slide-deck presentation, compared to AC's and Todd's mostly demo sessions, but had some good diagrams and architecture information.  One great quote he through out is that "dumping file-shares and folders of documents in to SharePoint with Taxonomy and metadata is just automating Chaos...", playing of course on the quote from Dorothy Graham.

    Good content, and tomorrow looks to be even better... :)

  • MS-SPC2008 - Day 1 Summery

    Boy, I wish Connections had been setup as good as this one is... From the starting blocks, I have been impressed with how good this conference is setup.  I unfortunately am starting this conference off with a torn ligament, but I'm limping along as best as possible.  I ended up missing the first couple of sessions today, unfortunately, due to both production issues and my foot..

    I started the day off by trying out public transportation and taking the bus... It wasn't too bad, except when I went to come home I realized the route getting there was a one-way street, and I didn't know what street the return route was on... I ended up walking all the way back to my hotel, which was about a dozen blocks away...  Could have been better, but I brought it on myself :)

    My first impressions:  There are a lot of attendees, and they are scaled up correctly to handle all of us.  There seems to be enough staff around all the time, and enough food.  Rather than barcodes or swipe cards, they are using RFID chips in the card (big-brother is watching!)...  So vendor scanning is pretty simple.  Another thing I really like is that unlike the recent Connections event, the vendor hall was open the entire time.  I started off in the hall, chatting with a few folks while the crowds were small...  I got a chance to talk to Ben Curry at the MindSharp booth... If you haven't seen his blog, check it out... He has some great resources there.  I used his stsadm white-paper, along with a post from Joel Olsen and another from Alpesh Nakars to create a script utility to generate automated install scripts for full farm installations (I'll post on that and see about releasing it on CodePlex when I get the rest of the bug out of it). He's a great guy and a good resource... :)

    I also got a chance to drop by the SharePoint Bootcamp booth and visit my friends from SharePoint Experts, Todd Baginski, Dustin Miller, and Heather Solomon.  Todd pointed me at a cool new option from Microsoft called "Shared Source" that allows customers and partners to get access to portions of source-code for Windows and major software, including WSS.  Get more details here.  He also clued me in on the awesome snowfall this year in Colorado (He's a ski-nut, if you didn't know!).

    I got a chance to talk to so vendors about some very interesting and promising new products, including the new search suite from BA-Insight and the eSense Visualizer from NSE, but I'll blog about those another time.

    I missed some of the beginning of the First Keynote from Bill Gates, but caught the last half of it... I cracked up at one thing he said, and had to write it down... When asked a question from the audience about competition from Google, and their productivity tools, he admitted that they are the industry standard for consumer search (currently, he joked), then said about their productivity/business tools. "The day Google releases a business productivity product is generally its best day... although I might be a bit biased."

    The following Keynote by Kurt DelBene was good, but fast-passed... It had to be to get so much information in it.  There were a few new SharePoint sites showcased I hadn't seen before, like Krogers, StarBucks Intranet, and Ford's Internal Marketing site.  Also showcased was General Mills internal Marketing site search, which is a custom made Silverlight solution with rotating carousels and dragable results, result filtering and all sorts of goodness.  A couple other nice resources I saw quick demos of (courtesy of Tom Rizzo) were the Cross Site-Collection SharePoint Configurator and the Extranet Collaboration Toolkit.  Both very awesome toolsets. :)

    Tomorrow looks to be loaded with excellent options, like AC's publishing demo, Todd's BDC presentation, not to mention Ben Curry's Automating installs presentation and Todd Bleaker's Workflow in VS presentation...  Like I said, good stuff :)

  • Mutex Mischief

    To clean up an old farm from some setup errors, I recently rebuilt the farm from bare metal, re-attaching all the content DB's after the rebuild to prevent data loss.  Imagine my horror when after 100% successful testing, and flawless installation, the first page I pull up shows this:

    Mutex could not be created.

    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
    Exception Details: System.InvalidOperationException: Mutex could not be created.

    After some research I learned that this is an ASP.Net issue that occasionally crops up when an app pool identity (ie the Web App Service Account in SharePoint) is not a local administrator.  When setting the identity, access to the Windows Registry key where the IIS Mutex Key is kept is supposed to be granted (obviously not an issue for local admins).  If it does not have access to read this key, the above error is generated.  To add it, you have to modify the key and grant permissions for you identity account(s) to read that key, then close all Mutex Threads (or just reboot the server).

    A big thanx to Jerry Orman who documented this issue and the fix here:

    http://blogs.msdn.com/jorman/archive/2006/07/24/system-invalidoperationexception-mutex-could-not-be-created.aspx

    As a side note to any trying to implement least-permission security on a locked down server, make sure your local WSS_WPG group has full control of the Windows\Temp folder, or you'll get an odd ASP.Net Temporary files error (that points to a bogus dir).  The WSS_WPG group contains all your Web App Identity accounts, and is created by the SharePoint Installation.

  • Image Changes on Hover

    It sees there are a lot of large javascript samples out there to change an image source on mouse over, but they all seem overly complex.  Here's a little one I made recently for a project I was working on:

    <script>
    function imgHover(imgObj,imgSrc){
        imgObj.src=imgObj.getAttribute(imgSrc);
    }
    </script>

    And here's some HTML to demonstrate how to use it:

    <img
        src="
    /PublishingImages/main.jpg"
        out="/PublishingImages/main.jpg"
        over="/PublishingImages/main_01.jpg"
        onmouseover="java-script:imgHover(this,'over');"
        onmouseout="java-script:imgHover(this,'out');"
        alt=""
        border=0
    />

    Change the "java-script" and remove the "-" to make it work... It won't show up on the blog post otherwise (it tries to run it).  I've found it easiest to just embed the script in the master page, then I can use img tag with the extra attributes on any page in my site I want...

  • Security Trimming WebControls and ASP Objects

    I hadn't used this yet, and had cause to this week.  It works slick, and is pretty configurable... I used it to hide the SiteActions button on list pages for members, but not admins, as well as admin web parts embedded in a page.  It works with Web Parts, Web Controls, and other ASP.Net objects (ie. SharePoint:*, etc.).  Wrap the content you want trimmed in the following code (using SPD):

    <Sharepoint:SPSecurityTrimmedControl runat="server" PermissionsString="BrowseDirectories">
    [Content to Trim]
    </Sharepoint:SPSecurityTrimmedControl>

    You can then swap out the "BrowseDirectories" with whatever you need for the trimming.  Here are the one's I've found handy so far:

    • BrowseDirectories = Anyone but Limited Read (Anonymous is Limited Read)
    • ManageWeb = Site Collection Admins
    • ManageSubwebs = Site Owners
    • AddListItems = Site Members and specified list contributors

    Here's a link to all the defined values in the SPBasePermissions Enum.

  • Adding category titles to Blog sites (category.aspx)

    I recently found an application of the Blog template that was a great fit, but needed the Category title listed on the top of the page when you click a category from the default page.  Normally, it is not visible anywhere except in the URL as a parameter, and in the categories of the posts listed. 

    The primary content of the page is displayed by a ListViewWebPart embedded in a table in the aspx file.  It starts like this:

    <table cellpadding=0 cellspacing=0 style='padding: 5px 10px 10px 10px;'>
               <tr>
                <td valign=top>
                    <WebPartPages:WebPartZone runat="server" FrameType="TitleBarOnly" ID="Left" Title="loc:Left"><ZoneTemplate>
    <WebPartPages:ListViewWebPart runat="server" __MarkupType="xmlmarkup" WebPart="true" __WebPartId="{973762DE-3C5C-47B0-B80C-895B16BEDD6E}" >
    <WebPart xmlns:xsi="
    http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.microsoft.com/WebPart/v2">
      <Title>Posts</Title>
      <FrameType>None</FrameType>
      <Description>Use the Posts list for posts in this blog.</Description>

    I added the following table row to the table above (before the webpart's row) to display it.

               <tr>
                <td><script language="javascript">
    function getURLParam()
        {
            var strReturn = "null";
              var strHref = window.location.href;
            if ( strHref.indexOf("?") > -1 )
            {
                var strQueryString = strHref.substr(strHref.indexOf("?")+1);
                var aQueryString = strQueryString.split("&");
                for ( var iParam = 0; iParam < aQueryString.length; iParam++ )
                {
                  if (aQueryString[iParam].indexOf("Name=") > -1 )
                  {
                    var aParam = aQueryString[iParam].split("=");
                    strReturn = aParam[1];
                    break;
                  }
                }
                var fields,i;
                  fields = document.getElementsByTagName('DIV');
                  for( i = 0; i < fields.length; i ++ )
                  {
                    if(fields[i ].innerHTML.indexOf("::") != -1)
                    {
                         fields[i ].innerHTML = unescape(strReturn);
                    }         
                }
             }
        }
        _spBodyOnLoadFunctionNames.push("getURLParam");
                </script>
                 <div class="ms-sitetitle">::</div></td>
               </tr>

    Note the use of the _spBodyOnLoadFunctionNames.push method to fire the script... This is documented on the SPD team's blog here.  This is so you can embed your javascript in master or aspx and have it execute correctly once the entire page is loaded.  I probably could have gotten away without it here, but used it to be safe. 

    The script basically just looks for the <DIV> tag containing "::" and replaces it with the unescaped text from the "Name" parameter in the URL (Looks like http://MySharePointServer/sites/ICS/blog/category.aspx?Name=General%20Questions).  That is how the category is passed from the hyperlink to the category.aspx page.

  • How to clear off a SQL server quickly...

    So I was asked in an online community how to quickly clean off a SQL Server to rebuild a MOSS Farm.  Although it won't clean up and "add-ins" to the system DB's or any security identities, this does a quick and dirty job...

    IF object_id('tempdb..#AllDatabases') IS NOT NULL DROP TABLE #AllDatabases

    CREATE TABLE #AllDatabases
    (
                id          INT IDENTITY,
                name     NVARCHAR(128)
    )

    DECLARE @dbname   nvarchar(128)
    DECLARE @counter  int
    DECLARE @maxcount int

    INSERT INTO #AllDatabases SELECT name FROM master..sysdatabases WHERE name NOT IN ('tempdb', 'master', 'model', 'msdb')

    SET @counter = 1
    SELECT @maxcount = MAX(id) FROM #AllDatabases

    WHILE @counter <= @maxcount
    BEGIN
        SELECT @dbname = name FROM #AllDatabases WHERE id = @counter
        Print 'Deleting DB ' + @dbname
        --Uncomment the next line to enable deleting all User DBs
        --DROP DATABASE @dbname
        SET @counter = @counter + 1
    END

    IF object_id('tempdb..#AllDatabases') IS NOT NULL DROP TABLE #AllDatabases

  • Service Account problems...

    I was asked a question the other day that I thought might be good to share...  The company had made some changes and suddenly SharePoint stopped working, and they got these errors in the Even log every minute (italics added for anonymity):

    --------------------------------------

    Event Type:      Error
    Event Source:      Office SharePoint Server
    Event Category:      Office Server Shared Services
    Event ID:      6482
    Date:            date
    Time:            time
    User:            N/A
    Computer:      computername
    Description:
    Application Server Administration job failed for service instance Microsoft.Office.Server.Search.Administration.SearchServiceInstance (ea45ac67-ede8-4be3-812c-193b10678515).
    Reason: Logon failure: the user has not been granted the requested logon type at this computer
    Techinal Support Details:
    System.ComponentModel.Win32Exception: Logon failure: the user has not been granted the requested logon type at this computer
       at Microsoft.Office.Server.Search.Administration.SearchServiceInstance.SynchronizeDefaultContentSource(IDictionary applications)
       at Microsoft.Office.Server.Search.Administration.SearchServiceInstance.Synchronize()
       at Microsoft.Office.Server.Administration.ApplicationServerJob.ProvisionLocalSharedServiceInstances(Boolean isAdministrationServiceJob)
    --------------------------------------

    And:
    --------------------------------------

    Event Type:      Error
    Event Source:      Office SharePoint Server
    Event Category:      Office Server Shared Services
    Event ID:      6641
    Date:            date
    Time:            time
    User:            N/A
    Computer:      computer
    Description:
    The SSP Timer Job Distribution List Import Job was not run.
    Reason: Logon failure: the user has not been granted the requested logon type at this computer
    Technical Support Details:
    System.ComponentModel.Win32Exception: Logon failure: the user has not been granted the requested logon type at this computer
       at Microsoft.Office.Server.Utilities.WindowsSecurity.GetUserTokenFromCredentials(String userDomainName, String password, LogonType logonType)
       at Microsoft.Office.Server.Utilities.WindowsSecurity.GetUserTokenFromCredentials(String userDomainName, String password)
       at Microsoft.Office.Server.Administration.JobHandler.Execute(Object state, Boolean timedOut)
    For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.

    --------------------------------------

    Turns out they had changed the service account (and done it correctly), but they forgot to grant the Logon as Service security right in the Local Security Admin tool for that account.  A good thing to remember :)  This is done automatically when run the SharePoint Product Install and Configuration Wizard (or run psconfig -cmd configdb -create)...

  • A document repository by any other name is still... well... just a list...

    So this is not so much technical as it is theoretical, but for requests I've gotten, here is a brief on SharePoint Lists. 

    Everything in SharePoint (WSS, MOSS, MSS, etc) is a list.  This goes from a document lirbary to a publishing web part page library to a custom list, to the galleries that hold master pages and web parts, to the very site security that allows people to access or not access your content.  This is done in a very OO method, where all of these items inherit basic list functionality.  Many of these also add additional functionality through the SharePoint object model. 

    A simple example is the custom list.  This is a list that starts out as just the basic require modified and modified by columns, along with a "name" column. You can add to this just about anything you can think of, either through the standard field types (text, multi-line text, hyper-link, file, etc.) or through site columns.  If you haven't experimented with site columns, check them out...  They are quite cool and give you the ability to create a field that is completely reusable.  I usually make a meta-data or "tag" site column on all my sites, to make it easy to add tagging or meta-data searches to my lists.  Ted Pattison actually has a few great resources available for download, like this screencast on Site Columns.

    You can also extend existing list templates, like the task or document library lists. Go to any list and select Settings, List (or Library) Settings.  You'll get a similar screen each time, listing general settings and permissions options, as well as a list of Columns and Views. This is where you can modify or add (or remove) columns.  You can use this to add additional options to your list, like meta-data.  If you have a task list, you can add fields for things like estimated cost, or project codes. If you have a calendar, you can add a column for classification or category.  This changes the built-in templates for lists from limited examples, to jumping-off points for customized anything-you-wants.

    Another example of this is the security list.  This is a list of individuals and their access for your site.  You can see some of the system-level activities (and a few screen shots) of in a previous post of mine about the behavior of My SharePoint Sites.  The gist of this is that if you go to the user information page of a root site collection (that's the "people" section of the people and groups admin pages), you can actually select "List Settings" just like any other list, and see the settings for the user list.  You can, in fact, even add columns to the user list, such as meta data or notes.  This could also include mapping extension information for programmatic user cross-matching to alternate data sources by user identity.

    Another things that is great is that the list object in SharePoint inherits the ability to have a workflow attached to it.  That means that it is not just document library that benifit, as they are commonly thought of as the target when we talk about workflows.  You can even attach workflows to the user security lists.

    Also, all lists of any sort can be saved as templates (stp files) with or without content in your template gallery (which, by the way, is another list).  This automatically adds that custom list to the appropriate category on the "create" page.  For those willing to adventure a bit farther in to the mirk, there is Content Types.  You can find a great post on the concept behind Content Types (I like to call it the Content Type is to Lists post) at John Holiday's blog.

    So what does this all mean?  I'll say it again... Everything in SharePoint is a list.  Understand that and what it implies to the platform, and you take a big jump forward in understanding how you can make SharePoint do whatever it is you want it to. 

  • Excel Calculation Services (ECS) Invalid Handle error

    Just had this happen to me while testing out a new IIS Build script...
     
    When firing up the ECS on a new farm, if you get the following "Handle is Invalid" error:
     
    System.Security.Cryptography.CryptographicException: The handle is invalid.

       at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
       at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle& safeProvHandle, SafeKeyHandle& safeKeyHandle)
    ... and so on ...
     
    You need to set permissions as follows:
     
    "C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\MachineKeys"
     
    Add Local Administrators - Full
    Add NETWORK SERVICE - Read
     
    Then try firing up ECS...

    I got this error in the Event Log (Applicaiton) as an Office SharePoint Server error with EventID of 6482 (MOSS Shared Services).  Not sure if this is always this ID or not.  It is accompanied by a 7034 event (Topology) telling you to try it again (which obviously wouldn't work with the fix first).
     

  • Getting Search Crawl Details from the DB

    Ok, so I must be on a roll... Here's another glorious script that goes directly to the SharePoint DB's... Don't tell Bill!  As usual, this is not recommended by MS, etc., etc., etc.  This one is to get result sets of your Crawl Details.  It will show each attempt to start/stop/delete a crawl, what it's current status is, when it was requested, started, and finished.  Handy for monitoring your Search crawling with home grown tools ;)

     --Begin Script

    /*
    CrawlLogDetails.sql
    Written by
    Josef Nielsen
    Nov. 2007

    Displays MOSS Crawl Details (Type, status, and times)
    Point this script at your Search DB (ie. SharedServices_Search_DB)
    */

    BEGIN

    -- Create temp tables for System values
    CREATE TABLE [#CrawlStatus](
    [CrawlStatusName] VARCHAR(35),
    [CrawlStatusID] INT
    )

    CREATE TABLE [#CrawlType](
    [CrawlTypeName] VARCHAR(25),
    [CrawlTypeID] INT
    )

    -- Populate Crawl Status System Values
    INSERT INTO [#CrawlStatus] VALUES ('CRAWL_ACQUIRED', 1)
    INSERT INTO [#CrawlStatus] VALUES ('CRAWL_STATUS_INSERTSTARTPAGE', 2)
    INSERT INTO [#CrawlStatus] VALUES ('CRAWL_STARTCHECK', 3 )
    INSERT INTO [#CrawlStatus] VALUES ('CRAWL_STATUS_START', 4)
    INSERT INTO [#CrawlStatus] VALUES ('CRAWL_STATUS_FORBID',  5)
    INSERT INTO [#CrawlStatus] VALUES ('CRAWL_UPDATE_SEED', 6 )
    INSERT INTO [#CrawlStatus] VALUES ('CRAWL_QUERY_DONE', 7 )
    INSERT INTO [#CrawlStatus] VALUES ('CRAWL_STATUS_DELETEUNVISITEDITEMS', 8 )
    INSERT INTO [#CrawlStatus] VALUES ('CRAWL_STATUS_PAUSE', 9 )
    INSERT INTO [#CrawlStatus] VALUES ('CRAWL_STATUS_RESUME', 10)
    INSERT INTO [#CrawlStatus] VALUES ('CRAWL_STATUS_DONE', 11 )
    INSERT INTO [#CrawlStatus] VALUES ('CRAWL_UPDATE_STOP', 12 )
    INSERT INTO [#CrawlStatus] VALUES ('CRAWL_STATUS_STOP', 13 )
    INSERT INTO [#CrawlStatus] VALUES ('CRAWL_STATUS_RESET',  14)
    INSERT INTO [#CrawlStatus] VALUES ('CRAWL_START_DELETE', 15 )
    INSERT INTO [#CrawlStatus] VALUES ('CRAWL_DELETE_CS', 16 )
    INSERT INTO [#CrawlStatus] VALUES ('CRAWL_DELETE_SA', 17 )

    -- Populate Crawl Type System Values
    INSERT INTO [#CrawlType] VALUES ('CRAWLTYPE_FULL', 1 )
    INSERT INTO [#CrawlType] VALUES ('CRAWLTYPE_INCREMENTAL', 2 )
    INSERT INTO [#CrawlType] VALUES ('CRAWLTYPE_DELETE', 6 )

    -- Join MSCrawlHistory to SCrawlHostList and our two temp tables
    SELECT    [CrawlID]
            ,[HostName]
            ,[CrawlTypeName]
            ,[CrawlStatusName]
            ,[RequestTime]
            ,[StartTime]
            ,[EndTime]
      FROM [SharedServices1_Search_DB].[dbo].[MSSCrawlHistory]
      LEFT JOIN [dbo].[MSSCrawlHostList] ON [ProjectID] = [HostID]
      LEFT JOIN [#CrawlStatus] ON [Status] = [CrawlStatusID]
      LEFT JOIN [#CrawlType] ON [CrawlType] = [CrawlTypeID]
      WHERE 1 = 1

      -- Uncomment and use this conditional to filter the results to just one Web App
      --AND [HostName] = 'MySharePointSiteName'
      ORDER BY [RequestTime] DESC

    END

    -- Do a little clean up and get rid of those pesky temp tables
    DROP TABLE [#CrawlStatus]
    DROP TABLE [#CrawlType]

     --End Script

  • Details and manual monitoring of the Content DBs

    So our Ad-Hoc environment started growing a bit faster than we had originally anticipated.  We knew we would have some disparity between site's content size, so we set our content DB max site limits a bit lower than normal (hey, we have 50 of them, so we thought we'd be safe).  The thought was that way we could help balance the sizing by adjusting the max counts on the DB's to reflect the physical size based on content. 

    It quickly became way to much of a pain to manually collate the size details with the site details based on content DB...  So heres a little script I wrote up (ok, modified from my original Site Details script) that pulls all the goodness you could want about a content DB direct from the DB itself... <Insert canned warnings about how MS does not recommend querying the DB directly here>

     

    /*
    ContentDBReport.sql
    written by Josef Nielsen
    October 2007 

    NOTE: You must create a linked server if you use multiple SQL server to house you content DBs
    */ 
     

    BEGIN
    DECLARE
    @ts1 varchar(1000), @ConfigDB VARCHAR(128) 

    -- Set your Config DB Name here if it is different
    SET
    @ConfigDB = 'SharePoint_Config'

    -- This creates a temp table to hold the list of content DBs referenced by the Config DB
    CREATE TABLE [#TempDbList]
    (

    DBname VARCHAR(128),
    DBInstance VARCHAR(128),
    DBServer VARCHAR(128),
    MaxSites INT,
    WarnSites INT
    )

    -- Populate the temp table with content DBs
    SET @ts1 = 'INSERT INTO #TempDbList
    SELECT [DbName].[Name] AS ''DatabaseName'',
    [Instance].[Name] AS ''DatabaseInstance'',
    [Server].[Name] AS ''DatabaseServer'',
    CONVERT(XML, [DbName].[properties]).value (''(/object/sFld/text())[1]'', ''int'') AS ''MaxSites'',
    CONVERT(XML, [DbName].[properties]).value (''(/object/sFld/text())[2]'', ''int'') AS ''WarnSites''
    FROM '
    +'['+@ConfigDB+']'+'.[dbo].[Objects] AS [DbName]
    LEFT JOIN '
    +'['+@ConfigDB+']'+'.[dbo].[Objects] AS [Instance]
    ON [DbName].[ParentId] = [Instance].[ID]
    LEFT JOIN '
    +'['+@ConfigDB+']'+'.[dbo].[Objects] AS [Server]
    ON [Instance].[ParentId] = [Server].[Id]
    WHERE [DbName].[Properties] LIKE ''%SPContentDatabase%''
    AND [DbName].[Properties] NOT LIKE ''%WebApplication%'''

    EXEC (@ts1)

    DECLARE @ts2 VARCHAR(1000)

    --This creates a temp table to hold the end results of the Site Collection lists from all Content DBs
    CREATE TABLE [#TempContentDbList]
    (
    WebApp
    VARCHAR(128),
    DBServer VARCHAR(128),
    DBName
    VARCHAR(128),
    DBSites
    int,
    DBWarnSites
    int,
    DBMaxSites
    int,
    DBSize float
    )

    -- Create a cursor to walk through each content DB
    DECLARE DB_cursor CURSOR
    FOR
    SELECT [DBServer], [DBInstance], [DBName], [MaxSites], [WarnSites]
    FROM [#TempDbList] 

    OPEN DB_Cursor

    -- Declare Variables to populate by Cursor
    DECLARE @vDBServer VARCHAR(128)
    DECLARE
    @vDBInstance VARCHAR(128)
    DECLARE @vDBName VARCHAR(128)
    DECLARE @vMaxSites INT
    DECLARE
    @vWarnSites INT
    DECLARE
    @DBv1 VARCHAR(5000) 

    FETCH NEXT FROM DB_cursor INTO @vDBServer, @vDBInstance, @vDBName, @vMaxSites, @vWarnSites
    WHILE @@FETCH_STATUS = 0
    BEGIN  

    -- Add a backslash for DBServers that are not default instances
    DECLARE @slash VARCHAR(5)
    IF @vDBInstance = ''
    SET @slash = ''
    ELSE
    SET @slash = '\'

    -- Script to insert Content DB details to the temp site summery table
    SET @DBv1 = 'INSERT INTO [#TempContentDbList]
    SELECT [ConfigObjects].[Name] AS ''WebApp'',
    (SELECT '''