• Windows PowerShell Script to Output Site Collection Information

    Windows PowerShell is a fantastic tool; SharePoint 2010 has literally hundreds of different PowerShell Cmdlets that are available out of the box, if you don’t believe me check this out - http://technet.microsoft.com/en-us/library/ff678226.aspx. What about MOSS 2007? Whilst there aren’t any native Cmdlets for MOSS 2007, PowerShell can be used to access the SharePoint object model directly instead and in most cases achieve the same objectives, this isn’t as daunting as it sounds; I’m not a developer but even I have been able to find my way around the object model and put together some useful scripts (at least to me anyway!)

    I’ve recently been helping one of my customers write some PowerShell scripts to improve their reporting capabilities and reduce the burden of day to day SharePoint administration on the support team. One of the scripts that I’ve written analyses every site collection within a Web application. The purpose of the script was to identify sites that were no longer required (as they hadn’t been updated for a long time) or that had a large quota assigned but were only using a small proportion of this, so that a smaller quota could be assigned. The script outputs the following information for each site collection into a csv file:
    • URL
    • Owner login
    • Owner e-mail address
    • Last time that the root web was modified
    • The size of the quota assigned
    • The total storage used
    • The percentage of the quota being used

    I've included the script below, all you need to do is to copy this into Notepad (or your text editor of choice), edit the two highlighted variables to match your requirements - $Output specifies the location to output the results to in csv format, $SiteURL specifies the URL of the root site collection, this will then be used to discover other site collections within the Web application. Once you have done this save the file with a .PS1 extension, for example ScriptName.PS1. The script can be run on any server in the SharePoint farm from within a Windows PowerShell window using .\ScriptName.PS1.

    [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
    #Configure the location for the output file
    $Output="C:\Output.csv";
    "Site URL"+","+"Owner Login"+","+"Owner Email"+","+"Root Site Last Modified"+","+"Quota Limit (MB)"+","+"Total Storage Used (MB)"+","+"Site Quota Percentage Used" | Out-File -Encoding Default -FilePath $Output;
    #Specify the root site collection within the Web app
    $Siteurl="http://intranet.contoso.com";
    $Rootweb=New-Object Microsoft.Sharepoint.Spsite($Siteurl);
    $Webapp=$Rootweb.Webapplication;
    #Loops through each site collection within the Web app, if the owner has an e-mail address this is written to the output file
    Foreach ($Site in $Webapp.Sites)
    {if ($Site.Quota.Storagemaximumlevel -gt 0) {[int]$MaxStorage=$Site.Quota.StorageMaximumLevel /1MB} else {$MaxStorage="0"};
    if ($Site.Usage.Storage -gt 0) {[int]$StorageUsed=$Site.Usage.Storage /1MB};
    if ($Storageused-gt 0 -and $Maxstorage-gt 0){[int]$SiteQuotaUsed=$Storageused/$Maxstorage* 100} else {$SiteQuotaUsed="0"};
    $Web=$Site.Rootweb; $Site.Url + "," + $Site.Owner.Name + "," + $Site.Owner.Email + "," +$Web.LastItemModifiedDate.ToShortDateString() + "," +$MaxStorage+","+$StorageUsed + "," + $SiteQuotaUsed | Out-File -Encoding Default -Append -FilePath $Output;$Site.Dispose()};

     
     
    Below is an example of the script output.
     
     
     Brendan Griffin
  • Working with SharePoint list data - OData, REST and JavaScript

    Working with SharePoint list data using OData, REST and JavaScript

    Recently I’ve been doing a fair amount of work with SharePoint list data using OData and the SharePoint 2013 REST APIs; so I thought I would share some of my experiences with you.

    As you are aware, SharePoint lists are far from a new thing. However, they do offer a really flexible method to store a lot of data. Creating data is simple through the OOB user interface and you can find many different ways of filtering, grouping and ordering your data using views.

    However, what if you have a completely customised user interface, and need to both create and surface list based data into it? Using the client object model, the new OData and REST functionality in SharePoint 2013 is definitely one way, and this is the focus of this blog post.

    Future posts may include different CRUD operations and different entities.

    Working with OData and REST in SharePoint 2013

    I'm going to assume that you have some understanding of OData and REST. If you are really new to it as a concept then there are plenty of informative articles out there, so we are purely focusing on SharePoint 2013's implementation here.

    My first impressions about the way that you construct your RESTful HTTP requests very closely mimics the client object model; so it doesn't take long for you to familiarise yourself with; lets take a look at a few examples:

    Accessing a list with the client object model:#

    List.GetByTitle(Sales)

    And with the corresponding REST endpoint:

    http://contoso/sites/sales/_api/lists/getbytitle('Sales')

    In the example above, you can see that we are requesting a list titled 'Sales', which is what will be returned to us. If we wanted to have the items within the list returned then we would create the following:

    http://contoso/sites/sales/_api/lists/getbytitle('Sales')/items

    We can go a lot further than this. I have included a few examples below:

    Operation                             REST Endpoint                          
    Retrieve a single list   /lists/getbytitle('listname')
    Retrieve all items in a list           /lists/getbytitle('listname')/items       
    Retrieve all items in a list and select a specific property    /lists/getbytitle('listname')/items?$select=Title     
    Filter items in a list, returning only entries that start with 'A'     /lists/getbytitle('listname')/items?$filter=startswith(Title, A) eq true  

     

     

     

     

    We have briefly covered querying data, so what does this look like in action? In the screenshot below, you can see that we are querying 'all suppliers' in a custom list:

    Creating list items in SharePoint 2013 using JavaScript

    We are going to move on to creating list items using a custom UI and the CSOM:

    Our form is nothing too scary really, we are going to create a simple ‘Supplier Management’ form which will allow our users to enter some basic information about suppliers. Which is a great point really to insert a disclaimer! All of the code and examples provided here are exactly that.
    There is no support provided, and if you want to use any of this content then I recommend that it is purely for learning purposes only. None of this has been tested on any of your environments.

    Now we have that out of the way; lets take a look at the form:

    Next, we will create the JavaScript that will create a new list item when our users click on the 'create' button:

     

    function newSupplier(siteUrl) {

       
        var sName = $('#supplierName').val();
        var sRegion = $('#supplierRegion').val();
        var sProduct = $('#supplierProduct').val();
        var sAcctMgr = $('#supplierAcctMgr').val();
     
        var clientContext = new SP.ClientContext(siteUrl);

        var oList = clientContext.get_web().get_lists().getByTitle('Suppliers');   
        var itemCreateInfo = new SP.ListItemCreationInformation();

        this.oListItem = oList.addItem(itemCreateInfo);   
        oListItem.set_item('Title', sName);   
        oListItem.set_item('Region', sRegion);
        oListItem.set_item('Product', sProduct);
        oListItem.set_item('AccountManager', sAcctMgr);
        oListItem.update();

        clientContext.load(oListItem);

        clientContext.executeQueryAsync( 
            Function.createDelegate(this, this.onQuerySucceeded),
            Function.createDelegate(this, this.onQueryFailed)
        );  

    Walkthrough of the code: 

    If we take a quick walk through the code above, you can see that we are creating several variable:

        var sName = $('#supplierName').val();
       var sRegion = $('#supplierRegion').val();
       var sProduct = $('#supplierProduct').val();
       var sAcctMgr = $('#supplierAcctMgr').val();

    These simply contain the data that our users enter into the <input> elements; you can see that we are using jQuery to reference the various input boxes, and the .val(); function to capture the data.

    Moving on, we now load our current site into context, and then get the list that we want to create a list item in:

        var clientContext = new SP.ClientContext(siteUrl);
      var oList = clientContext.get_web().get_lists().getByTitle('Suppliers');

    We next need to use the ListItemCreationInformation() function and state which columns we want to populate:

        var itemCreateInfo = new SP.ListItemCreationInformation();
        this.oListItem = oList.addItem(itemCreateInfo);
        oListItem.set_item('Title', sName);
        oListItem.set_item('Region', sRegion);
        oListItem.set_item('Product', sProduct);
        oListItem.set_item('AccountManager', sAcctMgr);

    We are passing the data in our variable into the various columns in our supplier list.

    Next we need to commit the changes; by using the oListItem.Update(); function.

    Now that we have created the list item, we have to consider what happens when the operation succeeds, or fails:

    function onQuerySucceeded() {
        alert('Item created: ' + oListItem.get_id());
    }

    function onQueryFailed(sender, args) {
        alert('Request failed. ' + args.get_message() +
            '\n' + args.get_stackTrace());
    }

    If you want to learn more about CRUD operations in SharePoint 2013, using the JavaScript OM, then here is an excellent place to start:

    http://msdn.microsoft.com/en-us/library/jj163201.aspx

    Lets take a look at our form working with a couple of new entries:

    Retrieving and rendering SharePoint 2013 list items

    Earlier on in this article, we briefly covered querying list data with OData; we saw how to retrieve list items, select specific properties and filter results. In this section we are going to render our Supplier list into a custom UI. We will use jSON and jQuery to do this, along with our RESTful HTTP request.

    The first step for us is to ensure that our HTTP request is returning the data that we are expecting:

    Our URL: http://contoso/_api/web/lists/GetByTitle('Suppliers')/items

    This returns all of the list items in ATOM/XML format:

     

    This is great, but we want to work with OData/jSON and not XML. If we start fiddler, we can take a look at the same data, but returned in jSON format instead. In fiddler, you will need to set a filter:

    Now when you refresh the page, you will be seeing the jSON returned.

    In order to render our content, we will be using jQuery, specifically jQuery.ajax(). If you check out the details for jQuery.ajax(); (http://api.jquery.com/jQuery.ajax/) then you can see that it 'Performs an asynchronous HTTP (ajax) request', which is exactly what we want to do :)

    So, in order for us to retrieve our supplier information, we need to create the following code:

    <script>
        $,ajax({

            url: "http://contoso/_api/web/lists/GetByTitle('Suppliers')/items",
            type: "GET",
            headers: {
                "accept": "application/json;odata=verbose",
            },
            success: function(data){
                $.each(data.d.results, function(index, item){
                    $('#oDataSuppliers').append("<li>" + "<h1>" + item.Title + "</h1>" + "<h2>" + item.Region + "</h2>" + "</li>");
                });
            },
            error: function(error){
                alert(JSON.stringify(error));
            }

    });

    </script>

    Lets take a walk through the code above.

    There is a really good description of the settings for $.ajax() on the jQuery site (http://api.jquery.com/jQuery.ajax), but to save time, I have included the information here:

    url: "http://contoso/_api/web/lists/GetByTitle('Supplier')/items", this is the URL to where we want the send the request; note this is our OData/REST HTTP endpoint.

    type: "GET", I am using a HTTP GET request to retrieve the data from the list.

    headers: {
                        "accept": "application/json;odata=verbose",
        },

    Here we are saying in the request header that we want the server to return jSON data. Remember that by default, SharePoint is going to return XML data..

    success: function(data){
                $.each(data.d.results, function(index, item){
                    $('#oDataSuppliers').append("<li>" + "<h1>" + item.Title + "</h1>" + "<h2>" + item.Region + "</h2>" + "</li>");
                });
            },


    In this block of code, we are stating what we want to do with the data that is being returned. I want to render this content into some HTML that I can then style using CSS. Lets take a closer look at this:

    $.each(data.d.results

    Here we are using a foreach loop; so for each object that is returned, we want to append the specific properties into HTML; into an existing element with the ID of 'oDataSuppliers'. The HTML that we want to render will basically look like this:

    <ul>
        <li>
            <h1> item.Title </h1>
            <h2> item.Region </h2>
        </li>
    </ul>

    The end result will retrieve the Supplier name and their region, and will append it to an unordered list:

     

    Hopefully, through this article you have seen how we can use the client object model to create list items; and by using OData and RESTful HTTP requests, along with jQuery we were able to render our list data into a custom UI.

    For more details on REST and OData in SharePoint 2013: http://msdn.microsoft.com/en-us/library/office/fp142380.aspx
    For more information about jSON: http://json.org/
    For more information about jQuery: http://jquery.com/


    Cheers,
    Steve.

  • Using PowerShell to upload a scripts output to SharePoint

    I often get asked to help customers write PowerShell scripts to aid with the reporting and administration of their SharePoint environment and as you can probably see from my previous Blog posts, this is something I rather enjoy! Recently a customer asked me to help them write a script that would extract information from SharePoint (for example a list of Sites) and then upload this information to a SharePoint document library. This was actually a lot easier than I anticipated and I thought I would share :)

    Please find the script below, this has been tested on SharePoint 2010 and should work on 2013 too. the highlighted values need to be updated to reflect your environment -

    • $Output = The location to store the actual output of the script, this is deleted once the output file has been uploaded to SharePoint.
    • $WebURL = The web that contains the list that you would like to upload the output file to.
    • $ListName = The name of the document library to upload the output file to
    • Get-SPSite etc = Replace this with commands to extract the relevant information from the farm, in this example I'm simply reporting a list of sites for illustration purposes, which is probably as basic as you can get!

     

    ASNP *SharePoint* -EA SilentlyContinue
    #Declare Variables
    $Output = "D:\Logs\Output.txt"
    $WebURL = "http://intranet.contoso.com/Sites/IT"
    $ListName = "SharePointInfo"

    #Create something to upload, in this case a list of all sites
    Get-SPSite | Out-File -FilePath $Output
     
    #Upload the results to SharePoint
    $File = Get-Item $Output
    $Stream = $File.OpenRead()
    $Web = Get-SPWeb $WebURL
    $List = $Web.Lists["$ListName"]
    $FileCollection = $List.RootFolder.Files
    $FileCollection.Add($File.Name,$Stream,$true)
    $Stream.Close()
    $File.Delete()

    Brendan Griffin

  • Create a Site Structure using PowerShell

    Updated to reflect feedback from Wes MacDonald - http://social.technet.microsoft.com/profile/wes%20macdonald/

    Another day, another excuse to write a PowerShell script! This time I was working with a customer who needed to create a Site Collection for their HR department with a large number of Sub-Sites (one for each team within the department), each Sub-Site required unique permissions. Rather than spending an hour doing this through the UI I put together a script to automate this.

    Update the values highlighted and run, this will create a single Site Collection and a Sub-Site beneath for each of the department team names contained in text file referenced by the $Departments variable, it will remove any spaces from the names to ensure that the URL is valid and will use the original department name for the display name of the site. The parameters used to create the Site: New-SPSite and Sub-Site: New-SPWeb can be tweaked to match your particular requirements.

    ASNP *SharePoint* -EA SilentlyContinue
    $Owner = "CONTOSO\JohnDoe"
    $WebAppURL = "http://intranet.contoso.com/"
    $Departments= Get-Content "C:\Departments.txt"
    $Site = New-SPSite ($WebAppURL + "Sites/" + "HR") -Template STS#0 -OwnerAlias $Owner
    $Site.RootWeb.CreateDefaultAssociatedGroups($Owner,$null,$Site.Title)
    Foreach ($Department in $Departments) {$Web = New-SPWeb -Url (($Site.URL) + "/" + $Department.replace(" ","")) -Name $Department -Template STS#0 -UniquePermissions;$Web.CreateDefaultAssociatedGroups($Owner,$null,$Web.Title)}

    Example $Departments input file:

    Brendan Griffin

     

  • Community Sites - Where are my analytics reports!

    Community Sites are a new type of site introduced in SharePoint 2013, if you are unfamiliar the following article has some background information on their purpose and functionality - http://technet.microsoft.com/en-us/library/jj219805(v=office.15)

    I was playing around with a Community Site the other day and noticed something very strange, for some reason in Site Settings it includes links to the SharePoint 2010 Web Analytics reports. As you may know Web Analytics has been removed from SharePoint 2013 and its functionality has been replaced by the Analytics Processing component provided by Search - http://technet.microsoft.com/en-gb/library/ff607742.aspx#section1.
     
    Below is a screenshot of how this appeared:
     
     
    As Web Analytics isn’t available in SharePoint 2013 neither of these reports work, in addition to this links for the SharePoint 2013 equivalent analytics reports are missing – Popularity and Search Reports & Popularity Trends. What should appear is the following (taken from a standard “Team Site”).
     
     
    I did some digging around and found that the reason for this is that the Site Collection “Reporting” feature isn’t activated for Community Sites by default, activating this feature removes the links to the legacy SharePoint 2010 Web Analytics Reports and adds links to the new SharePoint 2013 Analytics reports. Not sure exactly why this feature isn’t automatically activated!
     
    If you do need to access the reports for Community Sites it is simple enough to activate the feature or to put
    together a PowerShell script to automate the activation of this feature across all Community Sites. To prevent this from occurring in the future you could staple the “Reporting” feature to the Community Site template, this will ensure that all new Community Sites have the “Reporting” feature activated
    automatically.
     
    Brendan Griffin