May
31
2012

Server 8 and PowerShell published via OData

Repost from here...

 

There is a new feature of Windows Server 8 that will allow for access to PowerShell cmdlets and objects via OData served through ASP.NET. Doug Finke wrote a blog post for PowerShell Magazine on the topic. The article gives a good overview of what the Management OData feature is and how to configure it. In this blog post I will be showing off some of the steps involved in getting the service configured and what it looks like to consume the OData in PowerShell.

Setting Up the Management OData Feature

The first step in utilizing the Management OData in Windows Server 2012 is to enable the feature. You can either use Server Manager or the following cmdlet.

Install-WindowsFeature -Name ManagementOData

Once the feature has been installed you will need to install Visual Studio 2011 Beta on the Server machine. I hope there is better tooling around this but currently this is what is required in order to build the samples found on MSDN. Make sure to download the Management OData Schema Designer. For a whole lot information on the topic, download and read the whitepaper. It walks you through all the steps I’m about to, in more detail.

What Management OData Does

In simple terms (read Doug’s post for more info), the Management OData service provides RESTful endpoints that server up PowerShell objects. The schema designer is used to map cmdlets and their resulting objects to OData objects. These can then be served as JSON back through the endpoint to the client.  The Management OData Schema Designer is used to take existing modules, cmdlets and objects and map them to XML files that can then be consumed by the Management OData system and served to clients. Included with the examples are PowerShell scripts used to install the OData endpoints once they have been compiled.

Installing the Basic Endpoint Sample

Once Visual Studio 2011 has been installed open the BasicPlugin.sln solution. You can download the sample here. Once the solution is open, build it. Once the solution is built, run the SetupEndpoints.ps1 file to configure the endpoint on the local server. The file is part of the Basic Endpoint solution folder. You should now be able to navigate to the URL:

http://localhost:7000/MODataSvc/Microsoft.Management.Odata.svc

This should result in this:

To query particular resources, you can now query it like so http://localhost:7000/MODataSvc/Microsoft.Management.Odata.svc/Process. This will return all the processes on the server machine. The Content property contains all the XML for the objects.

Additionally, processes can be filtered using a URI-based syntax. For example:

http://localhost:7000/MODataSvc/Microsoft.Management.Odata.svc/Process?$filter=(Handles gt 1000)

By default the returned format will be XML. In order to return JSON, you have to use the following syntax.

http://localhost:7000/MODataSvc/Microsoft.Management.Odata.svc/Process?$format=JSON

Remember that you can utilize the new ConvertFrom-Json cmdlet to to convert the JSON to objects.

Pretty powerful stuff!

Adding new Cmdlets and Objects

The Management OData Schema Designer is used to add more entities to the OData service. Once installed there should be an icon placed on the desktop. Open the designer. The first step is to load a module that you want to model and expose in OData. For this example I will use the NetAdapter module. Type the module name into the text box and click Load New Module. Once the module is loaded you will see a big list of the types of entities the designer finds within the module. These coincide with the nouns of the cmdlets within the module. The verbs Get, Set, New, Remove will appear as check boxes next to the noun names. If a cmdlet is not defined the verb will be grayed out.

In order to map a new OData action and entity, check one of the verb for a noun. I selected the Get and NetAdapter verb and noun. Next click the “from cmdlet output” button. The cmdlet will appear in the displayed box. Clicking Add-Type will add the new OData entity. In order to successfully generate the MOF and XML needed to define the object, you will need to set a Key property. This is the uniquely defining property on the object. Name is already selected for NetAdapter.

Now you can click Generate Mof/Xml Schema. This will produce the mapping files that the Management OData service will use to translate between the REST request and the PowerShell cmdlet and resulting objects. Once saved, you can place this in C:\inetpub\wwwroot\modata.

Since the OData endpoint is constrained we need to play with the BasicPlugin a bit to get it to load the module we would like. In Visual Studio, I added the following lines to get the NetAdapter module to load into the runspace and to set the visibility of the proper cmdlets in the runspace. I just set them all to visible. Once built, copy the resulting DLL into the MOData folder and replace the one that is in there already. You may need to stop IIS first.

Now you should be able to query to the location:

http://localhost:7000/MODataSvc/Microsoft.Management.Odata.svc/NetAdapter

Note that the resource identifier (e.g. NetAdapter) is case sensitive in the beta!

Remember there is also an Invoke-RestMethod cmdlet that can be used to query the entities. Using this method, it looks something like this.

I think this is insanely powerful functionality. It seems that the tooling isn’t quite 100% yet and requires quite a bit of setup to get running but the possibilities are endless. Creating RESTful services from PowerShell modules will be a cinch! I really encourage you to read the whitepaper about this that I mentioned earlier. It contains a ton of information.

 

 

 

 

 

 

 

 

 

 

 

May
31
2012

MSDN - Data Access for Client Applications

Information pulled from here...

 

The product documentation for SharePoint 2010 includes extensive details about each of these approaches, together with examples and walkthroughs describing approaches to common client-side data access requirements. This documentation focuses on the merits and performance implications of each approach for different real-world scenarios, and it presents some guidance about how to maximize the efficiency of your data access operations in each case. Before you start, you need a broad awareness of the capabilities of each approach. The following table shows what you can do in terms of data access with the CSOM, the REST interface, and the ASP.NET Web services.

 

CSOM

REST interface

Web services

List queries

Ff798473.c40206f5-eb65-4c7e-817c-0fb0db45c5e3(en-us,PandP.10).png

Ff798473.5c044c4f-25c9-4694-a6be-2c75463019be(en-us,PandP.10).png

Ff798473.77ea8f26-8f7a-4087-862e-f81dd7978a15(en-us,PandP.10).png

List join queries

Ff798473.4f4e7d0f-b153-4a18-b92a-b10bbb9cfc6d(en-us,PandP.10).png

Ff798473.b04f0d07-1d2c-491c-8ebd-f8da1dc6c6d7(en-us,PandP.10).png*

 

External list queries

Ff798473.101541ae-dfa5-457d-bc79-3cddda160b53(en-us,PandP.10).png

   

View projections

Ff798473.f95dc899-6bf5-4e35-9869-fb882a840290(en-us,PandP.10).png

Ff798473.52298f60-e9c9-40a4-b22e-88e0e41404c9(en-us,PandP.10).png

Ff798473.c13cafdd-7995-4ba5-9554-98285f82e59c(en-us,PandP.10).png

Request batching

Ff798473.d9ef7585-a642-4536-a5b7-04fdeba712e9(en-us,PandP.10).png

Ff798473.d2b97d8c-6b45-43aa-b2ae-0ff9ba5d14af(en-us,PandP.10).png

 

Synchronous operations

Ff798473.a10bef38-86bf-4d93-98c4-d6b9c91e4623(en-us,PandP.10).png (except ECMA)

 

Ff798473.679fbf9f-4b05-4428-8c30-f1818e7bc7f4(en-us,PandP.10).png

Asynchronous operations

Ff798473.57536533-1346-470f-8c72-e3f3bea988ec(en-us,PandP.10).png

Ff798473.ffe08c49-cf71-4c80-95a1-73ffa53c0db0(en-us,PandP.10).png

Ff798473.aeca887e-179b-493e-bd09-a52d5bf6f82c(en-us,PandP.10).png

SharePoint Foundation object model access

Ff798473.3049ce3f-1264-4e34-9430-19e22af47692(en-us,PandP.10).png

   

Access to SharePoint Server functionality (beyond SharePoint Foundation)

   

Ff798473.afe36e98-f80a-40b0-af69-6403b7fd163c(en-us,PandP.10).png

Support non-Windows clients

Ff798473.9d770af0-f075-4b41-8d85-194401fd635b(en-us,PandP.10).png (ECMA only)

Ff798473.e8e0b274-044e-4e87-a1f4-9613ffdf90ab(en-us,PandP.10).png

Ff798473.ca484dfa-24a4-42a6-8f2d-800e76a87565(en-us,PandP.10).png

Support strongly-typed LINQ queries

Ff798473.d31d849d-79ae-4d7a-a9d0-19107cb17cd2(en-us,PandP.10).png (objects only, no list queries)

Ff798473.69e28530-8e6e-40fe-b4bd-98406c229529(en-us,PandP.10).png (with proxy, lists only)

 
May
31
2012

The SharePoint & jQuery Guide

Repost from here...

 

So, you've finally succumbed to the hype and decided to use jQuery in SharePoint? Good for you. I'm sure you are fully prepared with the knowledge of the pros and cons using jQuery as well as have all the requisite knowledge.

You should NOT be writing jQuery in SharePoint if…

You don't? You mean you are going to copy and paste scripts from blogs and then ask the blogger to modify the script to work for your particular circumstance? Oh, that's nice.


Well, assuming you actually want to understand what you are doing, maybe even learn a thing or two, I've decided to link to several of my past jQuery blogs in an order which will hopefully help you learn how to successfully use SharePoint and jQuery together. I'll even do my best to keep this post updated as I write new blogs on the subject.

Good luck!

Before getting started…

Make sure you have some good background knowledge.

When you start using things like SPServices and the Client Object Model to query SharePoint list data you will need to understand SharePoint's query language CAML. I always refer to it as the ugly crossbreed of XML and SQL.

If you plan to use SPServices to access SharePoint's Web Services (which I also reference in several of the blogs below), you need to get that at http://spservices.codeplex.com.

When to Choose SPServices vs. the Client Side Object Model (CSOM)

Also, if you are wondering if you should use SPServices instead of the Client Object Model you can read the helpful post put together by Marc Anderson and myself.

Be sure to keep the jQuery.com site handy as this is by far the most up-to-date site to reference the jQuery api.

The Intro to jQuery and SharePoint blogs

Here are the blogs (in learning order) to help you deploy and get started using jQuery in SharePoint.

A Dummies Guide to SharePoint and jQuery–Getting Started

This blog assumes you know nothing. What is jQuery and how can I deploy it in SharePoint?

Undoubtedly one of the most common tasks you will perform with jQuery is getting and setting SharePoint form fields. This blog walks you through the process with the most common field types. A corresponding blog post to this one is Setting SharePoint Lookup Lists w/ jQuery (+/- 20 items) because unfortunately at some point you will fall victim to this SharePoint quirk.

Creating a SharePoint Parent/Child List Relationship–No SPD Version

So, now that you understand the basics of using jQuery in SharePoint and know how to get/set SharePoint form fields, this blog helps you apply that knowledge to perform the common task of creating an automatic parent/child list relationship. There are MANY ways of accomplishing this functionality, but I actually prefer this method. It may be a little more technical than the other solutions I've blogged about for creating a Parent/Child list relationship, but this solution has the least impact on SharePoint and should also upgrade easily.

Okay, at this point you should be ready to start interacting with SharePoint list data using SPServices. This blog post walks you through the basics with a VERY commented script. If you think you have your head wrapped around reading list data with SPServices, you might also check out the following blog posts using SPServices to accomplish some tasks normally achieved using server side code:

Using SPServices & jQuery to Clone a Parent Item and All its Children – Reads items from a SharePoint List and then creates copies of those items.

Using SPServices & jQuery to Find My Stuff from Multi-Select Person/Group Field – Determines the groups a current user belongs to in order to determine if the current user is part of a group or person assigned to a list item.

A Dummies Guide to SharePoint & jQuery – An Easy to Use Content Slider

Now that jQuery and SPServices is old hat, I walk you through the process of integrating SharePoint List Data into a third party jQuery library.

Other SharePoint tips and tricks using jQuery

So, here is a smattering of other blog posts on the subject which you may find helpful, or might give you ideas for your projects. Some of them are just academic, and some you can put into practice immediately.

Using jQuery to Print a Web Part – In this blog I use a very simple third party library to print a specific web part and not the entire page.

Using jQuery to Make a Field Read Only in SharePoint – Another tip you could use to make a SharePoint form field read only.

SharePoint List Views –Quick & Easy jQuery Filter – Using a very simple script, add a filter box to an out of the box list view that filters the rows based upon what the user enters.

Using Google Maps to Populate an Address in a SharePoint New Item Form – Before I started using the Bing Map api, I played around with the Google Maps API.

A Dummies' Guide to SharePoint and jQuery–A Real World Example – A mostly academic post on the types of things you can do with jQuery to modify a page in the _Layouts directory that you don't' have direct access to.

Essential Links for the SharePoint Client Side Developer – This is a list of a lot of the jQuery/JavaScript libraries I use along with some suggestions from others. I actually need to update this list soon.

So, What's next?

What? Is this not enough? I'd say for the price you paid, it's a bargain!!

I hope to do a few blog entries on more advanced topics like Callbacks, templates, and design patterns. Also, as we move towards SharePoint vNext I do think it might be a good idea to start to wean myself off of SPServices and start using the Client Object Model more (although nothing leads me to believe that SPServices will not work in vNext). So, look for me to start a series on the Client Object Model as well and provide any tips or tricks I learn along the way.

As always, let me know what YOU want to learn and I'll see what I can do! Thanks again for stopping by.

May
31
2012

An extension method to convert a flat collection to a Hierarchical collection

This is a report from here...

 

A while ago I posted an article about LINQ to SQL and WPF treeviews. I demonstrated how to use multiple levels in treeviews and how to group data with LINQ. One interesting subject wasn't covered, namely self referencing tables or the adjacency list model. A WPF TreeView control does not support this. That is why I created a LINQ extension method to convert a flat collection to a hierarchical structure of nested collections which can be assigned to the ItemsSource of a WPF Treeview.

 

 

 

 

Adjacency model / self referencing table

 

Hierarchies like trees, organizational charts, ... are sometimes difficult to store in database tables. The most common database pattern to store hierarchical data is known as the adjacency model. It has been introduced by the famous computer scientist Edgar Frank Codd. It's called the "adjacency" model because a reference to the parent data is stored in the same row as the child data, in an adjacent column. These kind of tables are also called self referencing tables.

 

Let's crystalize this by displaying the Employees table in the Northwind database.

 

EmployeeIDLastNameFirstNameReportsTo
1 Davolio Nancy 2
2 Fuller Andrew null
3 Leverling Janet 2
4 Peacock Margaret 2
5 Buchanan Steven 2
6 Suyama Michael 5
7 King Robert 5
8 Callahan Laura 2
9 Dodsworth Anne 5

 

In this table, the child is the same kind of row as the parent. The ReportsTo column is a foreign key referencing the EmpNo column. So each employee has a reference to his/her boss.

 

If you want to use this data in a WPF TreeView, then you have to convert the adjacency list model to a hierarchical model/nested set model. This should be the result :

 

EmployeeIDLastNameFirstNameReportsToDepth
2 Fuller Andrew null 1
      1 Davolio Nancy 2 2
      3 Leverling Janet 2 2
      4 Peacock Margaret 2 2
      5 Buchanan Steven 2 2
            6 Suyama Michael 5 3
            7 King Robert 5 3
            9 Dodsworth Anne 5 3
      8 Callahan Laura 2 2

 

In SQL Server 2005 you can use CTE (Common Table Expressions) and a recursive function to query this kind of data. And SQL Server 2008, which will be released one of the next months, will provide a new SQLCLR datatype called HierarchyID which will support manipulating and querying hierarchical data. Besides these database features, I wanted to create a .NET solution which can be used to convert a flat collection to a hierarchical structure of nested collections. Next steps will describe how I implemented the LINQ AsHierarchy extension method.

 

 

 

GetEmployeesHierarchy() method

 

I first started creating a new EmployeeHierarchy class. This class contains an Employee entity (the boss) and a collection of child employees.

public class EmployeeHierarchy
{
  public Employee Employee { get; set; }
  public IEnumerable<EmployeeHierarchy> Employees { get; set; }
}

 

In .NET 3.5 we have LINQ at our's disposal. So I created a recursive GetEmployeesHierachy function which will start with the director (who does not have to report to anyone, ReportsTo = null) and query all employees which are working for him (ReportsTo == EmployeeId of boss). This will be repeated recursively. Finally this function will return a collection of EmployeeHierarchy objects.

 

public IEnumerable<EmployeeHierarchy> GetEmployeesHierachy(IEnumerable<Employee> allEmployees, Employee parentEmployee)
{
  int? parentEmployeeId = null;
 
  if (parentEmployee != null)
    parentEmployeeId = parentEmployee.EmployeeID;
 
  var childEmployees = allEmployees.Where(e => e.ReportsTo == parentEmployeeId);
 
  Collection<EmployeeHierarchy> hierarchy = new Collection<EmployeeHierarchy>();
 
  foreach (var emp in childEmployees)
    hierarchy.Add(new EmployeeHierarchy() { Employee = emp, Employees = GetEmployeesHierachy(allEmployees, emp) });
 
  return hierarchy;
}

 

This function can be called after a LINQ to SQL or LINQ to Entities (Entity Framework) query. Make sure to call the ToList() extension method. It is much more performant to first load all data from the database and then convert it to a hierachical structure. By calling the ToList() method all references to the database will be removed.

 

NorthWindDataContext dc = new NorthWindDataContext();
 
var employeesHierarchy = GetEmployeesHierachy(dc.Employees.AsEnumerable(), null);
 
treeViewEmployees.ItemsSource = employeesHierarchy;

 

AsHierarchy() extension method

 

Previous routines did work fine but I wanted a more generic solution. My motto is "do more with less code" so I created a HierarchyNode<T> class and a LINQ AsHierarchy() extension method which uses generics and anonymous functions (=Func delegates). This method will return an IEnumerable collection of generic HierarchyNode<T> objects.

 

This is the source code which does all the magic. Just copy it to one of your own projects.

using System;
using System.Collections.Generic;
using System.Linq;
 
namespace ScipBe.Common.LinqExtensions
{
  // Stefan Cruysberghs, http://www.scip.be, March 2008
 
  /// <summary>
  /// Hierarchy node class which contains a nested collection of hierarchy nodes
  /// </summary>
  /// <typeparam name="T">Entity</typeparam>
  public class HierarchyNode<T> where T : class
  {
    public T Entity { get; set; }
    public IEnumerable<HierarchyNode<T>> ChildNodes { get; set; }
    public int Depth { get; set; }
  }
 
  public static class LinqExtensionMethods
  {
    private static System.Collections.Generic.IEnumerable<HierarchyNode<TEntity>> CreateHierarchy<TEntity, TProperty>
      (IEnumerable<TEntity> allItems, TEntity parentItem, 
      Func<TEntity, TProperty> idProperty, Func<TEntity, TProperty> parentIdProperty, int depth) where TEntity : class
    { 
      IEnumerable<TEntity> childs;
 
      if (parentItem == null)
        childs = allItems.Where(i => parentIdProperty(i).Equals(default(TProperty)));
      else
        childs = allItems.Where(i => parentIdProperty(i).Equals(idProperty(parentItem)));
 
      if (childs.Count() > 0)
      {
        depth++;
 
        foreach (var item in childs)
          yield return new HierarchyNode<TEntity>() { Entity = item, ChildNodes = CreateHierarchy<TEntity, TProperty>
            (allItems, item, idProperty, parentIdProperty, depth), Depth = depth };
      }
    }
 
    /// <summary>
    /// LINQ IEnumerable AsHierachy() extension method
    /// </summary>
    /// <typeparam name="TEntity">Entity class</typeparam>
    /// <typeparam name="TProperty">Property of entity class</typeparam>
    /// <param name="allItems">Flat collection of entities</param>
    /// <param name="idProperty">Reference to Id/Key of entity</param>
    /// <param name="parentIdProperty">Reference to parent Id/Key</param>
    /// <returns>Hierarchical structure of entities</returns>
    public static System.Collections.Generic.IEnumerable<HierarchyNode<TEntity>> AsHierarchy<TEntity, TProperty>
      (this IEnumerable<TEntity> allItems, Func<TEntity, TProperty> idProperty, Func<TEntity, TProperty> parentIdProperty)
      where TEntity : class
    {
      return CreateHierarchy(allItems, default(TEntity), idProperty, parentIdProperty, 0);
    }
  }
}

AsHierarchy() examples

Call the AsHierachy() method and pass the Id/Key and the ParentId/Key of the entity as anonymous functions. As you can see, it really is that simple.

NorthWindDataContext dc = new NorthWindDataContext();
 
var hierachy = dc.Employees.ToList().AsHierarchy(e => e.EmployeeID, e => e.ReportsTo);
 
treeView1.ItemsSource = hierarchy;

 

Within each level of the hierarchical tree the original order will be preserved. So it is possible to use the LINQ OrderBy and OrderByDescending extension methods.

var hierachy = dc.Employees.OrderByDescending(e => e.LastName).ToList().
  AsHierarchy(e => e.EmployeeID, e => e.ReportsTo);

 

Of course this extension method will also work with anonymous classes.

var hierachy = (from e in dc.Employees
               select new { Id = e.EmployeeID, FullName = e.FirstName + " " + e.LastName, ParentId = e.ReportsTo }).ToList()
               AsHierarchy(e => e.Id, e => e.ParentId);

 

AsHierarchy() in LINQPad

External extension methods can also be used in LINPad. Go to Query >> Advanced Properties and add a reference to the assemby which holds the AsHierachy extension method. Don't forget to add the name of the namespace at the tabsheet Additional Namespace Imports.

LINQPad will show you a nice representation of the hierarchical structure.

 

 

 

Display hierarchy with WPF TreeView

Binding a collection of generic HierarchyNode<T> objects to a WPF TreeView is quite easy. Just set the ItemsSource of the HierarchicalDataTemplate to ChildNodes. Now the TreeView will recursively display all HierarchyNode<T> objects. Make sure you use the fixed name Entity in the binding of the template.

<TreeView Name="treeView1">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Path=ChildNodes}">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Path=Entity.FirstName}"></TextBlock>
                <TextBlock Text=" "></TextBlock>
                <TextBlock Text="{Binding Path=Entity.LastName}"></TextBlock>
            </StackPanel>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

 

his is how the TreeView will look like :

Once you have the data in the TreeView it is up to you to give it a nice visual representation. Take a look at the Custom TreeView Layout in WPF article of Josh Smith who demonstrates how to render a TreeView as an organizational chart. I already copied his XAML example and this is how my Employees tree will be displayed :

Let's summerize this article :

  • Copy the source of the AsHierarchy() extension method to your project
  • Add a TreeView control and define a HierarchicalDataTemplate which uses the ChildNodes and Entity properties in your XAML file
  • Call the AsHierarchy() method with the id/key and parentid/key in a LINQ to Objects, LINQ to SQL or LINQ to Entities query
  • Assign the result query to the ItemsSource of the WPF TreeView

I hope you like this LINQ extension method and that you can take advantage of this free code.

New improvements and a LINQ to SQL (IQueryable) version can be found in a more recent article.

 

May
30
2012

Using Powershell to play MP3 Audiobooks on Windows Phone

Re-post from here...

 

So about a year ago I changed my phone to a Windows mobile 7. Overall I’m really happy with it. Without setting the world alight with evangelistic wars, I think that if the Metro interface had come before the iPhone arrived then it’s likely it would be the dominant UI.

Anyway, one major problem I had arrived when it came to playing audiobooks. The issue was that I had three challenges when playing on the windows phone.

a) For space considerations, I wanted “read” chapters to be removed from the phone automatically

b) Some books have hundreds of chapters, but some have 12 chapters each >1hr in length. It was almost impossible to pick up where you left off. Therefore I needed to use the podcast “resume” functionality in Zune

c) This led to problem #3 – when I converted the “genre” using MP3Tagedit to podcast, they would frequently end up in a jumbled play-order depending on their date, so I needed to then ensure that Chapter1 had an earlier timestamp than chapter 2 etc. to force the right order in WP7. I could eventually get what I wanted but it was very painful and involved a bunch of manual steps as well as using BulkEditor and MP3Tagedit.

I found part of the answer in an excellent post over here, where it referenced TAGLIB# . So I launched powershell for the first time and wrote the script below.

Now, if you target it at a folder such as…

William Shakespeare/

Merchant of Venice/

Chapter1.mp3 ……

Hamlet/

Chapter1.mp3…..

It will loop through the subdirectories… renaming the files in sequence… setting the appropriate MP3 tag entries… Author = William Shakespeare/Album = BookDirectoryName/Chapter = Title.. and setting timestamp to force Zune to recognise chapter 1 as being before chapter 2..

So, here’s the code I used:

Function Zune
{
	[CmdletBinding()]
	param(
		[Parameter(Position=0, Mandatory=$True)]
		[ValidateNotNullOrEmpty()]
		[System.String]
		$Library,
 
		[Parameter(Position=1)]
		[ValidateNotNull()]
		[System.String]
		$Genre
	)
 
	cls
	
	$OriginDir = Get-Location
	
	#========Does the libary exist and contain books?=============================================
 
	if ((Test-Path -Path $Library) -eq $false) {
		write-output "$Library Does Not Exist"
		Break
	}

	$Books = Get-ChildItem $Library | where {$_.psiscontainer}
	if (!$books) {
		Write-Output "$Library Contains no books"
		Break
	}

	$librarylocation = Get-Item $Library
 
	fault Parameters===========================================================
	if (!$Genre)
	{
		$Genre="Podcast"
		Write-Host "Genre is blank, using Default $Genre" -foregroundcolor DarkGreen
	}
	else
	{
		Write-Output "Genre is " + $Genre
	}
	
	#========Load Assemblies======================================================================
	$TaglibLocation = (Resolve-path ($ProfileDir + "\taglib\taglib-sharp.dll"))
	Add-Type -Path ($TaglibLocation)
	Write-output "Taglib Loaded Successfully"
 
	#========Set up Recursive Subdirectories======================================================
	Write-Output "Processing the Library $Library"
	$NumberBooks = $books | Measure-Object | Select-Object -ExpandProperty Count
	Write-Output "Total Number of Runs is $Numberbooks"
 
	if ($NumberBooks -gt 0)
	{
		Set-Location $Librarylocation
		foreach ($book in $Books)
		{
			Write-Host "==================================================" -foregroundcolor Blue
			Write-Output "$("Processing the Book ")$($book.name)$(" in ")$($librarylocation)"
			$Chapters = Get-ChildItem $book.name *.mp3 | Sort-Object Name
			$NumberChapters = $Chapters | Measure-Object | Select-Object -ExpandProperty Count
			
			if ($NumberChapters -gt 0)
			{
 
				if ($NumberChapters -le 100) 
				{
					$pad = 2
				}
				elseif ($NumberChapters -le 255) 
				{
					$pad = 3
				}
				elseif ($NumberChapters -ge 256) 
				{
					Write-Output "$("Too Many chapters in the book :")$($book.name)"
					Break
				}

				Write-Output "$("Processing ")$($NumberChapters)$(" Chapters")"
				
				#========Set up Recursive Subdirectories==========================================
				$book.fullname
				set-location $book.fullname
				$i=1
				foreach ($chapter in $Chapters)
				{
					$title = "{0:D$pad}" -f ($i) +"$(" of $NumberChapters- ")$($book.name)"
					$Filename = $title + '.mp3'
					$chapter.fullname
					$media = [TagLib.File]::Create($chapter.Fullname)
					$media.Tag.Title = $title
					$media.Tag.Performers = "Narrator"
					$media.Tag.AlbumArtists = (get-culture).Textinfo.Totitlecase($Library.tolower())
					$media.Tag.Composers = "Composer"
					$media.Tag.Album = $book.name
					$media.Tag.Comment = $chapter.Name
					$media.Tag.Genres = $Genre
		
					if (!$media.Tag.Year) {$media.tag.year = (Get-date).Year}
					$media.Tag.Track = $i
					$media.Tag.Artists = (get-culture).Textinfo.Totitlecase($Library.tolower())
					
					$media.Save()
 
					$chapter.Creationtime = (Get-Date).date.addminutes($i)
					$chapter.LastWriteTime = (Get-Date).date.addminutes($i)
					#$chapter.LastAccessTime = (Get-Date).date.addminutes($i)
					$chapter.LastWriteTimeUTC = (Get-Date).date.addminutes($i)
					$chapter.CreationtimeUTC = (Get-Date).date.addminutes($i)
					#$chapter.LastAccessTimeUTC = (Get-Date).date.addminutes($i)
					Write-Output "$("Renaming ")$($chapter.name)$(" to ")$($Filename)"
					Rename-Item $chapter.fullname $filename
 
					$i++
				}
			}
			else
			{
				Write-Output "$("No Chapters inside the book :")$($book)"
			}
		
		Set-Location $Librarylocation
		}

		#===============================================================================================
		#========================     end of loop on books =============================================
		#===============================================================================================
	}
	else
	{
		Write-Output "$($"No Books inside the Library "$($Library))"
	}
 
	#===================================================================================================
	#========================     end of function     ==================================================
	#===================================================================================================
	Set-Location $OriginDir
}

Export-ModuleMember -Function Zune
May
24
2012

Articles about Templates and jQuery

http://weblogs.asp.net/dwahlin/archive/2011/11/23/reducing-javascript-code-by-using-jsrender-templates-in-html5-applications.aspx

May
24
2012

Dynamically adding JavaScript script tags at runtime

This is a report from here...

First Let’s discuss about the issue of loading all the javascript files together at a stroke.

  1. 1. Javascript will not allow parallel download. So the browser will not start any other download until it loads the javascripts.
  2. 2. We use to load javascript files and methods which are unnecessary for that page. For eg: In Login page, we just need some javascripts essential for Login page, but developers will add all the javascripts in common headers.

 

<script language =”javascript” src=”scriptRequiredForUserProfile.js”></script>
<script language =”javascript” src=”scriptRequiredForAddComment.js”></script>
<script language =”javascript” src=”scriptRequiredForReply.js”></script>

<script language =”javascript” src=”scriptRequiredForAddComment.js”></script>

<script language =”javascript” src=”scriptRequiredForReply.js”></script>

How to solve the above 2 issuesjQuery15204168177171158769_1337868541848?

  • Include only one script in the header.

 

<script src="”loadJS.js”"></script>


 

Now we can load the javascript dynamically using 2 ways.

 

Method 1:

 

Generate dynamic // <![CDATA[
tag using DOM

 

Maintain the list of javascripts that you need to download for a respective page.

 

 

var jsFilesArray = new Array();
jsFilesArray['home.html'] = new Array( ‘validation.js’, ‘home.js’ );
jsFilesArray['login.html'] = new Array( ‘validation.js’, ‘error.js’ );

Code to get File Name of the current page

 

 

function getCurrentPageName() {
    var fileName = document.location.href;
    var end = (fileName.indexOf("?") == -1) ? fileName.length : fileName.indexOf("?");
    return fileName.substring(fileName.lastIndexOf("/")+1, end);
}

Code to generate dynamic tag and append to the head tag.

 

 

var head = document.getElementsByTagName("head")[0];

for (var i = 0;i<jsFilesArray[getFileName()].length;i++)
{
  script = document.createElement('script');
  script.id = "id_" + i;
  script.type = 'text/javascript';
  script.src = jsFilesArray[getCurrentPageName ()][i];
  head.appendChild(script);
}


 

 

Click to download the code.

 

Method 2:

 

Use AJAX to load the JS file dynamically whenever required

 

Get the required JS file using xmlHttPRequest and execute the output by passing it into eval() method. The eval() method executes the argument.

 

So guys, load your Javascripts dynamically and experience improved performance of your application.

 

Enjoy Coding :)