zevenseas


 

Enumerating through SSP's

As you may have noticed in my previous post I called the SSP in my code using hard-coded text..

string sspname = "SharedServices1";
ServerContext current = ServerContext.GetContext(sspname);

Apart from the fact that I'm a bit ashamed by doing this there was a reason why it was still hard-coded and that was because I couldn't find an easy way to determine if a SPWebApplication was a SSP. All the examples from Microsoft on TechNet show the following snippets when try to open a SSP in code :

SSPGUID2

SSPGUIDReplace

Not very helpful eh ? :) Now with some Googling I found the following blog : Chris Hernandez's Blog with the following post Creating Shared Service Provider (SSP) via command-line options and in the comments section there is the answer to retrieve the SSP Web Applications while looping through the Web Applications. While you are looping there is a certain property in the propertybag that identifies what kind of webapplication it is and apparently for a SSP that key is :

spWebApp.Properties.ContainsKey("Microsoft.Office.Server.SharedResourceProvider")

Now we get all the WebApplications that use the Microsoft.Office.Server.SharedResourceProvider! Next step is to filter the MySites SSP from the Admin SSP ;) And that is pretty easy since we know that the mysites are using their own sitetemplates (MSITEHOST) and the admin page is created using the "OSRV" sitetemplate. By having narrowed down all possibilities we can get the ServerContext of our admin SSP :)

if (spWebApp.Sites[0].RootWeb.WebTemplate == "OSRV")
{
        ServerContext SSP = ServerContext.GetContext(spWebApp.Sites[0]);
} 

So the code in total looks like this :

SPFarm farm = SPFarm.Local;
SPWebService service = farm.Services.GetValue<SPWebService>("");

foreach (SPWebApplication spWebApp in service.WebApplications)
{
    if (spWebApp.Properties.ContainsKey("Microsoft.Office.Server.SharedResourceProvider"))
    {
        if (spWebApp.Sites[0].RootWeb.WebTemplate == "OSRV")
        {
            ServerContext SSP = ServerContext.GetContext(spWebApp.Sites[0]);
        }
    }
}

Hope this helps someone ;)

Programmatically retrieving if Usage Analysis is set

During the development of the LCM, I needed to know when a site is marked as 'unused' using the following three choices :

  • Last Content Modified Date
  • Last Security Modified Date
  • Last Usage Date

Now the first two choices are easily retrieved using the SPSite.LastSecurityModifiedDate and SPSite.LastContentModifiedDate methods. The third option is more of a challenge, but giving the fact that in V1 of the LifeCycleManagement source this was already developed (and nothing has changed since 2003->2007 in that area) I could re-use that code ;) Now the challenge here is that we have to determine first if Usage Analysis is properly set in the Central Admin, else we only get errors while retrieving the UsageDetails (SPWeb.GetUsageData)..

 

So I looked in the OM to find the first setting.. the so called "WSS Usage logging". To retrieve this setting you can use the following bit of code:

SPFarm farm = SPFarm.Local;
SPWebService service = farm.Services.GetValue<SPWebService>("");
WSSUsageAnalysis = service.UsageSettings.UsageProcessingEnabled;

Up to the Office SharePoint Usage Processing setting! Now this is a bit harder since there is no OM available to get this option. Thankfully Gary Lapointe (the guy who is responsible for the excellent STSADM Custom Extensions blog) paved the way for me here! This post about Set Usage Analysis directed me in the right direction.. in order to get the setting we have the use reflection on the Microsoft.SharePoint.Portal.Analytics.Configuration class (pretty funny that Microsoft still uses the good 'ol .Portal namespace).

Now when we use reflection on this class we see the following methods we can use :

  • Boolean IsAnalyticsEnabledOnSrp(Microsoft.Office.Server.Administration.SharedResourceProvider)
  • Boolean IsAnalyticsEnabledOnWebApp(Microsoft.SharePoint.Administration.SPWebApplication)
  • Void SetAnalyticsEnabledOnSrp(Microsoft.Office.Server.Administration.SharedResourceProvider, Boolean)
  • System.DateTime GetLastLocalImportDayForWebApp(Microsoft.SharePoint.Administration.SPWebApplication)
  • Void SetLastLocalImportDayForWebApp(Microsoft.SharePoint.Administration.SPWebApplication, System.DateTime)
  • Boolean HaveLocalWebAppLogsEverBeenImported(Microsoft.SharePoint.Administration.SPWebApplication)

Well we want to know if Usage Analytics is set on the SSP so we go for the IsAnalyticsEnabledOnSrp method. All we have to do now is to create a instance of Microsoft.Office.Server.Administration.SharedResourceProvider (the SSP context). To do this we use the Microsoft.Office.Server namespace where we can use the ServerContext.GetContext("SSP Name") to have an instance. The code to do all this looks like this :

string sspname = "SharedServices1";
ServerContext current = ServerContext.GetContext(sspname);
object sharedResourceProvider = current.GetType().GetProperty("SharedResourceProvider", 
AllBindings).GetValue(current, null); Type configurationType = Type.GetType("Microsoft.SharePoint.Portal.Analytics.Configuration,
Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
); MethodInfo methodinfo = configurationType.GetMethod("IsAnalyticsEnabledOnSrp"); object IsAnalyticsEnabledOnSrp = methodinfo.Invoke(null, new object[] { sharedResourceProvider }); OfficeUsageAnalysis = (bool)IsAnalyticsEnabledOnSrp;

I'm still a bit of newbie when it comes to reflection so don't ask any specific details on what I'm doing here.. but it works! :)

For those of you who don't read Dutch newspapers..

And I assume that will be a lot (Google Analytics show that the majority of you are based in the US ;), I thought it was quite funny to show that even SharePoint makes it to a national newspaper here! It's an article about the fact that more and more (dutch) companies are investing in social networking and instant messaging and are embracing the "New way of Work" and that the tool for doing this is SharePoint. It also states that 65% of the "top 200 companies" in the Netherlands are using SharePoint today!

Here is the link to the dutch article : 'Steeds meer bedrijven omarmen sociale software'

So Joel.. maybe an opportunity? ;)

Ever wondered how the CQWP performs in comparison to custom aggregation webparts?

I was wondering about this matter since I developed the What's New webpart (like Jan did as well with the The What's New Web Part for SharePoint 2007) a couple of months ago but never took the time to do some metrics to see what the best way to go was. Fortunately there is Waldek Mastykarz! He posted a very nice post Content Query Web Part vs. Custom Aggregation Web Part with graphs and a very detailed plan what all the differences are and what the best solution is to aggregate information.

Addition to "Want to blog about SharePoint using SharePoint?"

In addition of the announcement Want to blog about SharePoint using SharePoint? I want to say, this is not an attempt to be a competitor of SharePointBlogs.com! :)

At zevenseas we think the SharePoint community is one of the best communities around and the last thing we want is to have competition between the community sites and maybe even the bloggers themselves. 

What we offer though is a free blogging environment that runs on SharePoint with the CKS:EBE (the Enhanced Blog Edition). So the more people are using it the better idea we all get on what is missing in the product and thus how we can improve it! A perfect example of such an improvement is what Daniel posted a couple of days ago Adding Search to the CKS-Enhanced Blog Edition (CKS-EBE)

Want to blog about SharePoint using SharePoint?

To celebrate the release of the Community Kit for SharePoint: Enhanced Blog Edition 2.0 (CKS:EBE) zevenseas, in partnership with PixelMill, would like to offer the first 20 people to email us at openzeas@zevenseas.com a free, hosted blog, powered by the CKS:EBE.

The CKS:EBE brings the most critical features required to run a successful internet facing blog, including:

  • Modular Theme Framework ("MTF") that allows for the development of rich themes
  • Support for Akismet comment spam detection
  • Multiple categories/tags can be mapped to each blog entry/post
  • Friendly URL ("FURL") for the blog's posts
  • Friendly URL for the blog's RSS feed (and support for FeedBurner)
  • And more....

This offer came together at the recent SharePoint conference, and was the result of a discussion about the CKS kit and what it means to community building. At zevenseas we have been lucky enough to work with a number of customers on ways to engage with the people who care most about their products and services. We’ve used the CKS to build out a platform that enables them to do this effectively, on SharePoint, with blogging at its core. We hope this offer is the beginning of another small community.

PixelMill, our SharePoint Designer Partners, have worked with us on these projects and wanted to be able to demonstrate just how attractive these blogs can be. To do that they have offered, for free, a selection of their premium design themes built for CKS:EBE. These are just the first of a number of new themes they will be offering to help your blog stand out, so be sure to take a look at their gallery.

Of course, none of this would be possible without the team who put the toolkit together. A big thanks to the CKS Team below, we’re really excited about its future:

Vince Rothwell (MTF)
Nadeem Mitha (Linkbacks)
Ari Bakker (Themes)
Heather Waterman (Themes)
Yvonne Harryman (QA)
Matthew McDermott (Documentation/QA)
Shane Perran (Themes)
Gaetan Bouveret (QA)
Keith Bunge (Various)
Steven Van de Craen (Captcha)
Brent Bolleman (EBE-PM)
Lawrence Liu (CKS-PM)

Write error on file "wssxxx.tmp"

I received this error while restoring a sitecollection using STSADM -o restore command. The sitecollection was 3gb in size so I thought maybe that was the reason of the error but during a test of another restore of a very large sitecollection this was not the reason.

Next thing that sprung into mind that maybe the backup file was corrupted. Luckily the sitecollection still existed in our environment so I could create another backup of the site to check whether the file was damaged. Well as you might have guessed there was nothing wrong with the file itself because restoring using the new file also ended up in the 'write error on file' error message.

Next thing was to check if the disks of the database server were full or that the transaction log was full but that also wasn't the case.

Then I decided to backup the site using the STSADM -o export command, because the site was 3gb size it gave the error that it couldn't compress the cabinet files so I had to run the tool again with the paramater -nofilecompression. Now to restore from an export you need to create a new site to restore first and then you can run the STSADM -o import command. Make sure you use the parameter -nofilecompression because otherwise you get errors that it cannot find the cabinet file (took me a while to figure this one out, I thought the command was smart enough to detect that the export file was uncompressed ;)). The import did the trick.. except for three files which I had to manually copy/paste using the Explorer View. Guess that was the problem to restore the sitecollection using the STSADM -o restore command.. Weird stuff!

Here is a screenshot of the error :

Hope this helps someone ;)

LCM : Creating custom application page and using the propertybag.. more detailed

As I was reading my own post a couple of days later I realized that it was pretty cryptic and I didn't explain very much on what I did. So here is second post on the same subject but with slightly different content. I'm going to show you the statistic page which I've created and I will go in more detail on how to use the propertybag.

 

Nice page again eh? It might remind you of the search & crawl page you find in the SSP. And you are quite right! I used that page to create this page and I wanted to know how MS created such a page. I'm not going to tell you what standard controls are in there (like the ContentPlaceHolders) but only what is specified in the "PlaceHolderMain" control.
It begins with :

<table border="0" cellspacing="0" cellpadding="0" class="ms-propertysheet" width="100%">
    <tr><td>

then we see the first control section that inherits from Microsoft.SharePoint.Portal.WebControls and that looks like this :

<SPSWC:PageLevelError runat="server" id="pageLevelError"/>
        <SPSWC:ControlPanelSections runat="server">
            <SPSWC:ControlPanelSection runat="server" title="LCM Statistics" imageUrlFileContext="SharedImage" imageUrlFileName="manageuser.gif">

In this portion, the title of the section is given and the image that comes with it.. so next are the controls where it's all about!

<SPSWC:ControlPanelStatusTable runat="server">
                    <SPSWC:ControlPanelStatusRow runat="server" 
                        id="lblWebApps" Label="Web Applications" 
                        />
                    <SPSWC:ControlPanelStatusRow runat="server" 
                        id="lblSites" Label="Sites Collections (incl MySites)" 
                        />
                    <SPSWC:ControlPanelStatusRow runat="server" 
                        id="lblMySites" Label="MySites" 
                        />
                    <SPSWC:ControlPanelStatusRow runat="server" 
                        id="lblUsers" Label="Unique active users" 
                        />
                        <SPSWC:ControlPanelStatusRow runat="server" 
                        id="lblUnusedSites" Label="Unused Sites" 
                        />
             <SPSWC:ControlPanelStatusRow runat="server" 
                        id="lblEnterpriseSites" Label="Enterprise Enabled Sites" 
                        />                    
             <SPSWC:ControlPanelStatusRow runat="server" 
                        id="lblDeletedSites" Label="Deleted Sites" 
                        />
                </SPSWC:ControlPanelStatusTable>

All the labels are wrapped up in the StatusTable, so this table makes sure that the layout being taken care off. The last thing that is in there is the link to the 'Detailed Analytical LCM Site' and that looks like this :

<SPSWC:ControlPanelHyperLink runat="server" 
                    id="contentSourceLink"
                    text="Detailed Analytical LCM Site"
                    navigateUrl="/LCM/default.aspx"/>                
            </SPSWC:ControlPanelSection>
        </SPSWC:ControlPanelSections>
    </td></tr>
    </table>

So there you have it.. all of the controls take care of the layout so you don't have to write your own layout which is a big relieve if you ask me! If I did knew about this earlier it would have saved me a lot of time :) Now to put the numbers in there (instead of only showing the text of the labels) you have to write some code in the codebehind of the .aspx file. In the original .ASPX file those values were being set using .Value1.. So I looked up the control on MSDN and there I found the following bit on how to set those values..

So my codebehind looks like this :

<script runat="server">
SPWeb web = SPContext.Current.Web;
protected override void OnLoad(EventArgs e) 
{    
    if (GetWebProperty("Configured", web.Properties) == "true")
    {
        lblUnusedSites.Value1 = GetWebProperty("NumberOfUnusedSites", web.Properties);
        lblEnterpriseSites.Value1 = GetWebProperty("NumberOfEnterpriseSites", web.Properties);
        lblDeletedSites.Value1 = GetWebProperty("bFolderSitecollection", web.Properties);
        lblWebApps.Value1 = GetWebProperty("NumberOfWebApps", web.Properties);
        lblSites.Value1 = GetWebProperty("NumberOfSiteCollections", web.Properties);
        lblMySites.Value1 = GetWebProperty("NumberOfMySites", web.Properties);
        lblUsers.Value1 = GetWebProperty("NumberOfUniqueUsers", web.Properties);
    }    
    base.OnLoad(e);
}

So without much code and effort you can create SharePoint looking pages by using the default controls. Now the next step is to make use of the propertybag like I did in my codebehind to retrieve those values. The first thing that needs to be done is actually setting those properties.. I do this in a timer job that runs every day. I'll show you a small snippet of that specific timerjob (I will describe the overall working of the timerjob in detail in a future post) that sets those properties :

SPFarm farm = SPFarm.Local;
SPWebService service = farm.Services.GetValue<SPWebService>("");
NumberOfWebApps = service.WebApplications.Count;
foreach (SPWebApplication wa in service.WebApplications)
{
    if (wa.IsAdministrationWebApplication)
    {
         foreach (SPSite site in wa.Sites)
         {
               if (site.RootWeb.Properties.ContainsKey("LCM_Configured"))
               {
                      SetWebProperty(UniqueUsers.ToString(), "NumberOfUniqueUsers", site.RootWeb.Properties);
                      SetWebProperty(NumberOfWebApps.ToString(), "NumberOfWebApps", site.RootWeb.Properties);
                      SetWebProperty(NumberOfSiteCollections.ToString(), "NumberOfSiteCollections", site.RootWeb.Properties);
                      SetWebProperty(i_esites.ToString(), "NumberOfEnterpriseSites", site.RootWeb.Properties);
                      SetWebProperty(i_usites.ToString(), "NumberOfUnusedSites", site.RootWeb.Properties);
               }
        }
    }
}

By making use of the .IsAdminstrativeWebApplication boolean we elimate all the content webapplications (even the SSP WebApplication which really suprised me!). Because the Central Admin is just a SPSite with a SPWeb, we can store our properties in the PropertyBag of the Central Admin page.. really cool eh? ;) If you are wondering where the "SetWebProperty" and "GetWebProperty" functions come from because you can't find them in the OM.. well .. you're right.. ;) Here is the code of those functions (makes life a little bit easier) :

private void SetWebProperty(string propertyValue, string propertyName, SPPropertyBag siteWebProperties)
{
    string propertyname = "LCM_" + propertyName;

    if (siteWebProperties[propertyname] == null)
    {
        siteWebProperties.Add(propertyname, propertyValue);
    }
    else
    {
        siteWebProperties[propertyname] = propertyValue;
    }
    siteWebProperties.Update();
}

private string GetWebProperty(string propertyName, SPPropertyBag siteWebProperties)
{
    string propertyname = "LCM_" + propertyName;
    string returnvalue;

    if (siteWebProperties[propertyname] == null)
    {
        returnvalue = "";
    }
    else
    {
        returnvalue = siteWebProperties[propertyname];
    }

    return returnvalue;
}

Well that wraps up this post.. I hope this makes a bit more sense than my previous one did :)

Personal blog

If you want to know more about me.. (which I can hardly believe)  than I suggest you should take a look at my movie blog called sixteenosix.com. I blog there with my mate Daniel about all the movies we've seen :)

Also my xbox started to blog about me as well.. check it out on http://www.360voice.com/tag/gl0r1x ! And it's true, I don't play as much as I would like too but if I play.. PES 2008 is THE GAME !

LCM : Creating custom application page and using the propertybag

In this post I will describe how you can create an application page using SharePoint.Portal webcontrols instead of writing all the HTML yourself.. ;) And in addition I'm gonna describe how to make use of the property bag to store the configuration settings in.

So this is our admin page that is hosted in the Central Administration of the farm. From this admin page we can specify all the LifeCycleManagement (LCM) features. Pretty fancy eh? ;)

Here is how the controls look like under the hood (without any code yet)

<table width="100%" border="0" cellspacing="0" cellpadding="0" class="ms-propertysheet">
  <wssuc:InputFormSection Title="Backup Settings" id="ifmSQL"
    Description="Specify the settings for the site and web deletion capture" runat="server">
    <template_inputformcontrols>            
     <wssuc:InputFormControl LabelText="Specify backup location (e.g. \\fileshare\SharePointBackups\" runat="server">
      <Template_Control>
        <wssawc:InputFormTextBox CssClass="ms-input"
          ID="txtBackuplocation" Runat="server" Columns="60" />                
      </Template_Control>
    </wssuc:InputFormControl>
    <wssuc:InputFormControl LabelText="Specify filename policy" runat="server"
      Description="Specify filename policy">
      <Template_Control>
        <SPSWC:InputFormCheckBox CssClass="ms-input" ID="cbxDateTime"
          runat="server" Text="Include date time in filename?" />
        <SPSWC:InputFormCheckBox CssClass="ms-input" ID="cbxFolderSitecollection"
          runat="server" Text="Create folder per sitecollection?" />
        <SPSWC:InputFormCheckBox CssClass="ms-input" ID="cbxFolderWeb"
          runat="server" Text="Create (sub)folder per web?" />
      </Template_Control>
    </wssuc:InputFormControl> 
    </template_inputformcontrols>
  </wssuc:InputFormSection>
  <wssuc:InputFormSection Title="Install eventhandler" id="fmEventHandler"
    Description="Specify which on which application you want to install the site deletion capture event handler" runat="server">

    <template_inputformcontrols>            
      <wssuc:InputFormControl LabelText="Web Application" runat="server">
        <Template_Control>
    <SPSWC:InputFormDropDownList CssClass="ms-input" ID="drpWebApps"
          runat="server"/>
        </Template_Control>
      </wssuc:InputFormControl> 
      <wssuc:InputFormControl LabelText="Event Handler" runat="server">
        <Template_Control>
    <SPSWC:InputFormLinkButton Text="Install" OnClick="btn_Install" ID="btnInstall" runat="server" />
    <SPSWC:InputFormLinkButton Text="Check" OnClick="btn_Check" ID="btnCheck" runat="server" />               
        </Template_Control>
      </wssuc:InputFormControl> 
      <wssuc:InputFormControl LabelText="Timer Job" runat="server">
        <Template_Control>
    <SPSWC:InputFormLinkButton Text="Install" OnClick="btn_InstallTimerJob" ID="btnInstallTimerJob" runat="server" />            
    <SPSWC:InputFormLinkButton Text="UnInstall" OnClick="btn_UnInstallTimerJob" ID="btnUnInstallTimerJob" runat="server" />                
        </Template_Control>
      </wssuc:InputFormControl> 
    </template_inputformcontrols>            
  </wssuc:InputFormSection>
<wssuc:InputFormSection Title="Creates LCM Logging & Analytical Web" id="fmLCMWeb"
    Description="Creates a admin web with lists to display logging and statistical information." runat="server">
    <template_inputformcontrols>            
      <wssuc:InputFormControl LabelText="Creates Web & Lists" runat="server">
        <Template_Control>
    <SPSWC:InputFormLinkButton Text="Create Web" OnClick="btn_CreateWeb" ID="btnCreateWeb" runat="server" />
        </Template_Control>
      </wssuc:InputFormControl> 
    </template_inputformcontrols>
  </wssuc:InputFormSection>
<wssuc:InputFormSection Title="Statistics administration" id="fmLCMStatistisc"
    Description="Specify what all the details are to run the statistics on" runat="server">
    <template_inputformcontrols>            
      <wssuc:InputFormControl LabelText="Specify which webapplication hosts the MySites" runat="server">
        <Template_Control>
    <SPSWC:InputFormDropDownList CssClass="ms-input" ID="drpWebApps2" runat="server"/>
        </Template_Control>
      </wssuc:InputFormControl> 
    </template_inputformcontrols>
  </wssuc:InputFormSection>
  <SPSWC:InputFormButtonSection runat="server">
    <SPSWC:InputFormButtonAtBottom runat="server" ID="btnOK" OnClick="OnClickOK"
      TextLocId="Page_OkButton_Text" />
    <SPSWC:InputFormButtonAtBottom runat="server" ID="btnCancel" OnClick="OnClickCancel"     
      TextLocId="Page_CancelButton_Text" CausesValidation="false" />
  </SPSWC:InputFormButtonSection>
</table>

Nice eh? You don't have to worry about the layout, SharePoint takes care of that! Especially useful if you create this pages with sites that are themed ;) So the next question is.. how do you store all the settings that you can specify? Well you just add some script to the page with some .NET code in it. For example this is the code that is being used when you click on 'OK' (which is located at the bottom of the page (which you cannot see in the screenshot)) :

protected void OnClickOK(Object Sender, EventArgs e) 
{
    try
    {
        SetWebProperty(cbxDateTime.Checked.ToString(),"bDateTime",web.Properties);   
        SetWebProperty(cbxFolderSitecollection.Checked.ToString(),"bFolderSitecollection",web.Properties);   
        SetWebProperty(cbxFolderWeb.Checked.ToString(),"bFolderWeb",web.Properties);   
        SetWebProperty(txtBackuplocation.Text,"backuplocation",web.Properties);
        SetWebProperty("true","Configured",web.Properties);
        SetWebProperty(drpWebApps2.SelectedValue.ToString(),"MySitesWebApp",web.Properties);
    }
    catch
    {
        SetWebProperty("false","Configured",web.Properties);    
    }
       
    Response.Redirect("/_admin/applications.aspx");
}

private static string GetWebProperty(string propertyName, SPPropertyBag siteWebProperties)
{
    string propertyname = "LCM_" + propertyName;
    string returnvalue;

    if (siteWebProperties[propertyname] == null)
    {
        returnvalue = "";
    }
    else
    {
        returnvalue = siteWebProperties[propertyname];
    }

    return returnvalue;
}

private static void SetWebProperty(string propertyValue, string propertyName, SPPropertyBag siteWebProperties)
{
    string propertyname = "LCM_" + propertyName;

    if (siteWebProperties[propertyname] == null)
    {
        siteWebProperties.Add(propertyname, propertyValue);
    }
    else
    {
        siteWebProperties[propertyname] = propertyValue;
    }
    siteWebProperties.Update();
}

Very powerful stuff this PropertyBag! Instead of storing data in a list or writing a webpart to store the properties in or write them to SQL database table this is much easier and less resource heavy. Kinda like using cookies ;)

The beautiful thing is that all the .aspx pages that are located in the _layouts folder have permission to execute code. So you won't have to include an exception in the web.config file.If you are interested in the whole page (without any comments yet (don't worry that will be in there in the final version that will be released to CodePlex! :)) then here you go :

<%@ Page Language="C#" MasterPageFile="~/_layouts/application.master" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="wssuc" TagName="InputFormSection"  Src="~/_controltemplates/InputFormSection.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="InputFormControl"  Src="~/_controltemplates/InputFormControl.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="ButtonSection"  Src="~/_controltemplates/ButtonSection.ascx" %>
<%@ Register TagPrefix="wssawc" Namespace="Microsoft.SharePoint.WebControls"  Assembly="Microsoft.SharePoint, Version=12.0.0.0,  Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="SPSWC" Namespace="Microsoft.SharePoint.Portal.WebControls"  Assembly="Microsoft.SharePoint.Portal, Version=12.0.0.0,  Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls"  Assembly="Microsoft.SharePoint, Version=12.0.0.0,  Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="Utilities" Namespace="Microsoft.SharePoint.Utilities"  Assembly="Microsoft.SharePoint, Version=12.0.0.0,  Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="LifeCycleManagement" Namespace="LifeCycleManagement"  Assembly="LifeCycleManagement, Version=1.0.0.0,  Culture=neutral, PublicKeyToken=4306074270f0265a" %>

<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Import Namespace="Microsoft.SharePoint.Administration" %>
<%@ Import Namespace="System.Xml" %>
<%@ Import Namespace="LifeCycleManagement" %>

 
<script runat="server">

SPWeb web = SPContext.Current.Web;

protected override void OnLoad(EventArgs e) 
{
    //SPWeb web = SPContext.Current.Web;


        
    if (!this.IsPostBack)
    {
        SPFarm farm = SPFarm.Local;
                SPWebService service = farm.Services.GetValue<SPWebService>("");
                foreach (SPWebApplication webApp in service.WebApplications)
                {
            ListItem item = new ListItem();
                    item.Value = webApp.GetResponseUri(SPUrlZone.Default).ToString();
                    item.Text = webApp.Name.ToString();
            drpWebApps.Items.Add(item);
            drpWebApps2.Items.Add(item);
                }

        if (GetWebProperty("Configured", web.Properties) == "true")
        {
            txtBackuplocation.Text = GetWebProperty("backuplocation", web.Properties);
            cbxDateTime.Checked = Convert.ToBoolean(GetWebProperty("bDateTime", web.Properties));
            cbxFolderSitecollection.Checked = Convert.ToBoolean(GetWebProperty("bFolderSitecollection", web.Properties));
            cbxFolderWeb.Checked = Convert.ToBoolean(GetWebProperty("bFolderWeb", web.Properties));

        }
        if (GetWebProperty("LCMSiteCreated", web.Properties) == "true")
        {
            //btnCreateWeb.Enabled = false;
            //btnCreateWeb.Text = "Site already created";
        }
        output.Text += "Number of sites: " + GetWebProperty("MySitesWebApp", web.Properties);
        
    }


    base.OnLoad(e);
}
 
protected void OnClickOK(Object Sender, EventArgs e) 
{
    try
    {
        SetWebProperty(cbxDateTime.Checked.ToString(),"bDateTime",web.Properties);   
        SetWebProperty(cbxFolderSitecollection.Checked.ToString(),"bFolderSitecollection",web.Properties);   
        SetWebProperty(cbxFolderWeb.Checked.ToString(),"bFolderWeb",web.Properties);   
        SetWebProperty(txtBackuplocation.Text,"backuplocation",web.Properties);
        SetWebProperty("true","Configured",web.Properties);
        SetWebProperty(drpWebApps2.SelectedValue.ToString(),"MySitesWebApp",web.Properties);
    }
    catch
    {
        SetWebProperty("false","Configured",web.Properties);    
    }
       
    Response.Redirect("/_admin/applications.aspx");
}

private static string GetWebProperty(string propertyName, SPPropertyBag siteWebProperties)
{
    string propertyname = "LCM_" + propertyName;
    string returnvalue;

    if (siteWebProperties[propertyname] == null)
    {
        returnvalue = "";
    }
    else
    {
        returnvalue = siteWebProperties[propertyname];
    }

    return returnvalue;
}

private static void SetWebProperty(string propertyValue, string propertyName, SPPropertyBag siteWebProperties)
{
    string propertyname = "LCM_" + propertyName;

    if (siteWebProperties[propertyname] == null)
    {
        siteWebProperties.Add(propertyname, propertyValue);
    }
    else
    {
        siteWebProperties[propertyname] = propertyValue;
    }
    siteWebProperties.Update();
}
    
protected void OnClickCancel(Object Sender, EventArgs e) 
{
    Response.Redirect("/_admin/applications.aspx");
}

protected void btn_Install(Object Sender, EventArgs e) 
{
    FeatureEventHandler(true);    
}

protected void btn_Check(Object Sender, EventArgs e) 
{
    FeatureEventHandler(false);    

}

protected void btn_InstallTimerJob(Object Sender, EventArgs e)
{
    InstallTimerJob();

}

protected void btn_UnInstallTimerJob(Object Sender, EventArgs e)
{
    UnInstallTimerJob();
}

protected void btn_CreateWeb(Object Sender, EventArgs e)
{
    CreateWeb();
    CreateList();
}


protected void FeatureEventHandler(bool Install)
{

    Guid guid = new Guid("080ed5e5-3791-4433-a668-03b3902178a6");
    
    SPFarm farm = SPFarm.Local;
    SPWebService service = farm.Services.GetValue<SPWebService>("");
    SPWebApplication wa = service.WebApplications[drpWebApps.SelectedItem.ToString()];
    foreach (SPSite site in wa.Sites)
    {
        foreach(SPWeb _web in site.AllWebs)
        {
            
            if (Install)
            {
                try
                {
                    _web.AllowUnsafeUpdates = true;
                            _web.Features.Add(guid);
                    output.Text += "<BR>Installing at : " + _web.Title.ToString()  + "  " + _web.Url.ToString();
                }
                catch(Exception Installerror)
                {
                    output.Text += "<BR>Could not install at : " + _web.Title.ToString()  + "  " + _web.Url.ToString() + "due to " + Installerror.Message.ToString();
                }
            }
            else
            {
                try
                {
                    SPFeature feature = _web.Features[guid];
                    output.Text += "<BR>Installed at : " + _web.Title.ToString()  + "  " + _web.Url.ToString();
                }
                catch(Exception Checkerror)
                {
                    output.Text += "<BR>Not Installed at : " + _web.Title.ToString() + "  " + _web.Url.ToString() + "due to " + Checkerror.Message.ToString();;
                }
                
                
            }
        }
    }    

}

private void InstallTimerJob()
{
    SPFarm farm = SPFarm.Local;
    SPWebService service = farm.Services.GetValue<SPWebService>("");
    SPWebApplication wa = service.WebApplications[drpWebApps.SelectedItem.ToString()];
    GatherStatistics taskLoggerJob = new GatherStatistics("GatherStatistics", wa);

    SPMinuteSchedule schedule = new SPMinuteSchedule();
    schedule.BeginSecond = 0;
    schedule.EndSecond = 59;
    schedule.Interval = 2;
    taskLoggerJob.Schedule = schedule;

    taskLoggerJob.Update();

}

private void UnInstallTimerJob()
{
    SPFarm farm = SPFarm.Local;
    SPWebService service = farm.Services.GetValue<SPWebService>("");
    SPWebApplication wa = service.WebApplications[drpWebApps.SelectedItem.ToString()];
    GatherStatistics taskLoggerJob = new GatherStatistics("GatherStatistics", wa);

    foreach (SPJobDefinition job in wa.JobDefinitions) 
    {
        if (job.Name == "GatherStatistics")
        {     
            job.Delete();
        }
        }
}

private void CreateWeb()
{
    try
    {
        SPWeb LCMweb = web.Site.AllWebs.Add("LCM", "Life Cycle Management Logging and Analytical Site", "", Convert.ToUInt32(1033), "STS#0", false, false);
        SetWebProperty("true","LCMSiteCreated",web.Properties);
        output.Text += "<BR>" + LCMweb.Url.ToString();
    }
    catch(Exception sitecreationerror)
    {
        SetWebProperty("false","LCMSiteCreated",web.Properties);    
        output.Text += "<BR>" + sitecreationerror.Message.ToString();
    }

    

}

private void CreateList()
{

    SPWeb LCMWeb = web.Site.OpenWeb("LCM");
    LCMWeb.Lists.Add("EnterpriseFeatures", "Overview of all the sites and webs that have the enterprise features enabled", SPListTemplateType.GenericList);
    SPList EnterpriseFeaturesList = LCMWeb.Lists["EnterpriseFeatures"];
    EnterpriseFeaturesList.EnableAttachments = false;
    EnterpriseFeaturesList.EnableVersioning = false;
    EnterpriseFeaturesList.Fields.Add("Features", SPFieldType.Text, false);
    EnterpriseFeaturesList.Fields.Add("SiteOwner", SPFieldType.Text, false);
    EnterpriseFeaturesList.Fields.Add("Url", SPFieldType.Text, false);
    EnterpriseFeaturesList.Update();

    LCMWeb.Lists.Add("DeletedSites", "Overview of all the sites and webs that have been deleted", SPListTemplateType.GenericList);
    SPList DeletedSitesList = LCMWeb.Lists["DeletedSites"];
    DeletedSitesList.EnableAttachments = false;
    DeletedSitesList.EnableVersioning = false;
    DeletedSitesList.Fields.Add("SiteCollection", SPFieldType.Boolean, false);
    DeletedSitesList.Fields.Add("Web", SPFieldType.Boolean, false);
    DeletedSitesList.Fields.Add("Url", SPFieldType.Text, false);
    DeletedSitesList.Fields.Add("Date", SPFieldType.DateTime, false);
    DeletedSitesList.Fields.Add("Size", SPFieldType.Text, false);
    DeletedSitesList.Update();

    LCMWeb.Lists.Add("UnusedSites", "Overview of all the sites that are not being used for a period of time", SPListTemplateType.GenericList);
    SPList UnusedSites = LCMWeb.Lists["UnusedSites"];
    UnusedSites.EnableAttachments = false;
    UnusedSites.EnableVersioning = false;
    UnusedSites.Fields.Add("Url", SPFieldType.Text, false);
    UnusedSites.Fields.Add("LastContentModifiedDate", SPFieldType.DateTime, false);
    UnusedSites.Fields.Add("Size", SPFieldType.Text, false);
    UnusedSites.Update();



}


</script>
 
<asp:Content ID="Content2" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
  <SharePoint:EncodedLiteral runat="server" Text="Life Cycle Management Setting" EncodeMethod='HtmlEncode' />
</asp:Content>
 
<asp:Content ID="Content3" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server">
  <SharePoint:EncodedLiteral runat="server" Text="Life Cycle Management Settings" EncodeMethod='HtmlEncode' />
</asp:Content>
 
<asp:Content ContentPlaceHolderID="PlaceHolderPageImage" runat="server">
</asp:Content>
 
<asp:Content ID="contentMain" ContentPlaceHolderID="PlaceHolderMain" runat="server">
  <style type="text/css">
    table.ms-propertysheet {
      height: 100%;
    }
  </style>
  <table cellspacing="0" cellpadding="0" border="0" class="ms-settingsframe">
    <tr>
      <td width="100%" colspan="4" style="padding-top: 0px;">
        <table class="ms-pageinformation" width="100%" cellpadding="0" cellspacing="0">
          <tr>
            <td valign="top" style="padding: 10px;" width="100%" height="100px">
              <table height="100%" width="100%" id="idItemHoverTable">
                <tr>
                  <th scope="col" colspan="2" style="padding-bottom: 8px;">
                    <span class="ms-linksectionheader">
                      <h3 class="ms-standardheader">
                        <SharePoint:EncodedLiteral
                          ID="EncodedLiteral1"
                          runat="server"
                          Text="Admin page for setting LCM preferences"
                          EncodeMethod='HtmlEncode' />
                      </h3>
                    </span>
                  </th>
                </tr>
                <tr>
                  <th scope="row" nowrap="nowrap">
                    <SharePoint:EncodedLiteral
                      ID="EncodedLiteral2"
                      runat="server" Text="<% $Resources:wss,settings_siteurl %>"
                      EncodeMethod='HtmlEncode' />:
                  </th>
                  <td dir="ltr">
                    <% SPHttpUtility.HtmlEncode(web.Url + "/", Response.Output); %>
                  </td>
                </tr>
              </table>
            </td>
          </tr>
        </table>
      </td>
    </tr>
    <tr>
      <td valign="top" style="padding: 4px 0px 4px 0px;" height="100%">
<table width="100%" border="0" cellspacing="0" cellpadding="0" class="ms-propertysheet">
  <wssuc:InputFormSection Title="Backup Settings" id="ifmSQL"
    Description="Specify the settings for the site and web deletion capture" runat="server">
    <template_inputformcontrols>            
     <wssuc:InputFormControl LabelText="Specify backup location (e.g. \\fileshare\SharePointBackups\" runat="server">
      <Template_Control>
        <wssawc:InputFormTextBox CssClass="ms-input"
          ID="txtBackuplocation" Runat="server" Columns="60" />                
      </Template_Control>
    </wssuc:InputFormControl>
    <wssuc:InputFormControl LabelText="Specify filename policy" runat="server"
      Description="Specify filename policy">
      <Template_Control>
        <SPSWC:InputFormCheckBox CssClass="ms-input" ID="cbxDateTime"
          runat="server" Text="Include date time in filename?" />
        <SPSWC:InputFormCheckBox CssClass="ms-input" ID="cbxFolderSitecollection"
          runat="server" Text="Create folder per sitecollection?" />
        <SPSWC:InputFormCheckBox CssClass="ms-input" ID="cbxFolderWeb"
          runat="server" Text="Create (sub)folder per web?" />
      </Template_Control>
    </wssuc:InputFormControl> 
    </template_inputformcontrols>
  </wssuc:InputFormSection>
  <wssuc:InputFormSection Title="Install eventhandler" id="fmEventHandler"
    Description="Specify which on which application you want to install the site deletion capture event handler" runat="server">

    <template_inputformcontrols>            
      <wssuc:InputFormControl LabelText="Web Application" runat="server">
        <Template_Control>
    <SPSWC:InputFormDropDownList CssClass="ms-input" ID="drpWebApps"
          runat="server"/>
        </Template_Control>
      </wssuc:InputFormControl> 
      <wssuc:InputFormControl LabelText="Event Handler" runat="server">
        <Template_Control>
    <SPSWC:InputFormLinkButton Text="Install" OnClick="btn_Install" ID="btnInstall" runat="server" />
    <SPSWC:InputFormLinkButton Text="Check" OnClick="btn_Check" ID="btnCheck" runat="server" />               
        </Template_Control>
      </wssuc:InputFormControl> 
      <wssuc:InputFormControl LabelText="Timer Job" runat="server">
        <Template_Control>
    <SPSWC:InputFormLinkButton Text="Install" OnClick="btn_InstallTimerJob" ID="btnInstallTimerJob" runat="server" />            
    <SPSWC:InputFormLinkButton Text="UnInstall" OnClick="btn_UnInstallTimerJob" ID="btnUnInstallTimerJob" runat="server" />                
        </Template_Control>
      </wssuc:InputFormControl> 
    </template_inputformcontrols>            
  </wssuc:InputFormSection>
<wssuc:InputFormSection Title="Creates LCM Logging & Analytical Web" id="fmLCMWeb"
    Description="Creates a admin web with lists to display logging and statistical information." runat="server">
    <template_inputformcontrols>            
      <wssuc:InputFormControl LabelText="Creates Web & Lists" runat="server">
        <Template_Control>
    <SPSWC:InputFormLinkButton Text="Create Web" OnClick="btn_CreateWeb" ID="btnCreateWeb" runat="server" />
        </Template_Control>
      </wssuc:InputFormControl> 
    </template_inputformcontrols>
  </wssuc:InputFormSection>
<wssuc:InputFormSection Title="Statistics administration" id="fmLCMStatistisc"
    Description="Specify what all the details are to run the statistics on" runat="server">
    <template_inputformcontrols>            
      <wssuc:InputFormControl LabelText="Specify which webapplication hosts the MySites" runat="server">
        <Template_Control>
    <SPSWC:InputFormDropDownList CssClass="ms-input" ID="drpWebApps2" runat="server"/>
        </Template_Control>
      </wssuc:InputFormControl> 
    </template_inputformcontrols>
  </wssuc:InputFormSection>
  <SPSWC:InputFormButtonSection runat="server">
    <SPSWC:InputFormButtonAtBottom runat="server" ID="btnOK" OnClick="OnClickOK"
      TextLocId="Page_OkButton_Text" />
    <SPSWC:InputFormButtonAtBottom runat="server" ID="btnCancel" OnClick="OnClickCancel"     
      TextLocId="Page_CancelButton_Text" CausesValidation="false" />
  </SPSWC:InputFormButtonSection>
</table>
      </td>
    </tr>
  </table>
<asp:Label id="output" runat="server"/>
</asp:Content>

 

And the credit really goes to Steve Graegert who wrote this excellent post Using the SPPropertyBag with Custom Admin Pages in SharePoint. So if you want to know in detail how you can implement and design this, please read his post! Thanks Steve! :)

 Next >>

 
 
 

© 2009 Community Kit For SharePoint