List All Groups and All users of site collection on a single page

Yes, you have been asked this question before haven’t you?

“Dear Admin, can you send me a complete list of all the users in the Visitors group of my site collection, because there are so many in them and I am not able to export to Excel……”

Well, I finally got sick of either copy/pasting the info from the People and Groups page or exporting all users using a powershell script, that I took the time to create my own aspx page that will display that directly.

the code for this page looks like this:

<%@ Assembly Name=”Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c”%>
<%
@ Page Language=”C#” MasterPageFile=”~/_layouts/application.master” Inherits=”Microsoft.SharePoint.WebControls.LayoutsPageBase” %>
<%
@ Import Namespace=”Microsoft.SharePoint” %>

<
script runat=”server”>
   protected override void OnLoad(EventArgs e) {
     SPSecurity.RunWithElevatedPrivileges(delegate()
     {
       
using (SPWeb thisWeb = this.Web)
        {
          
string output = “”;
           output +=
“<table style=\”width=100%\”>”;
           foreach (SPGroup group in thisWeb.Groups)
           {
              
output += “<tr><td colspan=\”3\”><strong>” + group.Name + “</strong><td></tr>”;
               int i = 0;
              
if (group.Users.Count > 0)
               {
                   
foreach (SPUser user in group.Users)
                    {
                          i++;
                          output +=
“<tr>”;
                          
output += “<td>” + user.Name + “</td>”;
                         
output += “<td>” + user.Email + “</td>”;
                         
output += “<td>” + user.LoginName + “</td>”;
                          output += “</tr>”;
                    }
              }
             
else
                  
output += “<tr><td colspan=\”3\”>Group is empty<td></tr>”;
              output +=
“<tr><td colspan=\”3\”>&nbsp;<td></tr>”;
         }
         output +=
“</table>”;
         lblUsers.Text = output;
      }
   }
);
}
</script>
<
asp:Content ID=”Main” runat=”server” contentplaceholderid=”PlaceHolderMain” >
<p>Site Groups and Users</p>
<asp:Label ID=”lblUsers” runat=”server” />
</asp:Content>
<
asp:Content ID=”PageTitle” runat=”server” contentplaceholderid=”PlaceHolderPageTitle” >
Site Groups and Users
</asp:Content>
<
asp:Content ID=”PageTitleInTitleArea” runat=”server” contentplaceholderid=”PlaceHolderPageTitleInTitleArea” >
Site Groups and Users
</asp:Content>

Now save this code into an aspx page and then copy that page to the 12-hive\TEMPLATE\Layouts folder. In my case I named the file Allusers.aspx, so now I f I am in a specific site collection, I can simply call upon the page using _layouts/allusers.aspx and have my listing of all the groups with all the users in a single page.

It is so simple, but never really had the time or desire to create such a page….

Stay tuned on my blog, as I  am almost ready with my tool for generating a complete report of a SharePoint farm in a nice html document….

How To Recover Your SharePoint 2007 Product ID by Bert Johnson

On my post about the SP2 bug, I had a comment by Bert Johnson about a post of his explaining how to recover the SharePoint 2007 Product ID from your system. This is indeed very handy if you do not happen to have it or find it anymore and do not want to bother your customer for it loosing face (again [:D])

Bert wrote a vbs script that decodes the Product ID from the registry key blob data where it resides.

Thanks Bert for sharing this information, which will probably help a lot of us out there.

Subscribe to Bert’s blog with this Feed: http://blogs.pointbridge.com/Blogs/johnson_bert/_layouts/listfeed.aspx?List={071A5AE9-9B1F-44E7-8AF7-C0BC07CF531D}

The original post can be found at http://blogs.pointbridge.com/Blogs/johnson_bert/Pages/Post.aspx?_ID=10 .

Here is the script :

' Extract MOSS 2007 Product ID
' Written by Bert Johnson (PointBridge)
' http://blogs.pointbridge.com/Blogs/johnson_bert/Pages/Post.aspx?_ID=10

Const HKEY_LOCAL_MACHINE = &H80000002
Set reg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")

wscript.echo GetKey("SOFTWARE\Microsoft\Office\12.0\Registration\{90120000-110D-0000-0000-0000000FF1CE}", "DigitalProductId")

Public Function GetKey(path, key)
    Dim chars(24), prodid
    Dim productkey(14)

    reg.GetBinaryValue HKEY_LOCAL_MACHINE, path, key, prodid
    
    For ib = 52 To 66
        productkey(ib - 52) = prodid(ib)
    Next

    'Possible characters in the Product ID:
    chars(0) = Asc("B")
    chars(1) = Asc("C")
    chars(2) = Asc("D")
    chars(3) = Asc("F")
    chars(4) = Asc("G")
    chars(5) = Asc("H")
    chars(6) = Asc("J")
    chars(7) = Asc("K")
    chars(8) = Asc("M")
    chars(9) = Asc("P")
    chars(10) = Asc("Q")
    chars(11) = Asc("R")
    chars(12) = Asc("T")
    chars(13) = Asc("V")
    chars(14) = Asc("W")
    chars(15) = Asc("X")
    chars(16) = Asc("Y")
    chars(17) = Asc("2")
    chars(18) = Asc("3")
    chars(19) = Asc("4")
    chars(20) = Asc("6")
    chars(21) = Asc("7")
    chars(22) = Asc("8")
    chars(23) = Asc("9")

    For ib = 24 To 0 Step -1
        n = 0

        For ikb = 14 To 0 Step -1
            n = n * 256 Xor productkey(ikb)
            productkey(ikb) = Int(n / 24)
            n = n Mod 24
        Next

        sCDKey = Chr(chars(n)) & sCDKey
        If ib Mod 5 = 0 And ib <> 0 Then sCDKey = "-" & sCDKey
    Next

    GetKey = sCDKey
End Function
Simply save that to a file named “ExtractMOSS2007ProductID.vbs” and run it to recover your key.  Once recovered, re-apply your Product ID through Central Admin, as outlined in KB971620.

Bug in SP2 – product expiration date is improperly activated.

I saw this note on a linkedin post this morning and I immediately checked my calendar to see if it was April 1st today. Guess what, it isn’t….This bug will make SharePoint expire as though it was a trial installation 180 days after SP2 is deployed. Please check the original post on the msdn blogs here

To work around this issue you will need to re-enter their Product ID numbers (PID) on the Convert License Type page in Central Administration.  Please see this KB article for detailed steps. 

How to Ghost back or uncustomize customized Page Layouts

In followup of my previous post, today my favourite Microsoft Premier Support Engineer was asked to provide a way to unghost customized page layouts.
He came up with a little piece of code that does the trick in a C# Console application.

It must be getting clear to some of you that for administering SharePoint a knowledge of .Net development skills is becoming more and more a requirement….

The most important function of this piece of code depends on the method SPFile.RevertContentStream() which is described as: “Returns the file to its original uncustomized state so that its logic becomes cached in memory (also known as “ghosted”) rather than stored in the database.”

So, here it is. The folowing code will uncustomize the customized page layouts.

using System;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Publishing;

namespace GhostLayoutPages
{
  class Program
  {
    static void Main(string[] args)
    {
      using (SPSite site = new SPSite(args[0].ToString()))
      {
        using(SPWeb web = site.OpenWeb())
        {
          PublishingSite pubSite = new PublishingSite(site);
          PageLayoutCollection pageColl = pubSite.PageLayouts;
          foreach (PageLayout layout in pageColl)
          {
            SPFile currFile = web.GetFile(layout.ServerRelativeUrl);
            Console.WriteLine(“__________________________________”);
            Console.WriteLine(“Layout page name: “ + layout.Name);
            Console.WriteLine(“Status before: “ + currFile.CustomizedPageStatus);
 
            currFile.RevertContentStream();
            Console.WriteLine(“Status after: “ + currFile.CustomizedPageStatus);
           }
         }
       }
     }
   }
} 

How to find all the customized master pages in a site collection

I got this question today from one of my collegues and needed to find the answer to it. Why did I get this question? Well one of our developper teqms provided a new solution to deploy that replaces the default master pages and the update did not show any difference after deployment. therefore we suspected that the master pages had somehow be customized which causes this behaviour.

My first hunch for finding the answer was SharePoint Designer and my favourite Microsoft Premier Support Engineer confirmed with the following article: Track Customized Master Pages

Basically you need to open the site collection using SharePoint Designer and run the Customized Pages report and apply a filter to show only the customized master pages

Below is the information that describes how to do this as grabbed from the Microsoft article

Run the Customized Pages report

For both Office SharePoint Server 2007 and Windows SharePoint Services 3.0, data for the reports generated by Microsoft Office SharePoint Designer 2007 is saved on the server on which the site is hosted. Server administrators can grant or deny access to these reports. If the reports generated come back empty, contact your server administrator for assistance. You must have at least Web Designer permissions on the server to open the site and run reports.

When you are working with an Office SharePoint Server 2007 or Windows SharePoint Services 3.0 site, you can easily use Office SharePoint Designer 2007 to run site reports that collect a variety of information about your site’s health, usage, and potential problems. To run a Customized Pages report:

  1. Open the Web site for which you want to run the report in Office SharePoint Designer 2007.
  2. On the Site menu, point to Reports, point to Shared Content, and then click Customized Pages.The report opens with all of the pages in the site listed, and the Customized column indicates whether content has been customized for that page. Note   A page is considered customized only if it is included in the original site definition. New pages created from a master page, new blank ASPX pages, and custom list forms that you create are not considered customized pages.

 

Filter the report to show only master pages

After you run the Customized Pages report, you may want to narrow it down to include only those pages in the site that are master pages, as shown in the following illustration.

  • To limit the results to master pages only, click the arrow next to the Type column heading, and then click master.

Filter the report to show only customized master pages

You can narrow the results even further to list only customized master pages, as shown in the following illustration.

  1. Click the arrow next to the Type column heading, and then click master.
  2. Click the arrow next to the Customized column heading, and then click Yes.

The report now lists only master pages that have been customized.

 Note   To remove any filter, click the arrow next to the column heading, and then click (All).

Using SQL Aliases with SharePoint by Thomas Vochten

Thomas Vochten, a former colleague of mine, wrote about an interesting way to create and configure your SharePoint farm to take into account any possible changes in your backend SQL infrastructure by using SQL aliases on your MOSS servers and therefore adding the possibility to change your backend SQL server transparently to your SharePoint configuration.

On his blog, he wrote:

“I recently found out about SQL Aliases and how to use them in combination with SharePoint installations. It enables you to define local alias name to connect to with a SQL Client, so you can change the actual connection later on. This may come in handy when switching over to your mirror database server, when moving servers, when virtualizing you database server etc. “

Furthermore he describes the actual steps to configure this. I am not adding those steps to this blog post, to have you go look at the original post instead [8-|]

I also checked with my favorite Premier support Engineer form Microsoft to check if this is supported and he confirms it is. He aslo confirmed seeing this more and more for use with Excel Services and failover scenarios as suggested by Thomas.

**** Update ****
Also worth mentionning is Thomas’s comment on my question:

I wrote: “Just to be clear: this needs to be configured on the MOSS servers locally, right, and not on the SQL box? And if so, then it would need to be configured on all MOSS servers part of the farm, too, right? “

Thomas replied: “Indeed, it needs to be configured on every MOSS server. You could also do this after MOSS is already installed: configure the alias exactly as your existing connection, and change it when needed.”

Thanks Thomas for sharing.

SPS2003 Add Link to Site not working

Why might this be relevant to a MOSS admin. Well, you might be busy upgarding a SharePoint Portal Server 2003 environment to MOSS using the gradual approach, like I am. Off course you would test thjis on a test farm and reproduce your production environment in a somewhat representative way. In my case a imported only a couple of production sites in my test environment, which could be considered as logical.

Now, the thing is that I tried crawling the SPS content with my new MOSS farm and the crawl uses the Site Directory on the SPS Portal to anmalyze which sub sites it needs to crawl. Clearly the Site Directory was not reflecting teh istes I had on my test environment. So I cleaned out the Site Directory and wanted to add Links to the actual sites on the SPS application.Guess what, I was unable to. Apparently this is due to SP2 for SharePoint Portal Server 2003.

Thanks to this blog post I found the solution:

1. Open this file in a text editor:
C:\Program Files\Common Files\Microsoft Shared\web server extensions\60\TEMPLATE\[LCID]\SPSSITES\LISTS\SITESLST\NewForm.aspx
(Replace [LCID] with your locale identifier, 1033 for English)

2. Find this code fragment:

<SPSWC:InputFormButtonSection runat=”server”>
<SPSWC:InputFormButtonAtBottom ID=”ButtonOk” runat=”server”
TextLocId=”Page_OkButton_Text”/>
<SPSWC:InputFormButtonAtBottom ID=”ButtonCancel” runat=”server”
TextLocId=”Page_CancelButton_Text” visible=”false” />
</SPSWC:InputFormButtonSection>

3. Replace it with this code fragment:

<SPSWC:InputFormButtonSection runat=”server”>
<!– Workaround for WIN2003SP2 issue: http://support.microsoft.com/kb/934229
–>
<input type=”button” value=”         OK         ”
onclick=”document.forms[0].submit()” />
<!– <SPSWC:InputFormButtonAtBottom ID=”ButtonOk” runat=”server”
TextLocId=”Page_OkButton_Text”/> –>
<!– End workaround –>
<SPSWC:InputFormButtonAtBottom ID=”ButtonCancel” runat=”server”
TextLocId=”Page_CancelButton_Text” visible=”false” />
</SPSWC:InputFormButtonSection>

4. Thats it;-)

Tim Dobrinski’s SharePoint Space Monitor

While searching through the Technet SharePoint forum, I stumbled upon a post/question regarding how to find out how much data your subsites are using. I remember from the SPS 2003 days that there was a aspx page that would show this ( _layouts/storman.aspx), which actually still exists in MOSS, but is accessible ony if you have a storage quota defined on the site collection (maybe it was also the case already in SPS, but I am not sure). It is accessible though the Site Settings page listed as a link called storage space allocation

Well, Tom Dobrinski developped a tool that allows you to get this information regardless of the fact if storage quotas are enabled or not. Even more he has made it available free of charge, but you are kindly suggested to make a small donation (5$) to get a everlasting key for the tool. Otherwise you will have to drop Tim a mail requesting a key every 4 months or so…

Go check his blog for the tool called the SharePoint Space Monitor if you think it might be usefull to you.

Extract the installed solutions from the MOSS farm (updated)

I was looking today for a way to get all the original wsp and cab files that have been installed into a MOSS farm. Of course not everybody keeps track of where the original files are the same way. Certainly if there is a team that is managing the same MOSS farms, your original files get lost very rapidly, or you can find the files on the filesystem, but there are so many versions of them. which one is the latest and the version installed?

So I was thinking that there should be a way to extract them from MOSS directly. Of course there is no OOTB way to do this, but I found some code that allows you to do it. The piece of code was posted on a Technet blog comment

I basically took this code and wrote a small Console Application around it so I could use it on my systems.

*** UPDATE March 23rd 2009***

Once I had created my little tool to extract the solutions, I noticed that it would also be great to know what the properties are of the solutions. Where were they deployed to, etc. Therefore I added some code to generate in addition to the solution files also a corresponding xml file containing that information

I will share my updated code:

using System;

using System.Collections.Generic;

using System.Text;

using Microsoft.SharePoint.Administration;

using System.Xml;

 

namespace SolutionExtractor

{

    class Program

    {

        static void Main(string[] args)

        {

            if (args.GetLength(0) == 0)

            {

                Console.WriteLine(“Usage: SolutionExtracter.exe <path to save solution files>”);

                return;

            }

            string path = args[0].ToString();

           

            bool checkIfDirExists = System.IO.Directory.Exists(path);

            if (checkIfDirExists == false)

            {

                Console.WriteLine(“path “+path+ ” does not exist”);

                return;

            }

 

            SPSolutionCollection solutions = SPFarm.Local.Solutions;

 

            foreach (SPSolution solution in solutions)

            {

                SPPersistedFile wspFile = solution.SolutionFile;

                Console.WriteLine(“Saving “+path +“\\” + solution.Name);

                wspFile.SaveAs(path +“\\” + solution.Name);

               

                Console.WriteLine(“Saving properties to “ + path + “\\” + solution.Name + “.xml”);

                string filename = path + “\\” + solution.Name + “.xml”;

                XmlTextWriter tw =new XmlTextWriter(filename,null);//null represents the Encoding Type//

                tw.Formatting=Formatting.Indented;  //for xml tags to be indented//

                tw.WriteStartDocument();   //Indicates the starting of document (Required)//

                tw.WriteStartElement(“Solution”);

                tw.WriteAttributeString(“Name”, solution.Name);

                tw.WriteStartElement(“Properties”);

                tw.WriteElementString(“Added”, solution.Added.ToString());

                tw.WriteElementString(“ContainsCasPolicy”, solution.ContainsCasPolicy.ToString());

                tw.WriteElementString(“ContainsGlobalAssembly”, solution.ContainsGlobalAssembly.ToString());

                tw.WriteElementString(“ContainsWebApplicationResource”, solution.ContainsWebApplicationResource.ToString());

                tw.WriteElementString(“Deployed”, solution.Deployed.ToString());

                

                tw.WriteStartElement(“DeployedServers”);

                foreach(SPServer s in solution.DeployedServers)

                    tw.WriteElementString(“Server”, s.Name);

                tw.WriteEndElement();

               

                tw.WriteElementString(“DeploymentState”, solution.DeploymentState.ToString());

                if (solution.DeploymentState.ToString().ToLower() != “globaldeployed”)

                {

                    tw.WriteStartElement(“DeployedWebApplications”);

                    foreach (SPWebApplication w in solution.DeployedWebApplications)

                        tw.WriteElementString(“WebApplication”, w.Name);

                    tw.WriteEndElement();

                }

                tw.WriteElementString(“IsWebPartPackage”, solution.IsWebPartPackage.ToString());

                tw.WriteElementString(“SolutionId”, solution.SolutionId.ToString());

              

                tw.WriteEndElement();

                tw.WriteEndDocument();                                 

                tw.Flush();

                tw.Close();

            }

 

        }

    }

}

 

 

 

So after running this code you will find all the solutions accompanied by an xml file with the properties like this:

 <?xml version=1.0?>
<
Solution Name=mySolution.wsp>
  <
Properties>
    <
Added>True</Added>
    <
ContainsCasPolicy>False</ContainsCasPolicy>
    <
ContainsGlobalAssembly>True</ContainsGlobalAssembly>
    <
ContainsWebApplicationResource>True</ContainsWebApplicationResource>
    <
Deployed>True</Deployed>
    <
DeployedServers>
        <
Server>MOSS01</Server>
        <Server>MOSS02</Server>
    </
DeployedServers>
    <
DeploymentState>GlobalAndWebApplicationDeployed</DeploymentState>
    <DeployedWebApplications>
       <
WebApplication>SharePoint – WebApp1</WebApplication>
       <
WebApplication>SharePoint – WebApp2</WebApplication>
    </
DeployedWebApplications>
    <
IsWebPartPackage>False</IsWebPartPackage>
    <
SolutionId>eb07011e-3898-4d51-8e23-008a890c6549</SolutionId>
  </
Properties>
</
Solution>

For Those of you that do not want to start developping or compiling this peace of code, you can download an updated compressed version of it attached to this post.

Change the default 10 MB limit for saving a site as template

I bumped upon this 10 MB limit today when trying to save a site as a template. Did some research on the net and found that you can change this limit through the following stsadm command:

stsadm -o setproperty -pn max-template-document-size -pv 524288000

This will set a 500 MB limit instead, which is apparently the maximum value you can specify.