Skip to main content
Boman.Biz

Boman.Biz

Go Search
Home
Mobile Monger
  

Boman.Biz > Categories
SQL Script for Simple Recovery Mode and Shrink Databases

Developers quite often set up development environments for SharePoint, Project Server, Commerce Server etc. Once its all done, there will be many databases created on the Microsoft SQL Server containing the various configuration and content databases.  This is fine for a while, but if the development environment hangs around for any length of time, disk space will start to be consumed by SQL.  This is because the default setting for SQL Server is for Full Recovery mode, which is important for production scenarios where incremental backups are taken between full backups.  On development servers however, backups are rarely taken and certainly no backups of the transaction logs so the disk space just continues to be consumed.  If your developer has had the foresight to change the default recovery mode before installation, stop reading – but most of the time its realised later.

To set the Database Recovery mode to Simple and then shrink all the databases you could do it manually through the UI for each database, or just run the following script and then copy the result to a new query window and execute – and your disk space will be free once more.

USE master 

SELECT 'ALTER DATABASE [' + name + '] SET RECOVERY SIMPLE WITH NO_WAIT' from master..sysdatabases where name not in ('master','model','msdb','tempdb') 

SELECT 'EXEC sp_MSForEachDB @Command1 = N''DBCC SHRINKDATABASE (?)'', @replacechar = ''?'''

Decrease the sensitivity of the ASP:Menu control in SharePoint 2007

Today’s code nugget falls into the JavaScript-hackery category:

Recently I had a problem where the fly-out menus in the Global Navigation bar in SharePoint would fly-out and block user’s access to links like “View All Site Content” because they had moved their mouse over the Global nav to get there.

Anyhow the request was to make the Global navigation fly-outs less sensitive.  So the code below inserted on a master page ensures that the fly-out menus only expand after the user has actually hovered their mouse for one second over the actual menu item.  A much less crazy behaviour if you have alot of menus.

 

<script type="text/javascript" language="javascript">
    var intNumberOfMenusToFix = 9;
    var objTimer = null;
    var activeMenu = null;
    
    var tdTopMenuItem;
    var intItemCount = 0;
    
    tdTopMenuItem = document.all.item("zz1_TopNavigationMenun" + intItemCount);
    
    while ((typeof(tdTopMenuItem) != "undefined") && (tdTopMenuItem != null)
            && (intItemCount < intNumberOfMenusToFix)) {
        tdTopMenuItem.onmouseover = function() {
                                activeMenu = this;
                                //Reset the timer
                                if (objTimer != null) {
                                    window.clearInterval(objTimer);
                                    objTimer = null;
                                }
                                objTimer = window.setInterval('HoverDelay()', 1000);
                                }
        tdTopMenuItem.onmouseout = function () {
                                //Reset the timer
                                if (objTimer != null) {
                                    window.clearInterval(objTimer);
                                    objTimer = null;
                                }
                                activeMenu = null;
                                
                                Menu_Unhover(this);
                                }
        tdTopMenuItem=null;
        intItemCount+=1;
        tdTopMenuItem = document.all.item("zz1_TopNavigationMenun" + intItemCount);            
    }

    function HoverDelay() {
        //Reset the timer
        if (objTimer != null) {
            window.clearInterval(objTimer);
            objTimer = null;
        }
        
        Menu_HoverStatic(activeMenu);
    }

</script>
HOWTO: Fake the author information for documents in SharePoint

 

When migrating data into SharePoint it is sometimes necessary to upload pages/documents and set the Created and Modified information.

This can be difficult with minor versioning turned on, so in my case I was able to temporarily switch off Minor version while updating the lists and then turn it back on again.

To actually set the Created and Modified information with out leaving any footprints can be a little tricky, but this is how I did it:

sppTargetPage.CheckOut();

//Get the underlying list item
SPListItem sliTargetPage = sppTargetPage.ListItem;

//Set the publishing contact.
sppTargetPage.Contact = <SPFieldUserValue>;
//Check-In
sliTargetPage.File.CheckIn("Checked in by Data Migration", SPCheckinType.MajorCheckIn);

//Stealth Extra update to set modification date/time
SPListItem sliStealth = sliTargetPage.ParentList.GetItemById(sliTargetPage.ID);
sliStealth[SPBuiltInFieldId.Created] = <Fake Create Date> ;
sliStealth[SPBuiltInFieldId.Created_x0020_By] = <SPFieldUserValue>;
sliStealth[SPBuiltInFieldId.Modified_x0020_By] = <SPFieldUserValue>;
sliStealth[SPBuiltInFieldId.Modified] = <Fake Modified Date>;


//Creates new version if minor versioning turned on.
sliStealth.UpdateOverwriteVersion();
SharePoint UserProfileManager permission problems
Recently I had a problem where I was writing a webpart to modify some user profile values of people other than the logged in user.
 
So I do what I usually do, I call:
 
SPSecurity.RunWithElevatedPrivileges
 
and found that even though I was impersonating, I would still get errors saying:
 
Property Not Editable. This property can only be modified by an administrator
 
or
 
You may only modify your own profile, unless you are an administrator
 
I then I also tried my other tactic of creating the SPSite using the System Token from:
 
SPContext.Current.Site.SystemAccount.UserToken
 
but again no joy.
 
I tried a bunch of different things until I stumbled across this post, that suggested setting the HTTPContect to null just before updating the profile.  I thought that could never work, but I tried it anyway.  His post is unavailable and I only managed to get it through Google Cache!  The sample code was:
 
SPSecurity.RunWithElevatedPrivileges(delegate()
{
    SPSite sc = new SPSite(SPContext.Current.Site.ID);
    ServerContext context = ServerContext.GetContext(sc);
    HttpContext currentContext = HttpContext.Current;
    HttpContext.Current = null;
    UserProfileManager profileManager = new UserProfileManager(context);
    UserProfile user = profileManager.GetUserProfile("DOMAIN\\userName");
    writer.Write(user.PersonalUrl);
    HttpContext.Current = currentContext;
});
 
and to my amazement it works.  It seems with no HTTPContext, SharePoint is unable to determine the current user and so uses the credentials of the actual impersonated user (as it should).
 
Disgusting - but it saved the day.
 
UPDATE: Kamilm posted in the comments below a new method for SharePoint 2010:
 
UserProfileConfigManager upcm = new UserProfileConfigManager(spServiceContext);
ProfilePropertyManager ppm = upcm.ProfilePropertyManager;
CorePropertyManager cpm = ppm.GetCoreProperties();
CoreProperty cp = cpm.Create(false);
ProfileTypePropertyManager ptpm = ppm.GetProfileTypeProperties(ProfileType.User);
ProfileTypeProperty ptp = ptpm.Create(cp);

psp.IsUserEditable = true; // important in this case!
 
ProfileSubtypeManager psm = ProfileSubtypeManager.Get(spServerContext);
ProfileSubtype ps = psm.GetProfileSubtype(ProfileSubtypeManager.GetDefaultProfileName(ProfileType.User));
ProfileSubtypePropertyManager pspm = ps.Properties;
ProfileSubtypeProperty psp = pspm.Create(ptp);
I know the User Profile system is different in SPS2010 - so will have to give this a try.  Thanks Kamlin
 
UPDATE 25-Feb-2011:
If you are interested in the cause of this problem see Yohan Belval's comment below - very enlightening.
 
Changing the message during a Microsoft.SharePoint.SPLongOperation

The SPLongOperation is undoubtedly a Good Thing® to let users know that something is happening during a long processing operation. I had cause to use one the other day, and thought that it would be great to be able to change the message during the processing to let the user know which part of the Long Operation it was up to.

For example:

Using objLongOp As New SPLongOperation(Me.Page)

objLongOp.LeadingHTML = "Leading HTML"

objLongOp.TrailingHTML = "Trailing HTML"

 

objLongOp.Begin()

 

System.Threading.Thread.CurrentThread.Sleep(3000)

 

objLongOp.LeadingHTML = "New Leading HTML"

objLongOp.TrailingHTML = "New Trailing HTML"

 

System.Threading.Thread.CurrentThread.Sleep(3000)

 

objLongOp.End(Me.Page.Request.Url.ToString())

End Using

 

Would result in this screen, for 6 seconds:

I wrote a wrapper class called SPLongOperationEx to make sure that in our example after the first 3 seconds the LeadingHTML and TrailingHTML text is updated with the new values. This way you can have much longer Long Operations and still keep the user happy J

3 seconds later ...

This is a fairly trivial programming exercise once you understand how the SPLongOperation class is manipulating the browser, but I thought I would package it up into a separate class for easy re-use to save people some time.

Download the SPLongOperationEx Class here. (VB.NET)

Thanks to my good friend Adrian Bear from i-PMO, here is the C# version with support for line breaks in the message:

Download the SPLongOperationEX Class here. (C#)

Announcements Transform for CQWP
I was asked to do a roll-up for announcements and was frustrated that the Content Query WebPart does not have a out-of-the box transform for displaying announcements.  I could get the title but that was about it.
 
I have cobbled togther a transform to be put in the ItemStyle.xsl file to give the rolled-up announcements an almost identical look to the normal announcements webpart.
 
Note:
  • You need to add the Dataviewer namespace to your ItemStyle.xsl file.
  • You need to export you CQWP add "Body,text" into your commonviewfields property and import it back in.

<!-- JBoman: Start announcement transform --> 
 <xsl:template name="removeHtmlTags">
  <xsl:param name="html"/>
  <xsl:choose>
    <xsl:when test="contains($html, '&lt;')">
      <xsl:value-of select="substring-before($html, '&lt;')"/>
      <!-- Recurse through HTML -->
      <xsl:call-template name="removeHtmlTags">
        <xsl:with-param name="html" select="substring-after($html, '&gt;')"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$html"/>
    </xsl:otherwise>
  </xsl:choose>
 </xsl:template>
 <xsl:template name="Announcements" match="Row[@Style='Announcements']" mode="itemstyle">
 
  <xsl:variable name="SafeLinkUrl">
      <xsl:call-template name="OuterTemplate.GetSafeLink">
          <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
      </xsl:call-template>
  </xsl:variable>
        <xsl:variable name="LinkTarget">
            <xsl:if test="@OpenInNewWindow = 'True'" >_blank</xsl:if>
        </xsl:variable>
  <xsl:variable name="AuthorName">
    <xsl:call-template name="OuterTemplate.GetGroupName">
      <xsl:with-param name="GroupName" select="@Author"/>
      <xsl:with-param name="GroupType" select="'User'"/>
    </xsl:call-template>
  </xsl:variable>
       
        <xsl:variable name="TextBody">
            <xsl:call-template name="removeHtmlTags">
                <xsl:with-param name="html" select="@Body" />
            </xsl:call-template>
        </xsl:variable>
       
  <xsl:variable name="AuthorID">
    <xsl:value-of select="ddwrt:UserLookup(string(@Author) ,'ID')" />
  </xsl:variable>       

  <xsl:variable name="AuthorEmail">
    <xsl:value-of select="ddwrt:UserLookup(string(@Author) ,'EMail')" />
  </xsl:variable>   
       
<TABLE class="ms-summarycustombody">

 <TBODY>
  <TR>
   <TD class="ms-vb" style="PADDING-BOTTOM: 3px" width="80%">
    <SPAN class="ms-announcementtitle">
     <A onfocus="OnLink(this)" onclick="GoToLink(this);return false;" href="{$SafeLinkUrl}" target="_self"><xsl:value-of select="@Title"/></A>
    </SPAN>
    <BR />
    <table border="0" cellpadding="0" cellspacing="0">
     <tr>
      <td>
       by<xsl:value-of select="'&amp;nbsp;'" disable-output-escaping="yes" />
      </td>
      <!--
      <td>
       <span class="presence-status-icon">
          <img src="/_layouts/images/imnhdr.gif" onload="IMNRC('{$AuthorEmail}')" ShowOfflinePawn="1" alt="" id="{concat('MWP_pawn_',@ID,'type=sip')}" />
       </span>
      </td>
      -->
      <td>
       <a href="/_layouts/userdisp.aspx?ID={$AuthorID}"><xsl:value-of select="$AuthorName" /></a>
      </td>
     </tr>
    </table>

    <!-- Attempt at Presence icon, $ClientId is undefined :( <img src="/_layouts/images/imnhdr.gif" onload="IMNRC('{$AuthorEmail}')" ShowOfflinePawn="1" alt="" id="{concat('MWP_pawn_',$ClientId,'_',@ID,'type=sip')}" /> -->
    <!--     
    <A onclick="GoToLink(this);return false;" href="/_layouts/userdisp.aspx?ID={$AuthorID}"><xsl:value-of select="$Author" /></A>
    <IMG height="1" alt="" src="/_layouts/images/blank.gif" width="3" border="0" />
    -->
   </TD>
   <TD class="ms-vb" align="right" width="20%">
    <xsl:value-of select="'&amp;nbsp;'" disable-output-escaping="yes" />
    <xsl:value-of disable-output-escaping="no" select="ddwrt:FormatDateTime(string(@Created) ,1033 ,'d-MMM-yyyy hh:MM tt')" />
   </TD> 
  </TR>

  <TR>
   <TD class="ms-vb" colSpan="2">
    <DIV>
     <xsl:value-of select="substring($TextBody,0,200)" disable-output-escaping="yes" />
     <xsl:if test="string-length(@Body) &gt; 200">...</xsl:if>
    </DIV>
   </TD>
  </TR>
  <TR>
   <TD>
    <FONT size="1">
    <xsl:value-of select="'&amp;nbsp;'" disable-output-escaping="yes" />
    </FONT>
   </TD>
  </TR>
 </TBODY>
</TABLE>
  
 </xsl:template>
 <!-- JBoman: End announcement transform -->