Blog on the move

December 8th, 2009 by anoon

I’ve been having trouble blogging since the move to WorldPress…I’m going to start blogging on Live and see how it goes.

I guess I should have made the move previously given that I’m a Microsoft nut:  http://andynoon.spaces.live.com

InfoPath – Bulk update forms in a SharePoint library

July 30th, 2009 by anoon

After a customer of mine ran hopelessly behind processing forms in a SharePoint library they requested a utility to automate the update all the forms in bulk.

Initially, I thought this might be a bit of a pain but once I got into it it was a pretty simple little app.

It’s written as a windows application and simply loops through each form in a library and makes updates based on your the data you enter.  This quick and dirty app only allows 4 field updates per form but if I had the time it would be pretty simple to just do this in a repeating section so there were no limits.  You can also choose whether you want to copy the file to another location once the update is complete.

 

Here’s a screenshot:

image

 

And the code:

 

lstItemsProcessed.Items.Clear();
int i = 1;
SPSite objSite = new SPSite(txtSite.Text);
SPWeb objWeb = objSite.OpenWeb();
SPList objList = objWeb.Lists[txtLibraryName.Text];

foreach (SPListItem objListItem in objList.Items)
{
    try
    {
        SPFile objExistingFile = objListItem.File;
        objExistingFile.CheckOut();
        XmlDocument xmlFile = new XmlDocument();
        xmlFile.Load(objExistingFile.OpenBinaryStream());
        XmlNode xmlRootNode = xmlFile.DocumentElement;

        XPathNavigator xmlNav = xmlFile.CreateNavigator();
        XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlFile.NameTable);
        nsmgr.AddNamespace("my", "http://schemas.microsoft.com/office/infopath/2003/myXSD/2008-08-15T09:27:20");

        if (txtField.Text!="") xmlRootNode.SelectSingleNode(txtField.Text, nsmgr).InnerText = txtValue.Text;
        if (txtField2.Text != "") xmlRootNode.SelectSingleNode(txtField2.Text, nsmgr).InnerText = txtValue2.Text;
        if (txtField3.Text != "") xmlRootNode.SelectSingleNode(txtField3.Text, nsmgr).InnerText = txtValue3.Text;
        if (txtField4.Text != "") xmlRootNode.SelectSingleNode(txtField4.Text, nsmgr).InnerText = txtValue4.Text;

        string strData = xmlFile.OuterXml;
        MemoryStream msFile = new MemoryStream(Encoding.UTF8.GetBytes(strData));
        objExistingFile.SaveBinary(msFile);
        objExistingFile.CheckIn("Updated by stealth!");

        if (txtDestinationSite.Text != "")
        {
            SPWeb objDestWeb = new SPSite(txtDestinationSite.Text).OpenWeb();
            objDestWeb.GetFolder(txtDestinationLibrary.Text).Files.Add(objExistingFile.Name, msFile, true);
            objDestWeb.Dispose();
        }

        lstItemsProcessed.Items.Add(i.ToString() + ": Processed " + objListItem.Name + " at " + DateTime.Now);
    }
    catch (Exception exc)
    {
        lstItemsProcessed.Items.Add(i.ToString() + ": ERROR " + objListItem.Name + " at " + DateTime.Now + " -> " + exc.Message);
    }
    finally
    {
        i++;
    }
    objWeb.Close();
    objSite.Close();
    objWeb.Dispose();
    objSite.Dispose();

InfoPath – Bulk update forms in a SharePoint library

July 30th, 2009 by anoon

After a customer of mine ran hopelessly behind processing forms in a SharePoint library they requested a utility to automate the update all the forms in bulk.

Initially, I thought this might be a bit of a pain but once I got into it it was a pretty simple little app.

It’s written as a windows application and simply loops through each form in a library and makes updates based on your the data you enter.  This quick and dirty app only allows 4 field updates per form but if I had the time it would be pretty simple to just do this in a repeating section so there were no limits.  You can also choose whether you want to copy the file to another location once the update is complete.

 

Here’s a screenshot:

image

 

And the code:

 

lstItemsProcessed.Items.Clear();
int i = 1;
SPSite objSite = new SPSite(txtSite.Text);
SPWeb objWeb = objSite.OpenWeb();
SPList objList = objWeb.Lists[txtLibraryName.Text];

foreach (SPListItem objListItem in objList.Items)
{
    try
    {
        SPFile objExistingFile = objListItem.File;
        objExistingFile.CheckOut();
        XmlDocument xmlFile = new XmlDocument();
        xmlFile.Load(objExistingFile.OpenBinaryStream());
        XmlNode xmlRootNode = xmlFile.DocumentElement;

        XPathNavigator xmlNav = xmlFile.CreateNavigator();
        XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlFile.NameTable);
        nsmgr.AddNamespace("my", "http://schemas.microsoft.com/office/infopath/2003/myXSD/2008-08-15T09:27:20");

        if (txtField.Text!="") xmlRootNode.SelectSingleNode(txtField.Text, nsmgr).InnerText = txtValue.Text;
        if (txtField2.Text != "") xmlRootNode.SelectSingleNode(txtField2.Text, nsmgr).InnerText = txtValue2.Text;
        if (txtField3.Text != "") xmlRootNode.SelectSingleNode(txtField3.Text, nsmgr).InnerText = txtValue3.Text;
        if (txtField4.Text != "") xmlRootNode.SelectSingleNode(txtField4.Text, nsmgr).InnerText = txtValue4.Text;

        string strData = xmlFile.OuterXml;
        MemoryStream msFile = new MemoryStream(Encoding.UTF8.GetBytes(strData));
        objExistingFile.SaveBinary(msFile);
        objExistingFile.CheckIn("Updated by stealth!");

        if (txtDestinationSite.Text != "")
        {
            SPWeb objDestWeb = new SPSite(txtDestinationSite.Text).OpenWeb();
            objDestWeb.GetFolder(txtDestinationLibrary.Text).Files.Add(objExistingFile.Name, msFile, true);
            objDestWeb.Dispose();
        }

        lstItemsProcessed.Items.Add(i.ToString() + ": Processed " + objListItem.Name + " at " + DateTime.Now);
    }
    catch (Exception exc)
    {
        lstItemsProcessed.Items.Add(i.ToString() + ": ERROR " + objListItem.Name + " at " + DateTime.Now + " -> " + exc.Message);
    }
    finally
    {
        i++;
    }
    objWeb.Close();
    objSite.Close();
    objWeb.Dispose();
    objSite.Dispose();

Contact Selector / People Editor

December 11th, 2008 by anoon

I just spent far too long trying to find a blog on adding the SharePoint PeopleEditor control to InfoPath.  I've done it before but I couldn't remember how!

The controls are so similar that I didn't think the names would be different.  Anyway, here's how to add the PeopleEditor / Contact Selector to InfoPath…

  • Click on control and at the bottom select 'add or remove custom controls'
  • Choose 'contact selector'
  • Don't include the cab
  • Select 'field or group (any data type)'
  • Add the following structure to your data source

 

GroupName (group)

Person (group)

  • DisplayName (text)
  • AccountId (text)
  • AccountType (text)

 

  • That's it, as long as you're using a web form it will inherit the context of the site.

Contact Selector / People Editor

December 11th, 2008 by anoon

I just spent far too long trying to find a blog on adding the SharePoint PeopleEditor control to InfoPath.  I've done it before but I couldn't remember how!

The controls are so similar that I didn't think the names would be different.  Anyway, here's how to add the PeopleEditor / Contact Selector to InfoPath…

  • Click on control and at the bottom select 'add or remove custom controls'
  • Choose 'contact selector'
  • Don't include the cab
  • Select 'field or group (any data type)'
  • Add the following structure to your data source

 

GroupName (group)

Person (group)

  • DisplayName (text)
  • AccountId (text)
  • AccountType (text)

 

  • That's it, as long as you're using a web form it will inherit the context of the site.

Update on setting ReadOnly status on an SPSite

November 11th, 2008 by anoon

—————————————————————————————————————————————————————–

Forgive me blog for I have sinned, it has been 6 months (or so) since my last confession and I promise not to leave it so long this time ;-)

—————————————————————————————————————————————————————-

I recently had a query from an ex-colleague on a post I'd written early this year when having problems setting the read only status of a SharePoint site.  The previous post is here : SPSite ReadOnly & WriteLocked properties fail on a GET request

For context the application was for a controlled site creation and management process to replace/complement the site creation and permissions screens within MOSS and pre-populate sites will all sorts of funky data.  I never did get a real reason why the call fails but here is a sample from the code that got around the problem…

 

The HTML:

<br />

<fieldset>

    <legend>My Workgroups</legend>

    <div class="container"><a name="WorkgroupsICaptain"></a>

        <asp:Table ID="CaptainTable" runat="server" BorderWidth="0" CellPadding="0" CellSpacing="0" CssClass="custom">

                    <asp:TableHeaderRow>

                    <asp:TableCell CssClass="customth">Workgroup Name</asp:TableCell>

                    <asp:TableCell CssClass="customth">Created on</asp:TableCell>

                    <asp:TableCell CssClass="customth">Last Activity</asp:TableCell>

                    <asp:TableCell CssClass="customth">Members</asp:TableCell>

                    <asp:TableCell CssClass="customth">Status</asp:TableCell>

                    <asp:TableCell CssClass="customth">Areas</asp:TableCell>

                    <asp:TableCell CssClass="customth" ColumnSpan="2">Actions</asp:TableCell>  //   <—-  THIS IS WHERE THE BUTTON(S) GET DROPPED

                </asp:TableHeaderRow>

        </asp:Table>

    </div>

</fieldset>

<br />

 

Add the button…

 

                    Button tempBtn = new Button();

                    tempBtn.CommandArgument = groupsIdea.URL;

                    tempBtn.Width = 125;

                    tempBtn.Click += Call_LockSiteToggle;

                    tempBtn.ID = "btnToggleReadOnly" + i;

 

                    if (groupsIdea.ReadOnly)

                    {

                        tempBtn.Text = "Make Writeable";

                    }

                    else

                    {

                        tempBtn.Text = "Make Read Only";

                    }

                    readonlyCell.Controls.Add(tempBtn);

                    tempRow.Cells.Add(readonlyCell);

 

Code the button click:

 

    protected void Call_LockSiteToggle(object sender, EventArgs e)

    {

        setProperties();

       

        Button btn = (Button)sender;

        lockSiteToggle(btn.CommandArgument.ToString());

 

        loadWorkgroups();

    }

 

Code the lock:

 

    private void lockSiteToggle(string Url)

    {

        SPSecurity.RunWithElevatedPrivileges(delegate()

       {

               using (SPSite _SPSite = new SPSite(Url))

               {

                   _SPSite.AllowUnsafeUpdates = true;

               _SPSite.ReadOnly = !_SPSite.ReadOnly;

                   _SPSite.AllowUnsafeUpdates = false;

               }

       });

    }

Update on setting ReadOnly status on an SPSite

November 11th, 2008 by anoon

—————————————————————————————————————————————————————–

Forgive me blog for I have sinned, it has been 6 months (or so) since my last confession and I promise not to leave it so long this time ;-)

—————————————————————————————————————————————————————-

I recently had a query from an ex-colleague on a post I'd written early this year when having problems setting the read only status of a SharePoint site.  The previous post is here : SPSite ReadOnly & WriteLocked properties fail on a GET request

For context the application was for a controlled site creation and management process to replace/complement the site creation and permissions screens within MOSS and pre-populate sites will all sorts of funky data.  I never did get a real reason why the call fails but here is a sample from the code that got around the problem…

 

The HTML:

<br />

<fieldset>

    <legend>My Workgroups</legend>

    <div class="container"><a name="WorkgroupsICaptain"></a>

        <asp:Table ID="CaptainTable" runat="server" BorderWidth="0" CellPadding="0" CellSpacing="0" CssClass="custom">

                    <asp:TableHeaderRow>

                    <asp:TableCell CssClass="customth">Workgroup Name</asp:TableCell>

                    <asp:TableCell CssClass="customth">Created on</asp:TableCell>

                    <asp:TableCell CssClass="customth">Last Activity</asp:TableCell>

                    <asp:TableCell CssClass="customth">Members</asp:TableCell>

                    <asp:TableCell CssClass="customth">Status</asp:TableCell>

                    <asp:TableCell CssClass="customth">Areas</asp:TableCell>

                    <asp:TableCell CssClass="customth" ColumnSpan="2">Actions</asp:TableCell>  //   <—-  THIS IS WHERE THE BUTTON(S) GET DROPPED

                </asp:TableHeaderRow>

        </asp:Table>

    </div>

</fieldset>

<br />

 

Add the button…

 

                    Button tempBtn = new Button();

                    tempBtn.CommandArgument = groupsIdea.URL;

                    tempBtn.Width = 125;

                    tempBtn.Click += Call_LockSiteToggle;

                    tempBtn.ID = "btnToggleReadOnly" + i;

 

                    if (groupsIdea.ReadOnly)

                    {

                        tempBtn.Text = "Make Writeable";

                    }

                    else

                    {

                        tempBtn.Text = "Make Read Only";

                    }

                    readonlyCell.Controls.Add(tempBtn);

                    tempRow.Cells.Add(readonlyCell);

 

Code the button click:

 

    protected void Call_LockSiteToggle(object sender, EventArgs e)

    {

        setProperties();

       

        Button btn = (Button)sender;

        lockSiteToggle(btn.CommandArgument.ToString());

 

        loadWorkgroups();

    }

 

Code the lock:

 

    private void lockSiteToggle(string Url)

    {

        SPSecurity.RunWithElevatedPrivileges(delegate()

       {

               using (SPSite _SPSite = new SPSite(Url))

               {

                   _SPSite.AllowUnsafeUpdates = true;

               _SPSite.ReadOnly = !_SPSite.ReadOnly;

                   _SPSite.AllowUnsafeUpdates = false;

               }

       });

    }

SQL Server 2005 & Visual Studio 2008

June 14th, 2008 by anoon

I was having untold problems installing a new VM.  Windows 2008 with MOSS 2007, Visual Studio 2008 and SQL Server 2005.  Because I was building in that order I kept having problems after installing SQL Server.  Basically it didn't install the Management Studio or add the shortcut to the start menu.

 I tried for a long time to figure the problem out before I stumbled on a solution.  If you change the directory name C:Program FilesMicrosoft SQL Server90Tools before you do the SQL install (it's there because VS 2008 intsalls SQL Express) then the SQL install works fine and installs the Management Studio.

 I can only think that the SQL install finds the tools directory and then just assumes it doesn't need to do that bit of the install.  More likely it tries to create the directory, get a DIRECTORYEXISTS exception and tries to resume.

 Copy the old tools files back the the new tools directory when you're finished otherwise you might find VS has some problems!

Anyway, hope this help someone – I found nothing on google – maybe I'm the only one ;-)

SQL Server 2005 & Visual Studio 2008

June 14th, 2008 by anoon

I was having untold problems installing a new VM.  Windows 2008 with MOSS 2007, Visual Studio 2008 and SQL Server 2005.  Because I was building in that order I kept having problems after installing SQL Server.  Basically it didn't install the Management Studio or add the shortcut to the start menu.

 I tried for a long time to figure the problem out before I stumbled on a solution.  If you change the directory name C:Program FilesMicrosoft SQL Server90Tools before you do the SQL install (it's there because VS 2008 intsalls SQL Express) then the SQL install works fine and installs the Management Studio.

 I can only think that the SQL install finds the tools directory and then just assumes it doesn't need to do that bit of the install.  More likely it tries to create the directory, get a DIRECTORYEXISTS exception and tries to resume.

 Copy the old tools files back the the new tools directory when you're finished otherwise you might find VS has some problems!

Anyway, hope this help someone – I found nothing on google – maybe I'm the only one ;-)

Everyone wants one!

March 20th, 2008 by anoon

I've written so many SharePoint asset viewer type web parts (or applications) over the last few years I thought it was about time I blogged some code to get you started yourselves, the following will render a simple treeview that will allow you to traverse through your SharePoint site and sub sites and see what lists, libraries, users etc are in each site.

  image
        /// <summary>
        /// PopulateTreeView is a recursive function, starting at the supplied SPWeb parameter it will extract all relevant information from the site before recirsing for each sub site.
        /// </summary>
        /// <param name="web">web is the starting SPWeb (SharePoint web site) for the function.  In this case the current site i.e. the site on which the web part is placed.</param>
        /// <returns></returns>
        protected TreeNode PopulateTreeView(SPWeb web)
        {
            TreeNode top = null;
            if (web != null)
            {
                //get detail of this current web
                top = new TreeNode("Site Details(" + web.Title + ")", "0", "/_layouts/images/SPHOMESM.GIF", web.Url, "_blank");
                TreeNode node = new TreeNode(web.Title, "root", "/_layouts/images/ICHTT.GIF", web.Url, "_blank");
                node.ChildNodes.Add(new TreeNode("URL: " + web.Url, "", "/_layouts/images/NEWLINK.GIF", web.Url, "_blank"));
                TreeNode users = new TreeNode("Users", "", "/_layouts/images/stsicon.gif");
                //get all admins
                TreeNode admins = new TreeNode("Administrators (" + web.SiteAdministrators.Count + ")", "", "/_layouts/images/STSPEOPL.GIF");
                foreach (SPUser user in web.SiteAdministrators)
                {
                    TreeNode usr = new TreeNode(user.LoginName + "(" + user.Email + ")", "", "/_layouts/images/STAR.GIF", "mailto:" + user.Email, "");
                    admins.ChildNodes.Add(usr);
                }
                users.ChildNodes.Add(admins);
                //get all groups and users within those groups
                foreach (SPGroup group in web.Groups)
                {
                    //record this group
                    TreeNode grp = new TreeNode(group.Name + " (" + group.Users.Count + ")", "", "/_layouts/images/STSPEOPL.GIF");
                    //for for each user in this group
                    foreach (SPUser user in group.Users)
                    {
                        //record this user
                        TreeNode usr = new TreeNode(user.LoginName + "(" + user.Email + ")", "", "/_layouts/images/mysite_titlegraphic.gif", "mailto:" + user.Email, "");
                        grp.ChildNodes.Add(usr);
                    }
                    users.ChildNodes.Add(grp);
                }
                node.ChildNodes.Add(users);
                //get all lists (includes document libraries, discussion forums...)
                TreeNode lists = new TreeNode("Lists and libraries (" + web.Lists.Count + ")", "", "/_layouts/images/sts_list16.gif");
                foreach (SPList list in web.Lists)
                {
                    TreeNode lst = null;
                    try
                    {
                        //an exception can be thrown if an attempt to get the amount of items in a list returns null, also if the list is partially defines an exception may be thrown
                        lst = new TreeNode(list.Title + " (" + list.ItemCount + " items)", "", "/_layouts/images/iKpiList.png", list.DefaultViewUrl, "_blank");
                    }
                    catch(Exception)
                    {
                        //if the exception (above) was thrown, just record the name of the list (ignore the amount of items)
                        lst = new TreeNode(list.Title);
                    }
                    lists.ChildNodes.Add(lst);
                }
                node.ChildNodes.Add(lists);
                //recurse for each sub web of the current web
                TreeNode webs = new TreeNode("Sub Webs (" + web.Webs.Count + ")", "", "/_layouts/images/SITEVARIATION.GIF");
                foreach (SPWeb subweb in web.Webs)
                {
                    webs.ChildNodes.Add(PopulateTreeView(subweb));
                }
                node.ChildNodes.Add(webs);
                top.ChildNodes.Add(node);
            }
            //return the complete node
            return top;
        }