Friday, April 12, 2013

SharePoint ECMAScript to Create List of all Files & Folders in library

Recently I was asked by a client to provide a list of all files and folders (including name and ID) in a library. This library had over 15,000 files and folders and I was not allowed access to the SharePoint servers (so PowerShell & C# API were not possible). The farm's authentication method used Ping, and the way it was configured made it impossible to connect using the client side C# API.

Since I needed a flat list of all folders (not just files) I couldn't just create a list that ignored folder.

So, I resorted to some ECMAScript.

I first created a new view in the library, then used SharePoint Designer to edit the page. I removed the DataView webpart and replaced it with an HTML Form webpart. I uploaded the jquery-1.9.1.min.js file to the Forms folder (where the new view lived) and then I wrote the following JavaScript:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<script src="./jquery-1.9.1.min.js" type="text/javascript"></script>
<script type="text/ecmascript">

var context;
var web;
var list;
var query;
var allItems;
var contentTypeCollection;

function ViewAllFiles()
{
	context = new SP.ClientContext.get_current();
	web = context.get_web();
	this.contentTypeCollection = web.get_contentTypes();
	context.load(this.contentTypeCollection);
	list = web.get_lists().getByTitle("Documents");
    //First 50
    query = new SP.CamlQuery();
    query.set_viewXml("<view Scope='RecursiveAll'><viewfields><fieldref Name='Title'/><fieldref Name='FileLeafRef'/>"
    	+ "<fieldref Name='ContentTypeId'/><fieldref Name='ID'/></ViewFields><rowlimit>50</RowLimit><query>"
    	+ "<orderby Override='TRUE'><fieldref Name='ID' /></OrderBy></Query></View>");
    allItems = list.getItems(query);
    context.load(allItems);
	context.executeQueryAsync(Function.createDelegate(this, this.success), Function.createDelegate(this, this.failed));
}
function success()
{
	var ListEnumerator = this.allItems.getEnumerator();
	while(ListEnumerator.moveNext())
	{
		var currentItem = ListEnumerator.get_current();
		var _contentTypeId = currentItem.get_item('ContentTypeId');
		if(_contentTypeId == "0x010100A7875921E4CCDA46ACBCEA4C01F659F2")
			$("#documentReport").append("
<tr><td>File:" + currentItem.get_item('ID') + ":" + currentItem.get_item('FileLeafRef') + "</td></tr>
");
		else
			$("#documentReport").append("
<tr><td>Folder:" + currentItem.get_item('ID') + ":" + currentItem.get_item('Title') + "</td></tr>
");
	}
 	var position = allItems.get_listItemCollectionPosition();
	if (position != null) {
        query.set_listItemCollectionPosition(position);
        allItems = list.getItems(query);
        context.load(allItems);
        context.executeQueryAsync(Function.createDelegate(this, this.success), Function.createDelegate(this, this.failed));
    } 
}

function failed(sender, args) {
	alert("failed. Message:" + args.get_message());
}
</script>
<a href="#" onclick="javascript:ViewAllFiles();">View All Files</a>​
<div>
<table id="documentReport"></table>
</div>

To use this you just need to change out the library name ("Documents" in this case) with your own library, and then change out the content type Id that is hard coded ("0x010100A7875921E4CCDA46ACBCEA4C01F659F2" in this case) with your own Folder's content type Id. For this client the folders were a custom content type.

What this will do is essentially page through all the items (50 at a time) and dynamically add a row to the documentReport table for each one of them. It will continue to run until it "prints" all items on the screen. You can actually watch it happen.

Once it has completed you can then highlight all the rows and past it into Excel (using a Split Text with a : delimiter) if you wanted to then compare the list to something else.

This immensely helped my client when trying to verify that a data migration into SharePoint had been completed properly, and they actually identified files that had been missed in the migration!