RSS

Using the Cloud as a Media Hosting Option For SharePoint 2010 (Part 1–Amazon S3)

I know it’s been a while since I’ve posted anything to the blogsphere… I have to be honest to Abe, I had good reason. I have been working and working hard I should say. This means I have a lot of topics in the next upcoming months…

For this topic I’d like to focus on something my team and I have been working on and that’s SharePoint 2010 and Media files like videos, pictures and anything related to media. We recently had the requirement to create a SharePoint Web Application which used a ton of technologies. I’ll blog specifically about each at a later date, however one that caught my attention was the usage of Amazon S3 and Amazon CloudFront. In this post I’ll talk about how we are using Amazon S3, Windows Media Encoder SDK, and SharePoint to provide a great performing media experience to your SharePoint End Users.

For those that have worked with SharePoint before know that SharePoint… no matter what version… is not the best server or software for media, especially HD Videos, and high resolution pictures. Proof of this can be found in Microsoft’s attempt at supporting this through SQL’s Remote BLOB Storage (RBS). The RBS feature allows you the option of not storing BLOBs (Binary Large Objects) inline with other SharePoint Content Table entries. In other words, when you enter in items in a list, if one of the fields in the list is a File such as a large video file (the whole bit stream…), by default SharePoint stores that entry in the same SQL Content Table record entry as the other metadata details such as Title, Author, date and etc. Can you imagine the load this places on a server which needs to serve up 100′s if not 1000′s of entries all with their own large video file? While SharePoint does support this, your media experience will be horrible and that’s putting it politically correct. Acknowledging this, is one of the reasons Microsoft’s SQL team created RBS. RBS will allow you to offload your large files to another storage mechanism using “RBS Providers” which are effectively data storage providers. These providers work in sync with the inline metadata entries for a specified SQL Table and in this case your SharePoint List by communicating with RBS api’s and SQL.  There are many debatable reasons to either use the default (SQL FILESTREAM) or create your own providers (which by the way Microsoft only reccomends ISV’s do…), we have chosen to go down a different path. Maybe we will incorporate our design with the RBS provider architecture Microsoft provides… but then again maybe not. That’s another post for another time. With that, I’ll get into our design.

In order to understand our design, let’s first get started talking about our requirements. At first we thought some of the requirements were going to be way to complex to implement in the little amount of time given to implement this. However after a quick Proof Of Concept (POC) and a little light at the end of the tunnel things started going our way. To start, our requirements actually turned out to be simple, create a list which allows end users to upload vidoes, pictures, audio and other files. The files must not be uploaded on the Web Front end servers, but rather on Media Hosting servers so as to not put too much pressure and resource servicing on the Presentation Servers. Along with the first two requirements, we also had to convert and encode all the vidoes to a standard MP4 format, along with create a thumbnail, and validate the length 10minutes and less. The Architecture and implementation we put in place was done by my colleague (Soledad Pano) here. In her post she outlines the three major components she used to build it:

  1. Custom Upload Process: This is the front end of the solution. It consists of a custom list with a custom upload form. The list has the link to the media file and more metadata fields (title, author, date, keywords, etc). When you click on create a new item on the list the custom upload form is opened and you can browse for a file to upload. The form has the required validation logic and it serves to save the assets to the configured location, which can be a Sharepoint library or an external location, like File System or FTP server. When the upload finishes you are redirected to the list item edit form so you can enter the metadata. The experience is similar to uploading a file to a Sharepoint document library.

  2. Media Processing Backend Process: This consists of a timer job that queries the Media Assets list for items to process. It encodes the videos, generates thumbnail and poster images and uploads everything to the final destination. Finally, it notifies the user of the result of the process by email. For the video encoding we used the Microsoft Expression Encoder SDK. As I will explain later, this SDK cannot be used inside a Sharepoint process, so it runs in a separated process that is invoked from the timer job.

  3. Storage Manager: this is a flexible and extensible component that abstracts the logic of saving (and deleting) a file to the final location depending on the flavor chosen thru configuration (File System, Sharepoint library or FTP). This component is used both by the front end upload mechanism and the back end media processing job.

The above is take from Soledad’s post, In which she utilizes the Storage Manager component as one of the extensible points we can use to integrate with Amazon S3.

The Storage manager implements a single interface: IAssetStorageManager

public interface IAssetStorageManager
{
    void Delete(string fileUrl);
    string Save(System.IO.FileInfo file);
    string Save(string fileName, System.IO.Stream fileStream);
}

The above interface tells you everything you need to know about what to implement. If you want to upload a file or stream, use the “Save” methods. if you want to delete the file, use the “Delete” Method. So with Soledad’s design, I implemented a StorageManager that uploads to AmazonS3.

Getting Started with Amazon

To use AmazonS3, you must first sign up on Amazon’s site: http://aws.amazon.com/

image

Click the Sign Up button, enter in your information, give em’ a credit card, and you’re done. If you already have an Amazon account from purchasing books and other items, you can use that account.

Once you have an account, you can login to your AWS management console and get your AmazonS3 Access KeyID, SecretID key (Remember your Access Key ID and Secret Key ID, you’ll need this for access to the AmazonS3 through the API):

SNAGHTML6950e0

You can also navigate to the AmazonS3 Area (https://console.aws.amazon.com/console/home):

SNAGHTML3fb17b

Once inside AmazonS3, the AWS Panel is easy to navigate. If you want to create AmazonS3 Buckets you can, if you want to see which items are inside the Buckets you can and so on and so forth. The only catch is that the AWS Panel is rather lacking as far as functionality, no searching; no sorting; just really a look inside what you have.

SNAGHTML59950b

Create your bucket name, remember this name because it’s the name you will use for the AmazonS3StorageManager.

AmazonS3AssetStorageManager

The implementation is below:

   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Text;

   5: using System.Net;

   6: using System.IO;

   7:  

   8: using Amazon.S3;

   9: using Amazon.S3.Model;

  10: using Amazon.S3.Util;

  11: using Microsoft.SharePoint.Administration;

  12: using Common.Logging;

  13:  

  14: namespace Common.AssetStorage

  15: {

  16:     public class AmazonS3AssetStorageManager : IAssetStorageManager

  17:     {

  18:  

  19:         private string bucketName = string.Empty;

  20:         private string keyPrefix = string.Empty;

  21:         private string accessKeyID = string.Empty;

  22:         private string secretAccessKeyID = string.Empty;

  23:  

  24:         AmazonS3 client;

  25:         private Logger logger;

  26:  

  27:         public AmazonS3AssetStorageManager(string _bucketName, string _keyName, string _accessKeyID, string _secretAccessKeyID)

  28:         {

  29:             // setup some class level variables

  30:             bucketName = _bucketName;

  31:             keyPrefix = _keyName;

  32:             accessKeyID = _accessKeyID;

  33:             secretAccessKeyID = _secretAccessKeyID;

  34:             logger = new Logger();

  35:         }

  36:  

  37:         public void Delete(string fileName)

  38:         {

  39:             // To Delete we need the exact key of the file that is in AmazonS3

  40:             // as well as the bucketName where the file exists

  41:             // In my implementation the key is the KeyPrefix-FileName

  42:             string uniqueKeyItemName = string.Format("{0}-{1}", keyPrefix, fileName);

  43:             DeleteObjectRequest deleteObjectRequest =

  44:          new DeleteObjectRequest()

  45:          .WithBucketName(bucketName)

  46:          .WithKey(uniqueKeyItemName );

  47:                        

  48:             using (client = new AmazonS3Client())

  49:             {

  50:                 try

  51:                 {

  52:                     client.DeleteObject(deleteObjectRequest);

  53:                     logger.LogToOperations(Categories.Media, EventSeverity.Information, "Amazon Object KeyID: {0} deleted successfully", uniqueKeyItemName   );

  54:                 }

  55:                 catch (AmazonS3Exception s3Exception)

  56:                 {

  57:                     logger.LogToOperations(s3Exception, Categories.Media, EventSeverity.ErrorCritical,

  58:                                            "Error Occurred in Delete operation for ObjectKeyID: {0}", uniqueKeyItemName );

  59:                 }

  60:             }

  61:            

  62:         }

  63:  

  64:         public string Save(FileInfo file)

  65:         {

  66:             using (FileStream fileStream = new FileStream(file.FullName, FileMode.Open))

  67:             {

  68:                 return Save(file.Name, fileStream);

  69:             }

  70:  

  71:         }

  72:  

  73:         public string Save(string fileName, Stream fileStream)

  74:         {

  75:             // ToUpload to AmazonS3, we can use either HTTP or HTTPS

  76:             // When using HTTPS, you have to make sure you have the AmazonS3 x.509 cert

  77:             // trusted in your cert store

  78:             AmazonS3Config S3Config = new AmazonS3Config()

  79:             {

  80:                 ServiceURL = "s3.amazonaws.com",

  81:                 CommunicationProtocol = Amazon.S3.Model.Protocol.HTTP,

  82:             };

  83:  

  84:             using (client = Amazon.AWSClientFactory.CreateAmazonS3Client(

  85:                     accessKeyID, secretAccessKeyID, S3Config ))

  86:                 {

  87:                     return UploadToAmazon(fileName, fileStream);

  88:                 }

  89:           

  90:         }

  91:  

  92:         string  UploadToAmazon(string fileName, Stream fileStream)

  93:         {

  94:             try

  95:             {

  96:               

  97:                 string uniqueKeyItemName = string.Format("{0}-{1}", keyPrefix, fileName);

  98:                 PutObjectRequest request = new PutObjectRequest();

  99:                 request.WithInputStream(fileStream);

 100:                 request.WithBucketName(bucketName)

 101:                     .WithKey(uniqueKeyItemName);

 102:                 request.WithMetaData("title", fileName);

 103:                

 104:                 // if header is needed...

 105:                 // Add a header to the request

 106:                 // You can add custom header values as well as specific values to use in AmazonS3

 107:                 // for Querying the item in AmazonS3

 108:                 //request.AddHeaders(AmazonS3Util.CreateHeaderEntry ("ContentType", contentType));

 109:  

 110:                 // Here we explicitly allow all users the ability to read the specific file.

 111:                 // We can put security policies on files, buckets, and other items in AmazonS3

 112:                 S3CannedACL anonPolicy = S3CannedACL.PublicRead;

 113:                 request.WithCannedACL(anonPolicy);

 114:                 S3Response response = client.PutObject(request);

 115:                 

 116:  

 117:                 // if you want to create a temporary  AmazonS3 upload location based on some expired time

 118:                 // for security reasons you can do the below:

 119:                 //GetPreSignedUrlRequest publicUrlRequest = new GetPreSignedUrlRequest().WithBucketName(bucketName).WithKey( uniqueKeyItemName ).WithExpires(DateTime.Now.AddMonths(3) );

 120:                 //var urlResponse = client.GetPreSignedURL(publicUrlRequest);

 121:  

 122:                 response.Dispose();

 123:  

 124:                 // otherwise the url will be a public url 

 125:                 // which is always https://s3.amazonaws.com/[yourBucketName]/[YourUploadedFileKey]

 126:                 var urlResponse = string.Format("https://s3.amazonaws.com/{0}/{1}", bucketName, uniqueKeyItemName );

 127:                 return urlResponse;

 128:             }

 129:             catch (AmazonS3Exception amazonS3Exception)

 130:             {

 131:                 if (amazonS3Exception.ErrorCode != null &&

 132:                     (amazonS3Exception.ErrorCode.Equals("InvalidAccessKeyId")

 133:                     ||

 134:                     amazonS3Exception.ErrorCode.Equals("InvalidSecurity")))

 135:                 {

 136:             

 137:                     logger.LogToOperations(amazonS3Exception, Categories.Media, EventSeverity.ErrorCritical,

 138:                                            "Error - Invalid Credentials - please check the provided AWS Credentials");

 139:                     return null;

 140:                 }

 141:                 else

 142:                 {

 143:                     logger.LogToOperations(amazonS3Exception, Categories.Media, EventSeverity.ErrorCritical,

 144:                                                    "Error occured when uploading media: {0}",amazonS3Exception.Message );

 145:                     return null;

 146:                 }

 147:             }

 148:         }

 149:     }

 150:     

 151: }

The AmazonS3 Storage Manager implements the 3 methods Save(x2) and Delete. To programmatically work with AmazonS3, you have a variety of options. You can use the REST interface, SOAP interface, or use the SDK Frameworks provided by Amazon and the community.

Using the REST interface is the Rawest way to communicate and by far the most complex, and in my opinion the most powerful way. When using the REST interface, many different programming languages and environments are supported, such as JavaScript, Perl, PHP, Java, .Net (C#, F#, VB.Net, C++), Ruby, Node.js, objective C++, and the essence of this article SharePoint development. The catch is using the RAW interface requires deep knowledge of basic Web programming stacks, such as manipulating HTTP Headers, working with the HTTP Body, HTTP Response and streams.

Using the SOAP Interface is easier to work with if you’ve ever done Web Service Programming. Just create a proxy based on the SOAP WSDL, and you can write code against the WSDL generated proxies. Most programming languages support proxy generation. The only caveat here is when working with certificates, security policies and all things related to security the SOAP interface can easily get in the way and cause headaches and issues later down the road.

Using SDK’s for specific programming languages is the simplest approach because it hides and encapsulates all the gory details from the previous two methods: REST and SOAP. Underneath the SDK frameworks, they use a mixture of REST and SOAP calls depending on the SDK. Luckily for SharePoint Developers, there is a .Net SDK available that even includes a VS.NET Plugin and project template that expedites your usage of Amazon S3 into the SharePoint world. If you navigate to this URL: https://aws.amazon.com/net/ you will find a ton of videos, sample code, articles and etc, pointing you to how to best write code against the .Net SDK.

Thus, for the purpose of speed, I will outline my steps used to work with the .NET SDK for Amazon to upload media to a SharePoint List using the AmazonS3AssetStorageManager.

Using the Amazon S3 .NET SDK

The first thing I did was to download the SDK for .Net and install it inside the VS.NET 2010 development environment. Once that was done, I opened a dummy project inside VS.NET to see how the AWS project template lead me to interact with AWS.

SNAGHTML87051f

I let the wizard run and I examined the code produced by the project template wizard. The Wizard first asked me to enter in my AWS Credentials and setup my account information:

SNAGHTML88e24c

I typed in my display name, Access Key ID, and Secret Access Key. The Account number is optional. Immediately a project opened with all the information needed to programmatically work with Amazon S3 in Visual Studio .Net 2010:

SNAGHTML8e5a62

The actual source code revealed that was of importance to my Amazon S3 implementation was this:

   1: // Print the number of Amazon S3 Buckets.

   2:               AmazonS3 s3Client = AWSClientFactory.CreateAmazonS3Client();

   3:  

   4:               try

   5:               {

   6:                   ListBucketsResponse response = s3Client.ListBuckets();

   7:                   int numBuckets = 0;

   8:                   if (response.Buckets != null &&

   9:                       response.Buckets.Count > 0)

  10:                   {

  11:                       numBuckets = response.Buckets.Count;

  12:                   }

  13:                   sr.WriteLine("You have " + numBuckets + " Amazon S3 bucket(s) in the US Standard region.");

  14:               }

The code above simply lists the buckets based on my Amazon    S3 account and credentials. This lead me to investigate the AWSClientFactory, and AmazonS3Client  classes. Lo and Behold there are many methods, and classes that make it very easy to upload entries into your amazon bucket. The main object to work with is the AmazonS3Client object. this object allows you to delete, create, upload, modify and retrieve almost any item in AmazonS3. The object supports synchronous and asynchronous calls for more efficient development and implementation patterns.

So basically, all I needed was the AmazonS3Client, the media file stream, the file stream name, bucketName, AccessID, and Secret ID values to upload the item into the AmazonS3 Bucket. Once I uploaded the media into the bucket I simply returned the URL to where this item resided inside AmazonS3. I won’t go into the specifics as you can step through the code from above and read the very detailed documentation Amazon has.

So you may be wondering how I got it all to run with Soledad’s design?

Well, getting all this to run, required me to hook up to the Storage manager. In Soledad’s design she also makes use of the “Factory” pattern. Thus, there is a factory class that will give you the particular storage manager based on a setting inside the config store list. All configuration is saved in a Sharepoint list, and the Sharepoint Config Store is used for retrieving it. Here is part of the factory code outlining the AmazonS3StorageManager class:

   1: public class AssetStorageFactory

   2:

   3:  static public IAssetStorageManager GetStorageManager(string configCategory,string webUrl)

   4:  {

   5:      var configHelper = new ConfigHelper(webUrl);

   6:      string storageMethod = configHelper.GetValue(configCategory, StorageMethodConfigKey);

   7:      if ("AmazonS3".Equals(storageMethod, StringComparison.InvariantCultureIgnoreCase))

   8:      {

   9:          return new AmazonS3AssetStorageManager("test", "devPrefix", "AB123-myAmazonKEYID-ZZZ", "123ABC-MySecretKeyID-ZZZ");

  10:      }

  11:      else if (true)

  12:      {

  13:          // ...Other Storage Managers 

  14:      }

  15:      throw new ArgumentException(String.Format("Incorrect configuration Value '{0}' in ConfigStore for category '{1}' and key '{2}'. Supported options are: '{3}'",

  16:          storageMethod, configCategory, StorageMethodConfigKey, "FileSystem|FTP|SPLibrary"));

  17:  }

  18: }

Once everything was hooked up, all I had to do was deploy the components and configure the entries inside the Config Store and rest is… “ourstory”

In case you’re wondering what the requirements are for deploying only the AmazonS3 part, that’s even more simpler. The AmazonS3 SDK provides all of its functionality inside 1 Assembly (AWSSDK.dll), by default install it can be found here: C:\Program Files (x86)\AWS SDK for .NET\bin. The best thing about this assembly is that it’s strongly named. This means that to install it on SharePoint, just install it /register it inside the Global Assembly Cache (GAC). This assembly will need to be installed on all servers that need to run or interact with the AmazonS3 system.

 

Happy SharePointing!!!

 
2 Comments

Posted by on 2012/01/19 in Uncategorized

 

Azure EAI CTP – First Public Review

http://blogs.msdn.com/b/avkashchauhan/archive/2011/12/17/windows-azure-service-bus-eai-and-edi-first-public-ctp-availability.aspx

 
Leave a comment

Posted by on 2011/12/19 in Uncategorized

 

Biased Comparison Most Popular Cloud OS’ part 1

In this post I attempt to give you a biased view of the most Popular Cloud OS’ in the industry today. I will cover downloading and installing, Usage, and general feedback on what I’ve noticed about each system. The Cloud computing systems I will cover are; Windows Thin PC, Google Chrome OS, and Joli OS. The reason I’m doing a biased comparison is because I have already found a like and dislike to the various systems I will be comparing, which obviously skews any objective thought, or difference.

Downloading:

Windows Thin PC

To access and download the bits of Windows Thin PC, you’ll need either a MSDN, TechNet license. Here depending on your license, the install  consists of one 1.6GB ISO file. http://msdn.microsoft.com

Google Chrome OS

To access Google Chromium or Chrome OS, there are a couple of ways to get the bits. The first way is officially to download the source codee and compile the system yourself. You can download the system from the developer pages on the Chromium projects and developer guide: (http://www.chromium.org/chromium-os/developer-guide). The second way is a more un-official way. Since this OS is a open source project, there are many developers who keep track of the progress and maintain sites for downloading the latest builds. You can find such a site maintained by Hexxeh (http://chromeos.hexxeh.net/)

If you plan to build your own copy, which means you’ll have total control over content and accounts, you’ll need to have a Linux system on hand to compile the OS. In the developer guide, it mentions using Ubuntu, however any flavor of Linux should work as I used Gentoo to build my images.

I must warn you, compiling the OS is not for the faint at heart, and depending on the options you choose when downloading from the Git hub source tree, the process can take about an hour or more depending on the speed of your network and computer system.

The Google Chrome OS experience is a trying one… Just in getting access to the installation bits is a challenge, and building and compiling is not for the faint at heart as I mentioned previously. Once you have the bits, you can either create a bootable USB Thumb drive, VM Image such as VM Ware, Virtual Box or the Open Source Qemu image. Qemu images appear to be the best image format, because depending on the version you download, some of the daily builds break VM Ware and VBox images. To give you an example, when I first tried to download and build the image, I created a VM Ware image and place it on one of my USB Drives. The Image itself couldn’t access the Network stack thus the image was useless. My Qemu image on the other hand was fine. A couple of days later, I downloaded the new builds, and the VM Ware image worked, my Qemu image worked, but my VBox image didn’t…

Joli OS

To access JoliOS, you will need to download it’s ISO file located here http://www.jolicloud.com/download. The current version if JoliOS v1.2 and it’s a 691 mb download.

 

Installation:

Windows Thin PC

First and foremost I’ll say the installation experience of Windows 7, oops, I mean Windows Thin PC is like any normal Windows Installation. Click Next a few dozen times and you’re done. The Windows Thin PC leaves only like 2 screens that differ from your normal Windows 7 installation. If you’re not careful, you’d swear you were still in Windows 7. Here are some screen shots of the windows 7, I mean Windows Thin PC installation:

image image
image image
   

image

Overall the experience is a rather pleasant and rather quick, like 5-10 minutes quick. For those advanced techies out there, you do have advanced options where you can change many of the default settings

Google Chrome OS

Overall, my impression of the Google Chrome OS installation experience was also a quick and pleasant one. It too gave the feeling of click a few dozen times and you were finished. There were some mandatory hardware requirements, as you couldn’t get pass the first screen unless you have a supported Network card/Adapter. The next screen prompted you for a Google account, no surprise there, being this whole OS is based upon the Google Cloud system/services. After you type in your google account credentials, you choose a profile picture, and you’re done. If you’re following and wondering “wait, that wasn’t an install, that was really just a configuration of your user account” You’re right.  To be honest, there was no install!

The installation was simply start up the OS, and login with your Google Account credentials. Don’t you just love the *nix systems, just turn on a go!!!

Below are some screenshots showing the install/ or better yet User Profile experience.

image image
image image
   

image

Within seconds I was online and communicating with my new Google-Chrome Book. BTW I installed this on a Dell Mini, but my wireless adapter didn’t work so I had to use my Gentoo skillz to get it working… Smile

Compared to the Windows Thin PC, this installation was actually WAY quicker, we’re talking about 45 seconds and I was done!

Well I must digress a little there is an install experience, however it’s unlike the normal installation of your Windows Thin PC and JoliOS systems. To be more fair to the other too, what I explained above was the “Start Up” experience and not the installation experience. While it’s true there is no “Installation experience” when you boot up to Google Chrome OS, there is one if you want to not use a USB Thumb drive to boot from, and boot directly from the hard drive on your system. To do this requires that you login into your system as root (If you compiled your own system you created your own root password so this shouldn’t be a problem) otherwise if you downloaded a pre-built system, you’re at the mercy of the creator to provide you with this password.

Once you’re logged in as root, there is a command that you can run that will reformat, and copy the USB Thumb drive bootup image and files on to your system. The process takes seconds, like 30 seconds or so.

Thus the real installation experience is one where you need to open up a command prompt by pressing Ctrl+ Alt + F1 , and then typing a few dd and fdisk command prompts…

Joli OS

Now the JoliCloud based OS installation was a true installation like that of WIndows Thin PC. It’s installation package and feel renders the same feel of a debian based Linux system like Ubuntu. It contained all the screens your normal Ubuntu system contains, including the more advanced options such as creating partitions, choosing mount points and etc. Overall the installation experience was smooth and painless like that of Windows Thin PC and Google, a few dozen clicks and you’re done. Unlike the Google Chromium OS, there were no requirements to actually have a network connection, as  you could actually install it. Below are some screen shots of the installation process and screens:

image image
image image
image image
image image
image image
image image

image

In the next posting, I’ll go over the differences of each OS when using it, applications, and general feedback of the look, feel, speed, and impression of the OS’s

 
1 Comment

Posted by on 2011/08/06 in Uncategorized

 

Locating SharePoint Features with PowerShell

I figure I’d write this quick post moreso for remembering sake than anything else….

We are in the middle of creating deployment scripts for our SharePoint Development cycle. Today we have the task of enabling various different features using PowerShell. A good site to view various different powershell syntax can be found here:

http://www.sharepointanalysthq.com/2010/09/sharepoint-2010-powershell-feature-cmdlets-2/

One of the tasks we needed to do was to enable some of the standard SharePoint features, such as the SharePoint Enterprise Features explained here.

Well naturally we decided to place these features inside a web site template, and then upon deployment run a powershell script to apply the web template to the site as found in this code below:

   1: Param($SiteUrl,[String]$WebTemplateName,$ScriptsFolder)

   2:  

   3: #### Properties ####

   4: $getValue = $EnvConfig

   5:  

   6: $watch = New-Object System.Diagnostics.StopWatch

   7: #### End Properties ####

   8:  

   9: echo "Checking Execution Policy"

  10: &;$ScriptsFolder\WriteLog.ps1 -Message "Checking Execution policy"

  11:  

  12: $execPolicy = Get-ExecutionPolicy

  13: if(!(($execPolicy) -eq "RemoteSigned")){

  14:     Set-ExecutionPolicy RemoteSigned

  15:     echo "Setting Execution Policy to RemoteSigned"

  16:     &;$ScriptsFolder\WriteLog.ps1 -Message "Setting Execution policy to RemoteSigned"

  17:  

  18: }

  19:  

  20:  

  21: function apply-web-template(){

  22:     [System.Reflection.Assembly]::Load("Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c") 

  23:     echo "Applying web template to site collection"

  24:     &;$ScriptsFolder\WriteLog.ps1 -Message "Applying web template to site collection"

  25:     

  26:  

  27:     $site= new-Object Microsoft.SharePoint.SPSite($SiteUrl)

  28:     $site.RootWeb.ApplyWebTemplate($WebTemplateName)

  29:     $site.Dispose()

  30: }

  31:  

  32: #Not continue on error

  33: trap [Exception] {

  34:     echo "There was errors"

  35:     break;

  36: }

  37:  

  38: $watch.Start()

  39:  

  40: apply-web-template

  41: $watch.Stop()

  42: $time = $watch.Elapsed.ToString()

  43: echo "Time elapsed: $time"

  44: &;$ScriptsFolder\WriteLog.ps1 -Message "Time elapsed: $time"

  45:  

  46: echo "Setting Execution policy back to $execPolicy"

  47: &;$ScriptsFolder\WriteLog.ps1 -Message "Setting Execution policy back to $execPolicy"

  48: Set-ExecutionPolicy $execPolicy

 

However upon running the script we ran into some errors. These errors were dealing with individual features not being enabled for various reasons. We wanted to test individual features being enabled using PowerShell. Question is, how do you determine some of the SharePoint Features Out of the box, because they are not named according to anything that make sense…

Take a look:

image

What’s the name of the above feature? It’s not: SharePoint Server Enterprise Site Collection  It’s actually named PremiumSite.

So How do you figure out some of the others?

Well this is what I did. I knew from google that one of the features I was interested in was the SharePoint Enterprise Features thus I started there. From google I learned that this feature can be found in the Folder: C:\program files\common files\microsoft shared\web server extensions\14\template\features\PremiumSite.

When I went to this location I found this file:

Feature.xml

image

Notice above the value for Title and Description. These values use the embedded resource mechanism of the .Net Framework, and the Resources token to get exactly what these names mean. Thus I went searching, the file, osrvcore either had to be an assembly or a resource file that could dynamically be converted into an assembly at runtime, so I searched my computer.

What I found was a file in this directory:

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\Resources

image

The file name osrvcore.en-US.resx  was just the file I was looking for. I opened this file up and saw all the names of the Out of the box SharePoint Features, and where they point to feature folder wise.

image

In this resource file, the name of the feature found in the c:\program files\common files\microsoft shared\web server extensions\14\template\features will be PremiumSite minus the suffix “FeatureTitle”.

Now we can write a powershell script such as this to get this and related features, and also enable them such as this:

   1: Get-SPFeature 

   2:     | where-object {$_.displayname -eq "PremiumSite" } 

   3:     | %{ Enable-SPFeature -Identity $_ -url "http://localhost" }

 

Done…

 
Leave a comment

Posted by on 2011/07/29 in Uncategorized

 

Is Rain in our forecast, because of heavy cloud computing?

For those not up on the latest and greatest. Cloud computing seems to be the buzz word in the industry. Cloud computing refers to Computers, devices, servers, clients, applications, solutions and anything you can think of in this modern time running in the clouds. Pretty soon it will be running on systems in Quadrants and start clusters, but that’s another story for another era, even though we’re supposed to be in the age of Aquarius or the age of Aires depending on if you’re astrologist or sun solstice subscriber. This age some say deals with fire, electricity, motion, energy, which can easily relate to computers, lasers, and technology .

But I digress, Cloud computing deals with the idea that applications and systems will run on computers on the “Internet” hosted by Major Companies like Amazon, Google, IBM, Oracle and Microsoft. This new network of computers is termed “The Cloud”.  One of the going thoughts is there will no longer be a need for Personal Computers at home (the Home PC), as new computers henceforth known as “Devices” will run with less powerful components, but still maintain the speed and functionality of PC. The idea stems from the fact that almost everyone has a mobile device with them, and no longer is that device constrained to remain at home. It can go everywhere with you. Kind of like the American express slogan “Never leave home without it”.

Most of the major computer manufacturers and software developers are building “devices” and software that will run  run “in the cloud”. For example, Microsoft  just announced it’s release of Microsoft Thin PC.

 

image

image

A very scaled down version of Windows 7 designed to run on the new “Netbooks”, and other less powerful computers. This OS kind of rivals Google’s Chrome OS,

image

which in a sense better rivals JoliCloud, and it’s JoliOS 

image

 

and as a far stretch the likes of MeeGo

image

and Ubuntu’s NBE (which has been merged into Ubuntu 11.04).

The applications, that can run in the cloud are too numerous to list, however I’ll mention a few, because you’ve probably been using these already without knowing they are running on cloud based infrastructure:

  • Google Docs, and anything Google Related. I call these guys the Cloud trackers!!!
  • Amazon EC2
  • Office 365
  • DropBox
  • OpenGoo
  • MSN Live
  • Skype

These are just some of the software applications that are running in the “Cloud”.

So now, I ask the question are we relying too much on “The Cloud” Will the cloud get too heavy and eventually start raining on us bits and bytes, and cluster storms, and hit us with bytening!? Will we get so out of sync that the Maxtrix will be here sooner than we think. Can you imagine the Microsoft, Amazon, Google, IBM, or Oracle becoming the “Agent Smith’s” of the world telling us what we can and can’t have “in the Cloud”. Controlling our very devices to the point where it wakes us up to tell us we have a meeting or our device will be rendered obsolete? Just a thought… Up Next a comprehensive comparison of the Cloud OS’s

 
Leave a comment

Posted by on 2011/07/24 in Uncategorized

 

Start of the Cloud Computing Wars

Most of the major computer manufacturers and software developers are building “devices” and software that will run run “in the cloud”. Microsoft just announced it’s release of Microsoft Thin PC. A very scaled down version of Windows 7 designed to run on the new “Netbooks”, and other less powerful computers. This OS rivals Google’s Chrome OS, which in a sense rivals JoliCloud, and as a far stretch the likes of MeeGo and Ubuntu’s NBE (which has been merged into Ubuntu 11.04).

In a future post, I’ll try to do a small comparison between the different OS’s

 
2 Comments

Posted by on 2011/07/11 in Uncategorized

 

The 960 Grid in SharePoint Made Easy

Recently my team and I were tasked with creating a SharePoint 2010 solution utilizing windows workflow, WCF REST, web parts, and SharePoint out of the box functionality. The project in general is to create 2 different SharePoint web sites. Without going into all the specifics, one site is a public site and the other an internal portal. One of the requirements is to convert the SharePoint Default look and feel into  customer branded site, no surprise there!

Well the surprise comes in the form of how the Branded site will look and behave. Our client requires us to use the  960 grid system to position sections and elements on the page… What Fun!!!

So, anyone who has done SharePoint Branding project before know that SharePoint is very picky about what we change, and how we change it, thus the challenges. Accomplishing this we were presented with quite a few obstacles, such as the infamous Office Ribbon, SharePoint Menus, the “Site Actions” button, and architecture of how SharePoint 2010 works just to name a few. In this series of Posts I will attempt to explain how we overcame these tasks and still designed a SharePoint Branded Solution using the 960 grid system.

One of the main topics I’d like to discuss here is  exactly what the 960 grid is all about for those that don’t understand it or have never heard of it, and how it affects SharePoint 2010 branding solutions. So Shall I proceed????

Act I: The Preface

Initially, we were thinking this should be easy, until we realized that the client would have to maintain the site after we’re gone. Easy task you say…. Well the client doesn’t have any SharePoint developers on staff, nor are they looking to get some in the future.

We have to adjust the default SharePoint 2010 master pages in a sway so that it would be easy for  graphical Designers to modify the the pages and page layouts. According to Microsoft, one of the reasons SharePoint 2010 is not “sexy” upon default deployment is to enforce the point that SharePoint should be branded for your company. So Microsoft makes it “ugly” so that you would want to change it, brand it, change the look and feel of it.

I say this is hogwash…. there are other ways you could accomplish this by just using placeholders saying things like “Your company logo goes here” or something obvious. Along with this Microsoft could make SharePoint 2010 just plain ol “sexy”.

One way in which to do this is to just allow graphical designers design the UI. I mean it only makes sense that’s what they went to school for, and it is what  a designer does best. However, to do this, the tools, and capability to brand and design must be easy, useful and not full of developer jargon and fluff.

One of the common patterns graphical designers and web developers are using to build great web sites is a Cascading style system known as the 960 Grid system. The 960 Grid system is simply a set of CSS classes defined in such a way to turn the design of your pages into a 960 pixel grid of columns. This fake grid, allows you to position elements, blocks, and sections of the web page into nicely even sections on the page. You can read more about the 960 grid here and here.

Bringing the 960 Grid into the SharePoint 2010 system is easy, getting it to play nicely with SharePoint, well that’s another story.

The first thing you need to do is register the 2 major css files into your master page. The first css, is a “Reset.css” style sheet. This style sheet contains some classes that resets and clears out margins  on the page so that if there are any inconsistencies between browsers it starts everyone off with a clean slate or “grid” I should say.

The next style sheet is the main style sheet that creates the fake grid. With the 960 Grid system you can choose  many column formulas to design your page. the defaults are 12, 16, and 24. However there are tools that allow you to define you own grid system with differing columns widths, you choose. The Main style sheet contains classes like “grid_1”, “push_1”, “suffix_2”, “pull_1”, “prefix_1”, “alpha” and “omega”. These css classes tell the element in question where to position itself in a container horizontally speaking. These classes do not affect the vertical aspect of positioning. You’ll have to calculate that you self, however as far as horizontal, you can’t ask for a easier system to use.

The catch to using these classes with SharePoint requires knowing a few things:

1. Understanding the 960 Grid System. I suggest you step through the tutorials to get a good feel of how the 960 grid works.

2. Remove or Override any SharePoint CSS Classes that affect positioning from a horizontal perspective. This  may mean overriding the default styles in some cases, and actually removing the absolute horizontal positioning values.

To get started I suggest using Randy Drisgill’s starter Master Page, or Microsoft’s starter Master Page to apply your first branding project with SharePoint 2010. Once you have a clean working  starter master page, remove all the style sheets and default classes  that control positioning. Download or generate the 960 css files and place them in a SharePoint style library

Next add in the the 960 CSS files inside your master page right before any <script> tags inside your <head> tag;

   1: <SharePoint:CssRegistration ID="CssRegistrationReset" name="<% $SPUrl:~sitecollection/Style Library/css/reset.css %>" runat="server"/>

   2: <SharePoint:CssRegistration ID="CssRegistrationText" name="<% $SPUrl:~sitecollection/Style Library/css/text.css %>" after="<% $SPUrl:~sitecollection/Style Library/css/reset.css %>" runat="server"/>

   3: <SharePoint:CssRegistration ID="CssRegistration960" name="<% $SPUrl:~sitecollection/Style Library/css/960.css %>" after="<% $SPUrl:~sitecollection/Style Library/css/text.css %>" runat="server"/>

 

The above lines will include the CSS StyleSheets for resetting the margins, and creating the fake 960 pixel grid for styling the page. After this I usually comment out any styles that set the width to 100%, such as this one:

   1: <style type="text/css">

   2:     /* fix scrolling on list pages */

   3:     #s4-bodyContainer {

   4:         position: relative;

   5:     }

   6:  

   7:     /* hide body scrolling (SharePoint will handle) */

   8:     body {

   9:         height:100%;

  10:         overflow: scroll;

  11:         /* comment out width because we're using 960px instead */

  12:         /*width:100%;*/

  13:     }

  14:     </style>

 

Next wrap your body content into a single “<div>” element which uses the 960 Grid container. You’ll have to choose which column grid format you want to use for my example I’ll use the 16 Column format.

   1: <!-- this control is more navigation for mysites, otherwise it is empty -->

   2: <SharePoint:DelegateControl runat="server" ControlId="GlobalNavigation"/>

   3:  

   4: <!-- this is the main 16 grid container for the 960Grid system -->

   5: <div id="container_16" class="container_16" >

 

Once I have the container, I can now start designing, and placing the necessary SharePoint tags specifically where I want them. Here’s an example of how I want the SharePoint RIbbon structured:

   1: <!-- =====  Begin Ribbon ============================================================ -->

   2: <div id="ribbonWelcomeArea_16" class="grid_16 welcomeMessageColor" >

   3:     <div id="ribbonrow" class="s4-ribbonrowColor">

   4:     <div id="ribboncont" class="s4-ribboncontColor ">

   5:     

   6:         <!-- ribbon starts here -->

   7:         <SharePoint:SPRibbon

   8:             runat="server"

   9:             PlaceholderElementId="RibbonContainer"

  10:             CssFile="">

  11:         

  12:             <!-- ribbon left side content starts here -->

  13:             <SharePoint:SPRibbonPeripheralContent

  14:                 runat="server"

  15:                 Location="TabRowLeft"

  16:                 CssClass="ms-siteactionscontainer s4-notdlg">

  17:                     

  18:                     <!-- site actions -->

  19:                     <span class="ms-siteactionsmenu " id="siteactiontd">

  20:                     <SharePoint:SiteActions runat="server" accesskey="<%$Resources:wss,tb_SiteActions_AK%>" id="SiteActionsMenuMain"

  21:                         PrefixHtml=""

  22:                         SuffixHtml=""

  23:                         MenuNotVisibleHtml="&amp;nbsp;"

  24:                         >

  25:                         <CustomTemplate>

  26:                         <SharePoint:FeatureMenuTemplate runat="server"

  27:                             FeatureScope="Site"

  28:                             Location="Microsoft.SharePoint.StandardMenu"

  29:                             GroupId="SiteActions"

  30:                             UseShortId="true"

  31:                             >

  32:                             <SharePoint:MenuItemTemplate runat="server" id="MenuItem_EditPage"

  33:                                 Text="<%$Resources:wss,siteactions_editpage%>"

  34:                                 Description="<%$Resources:wss,siteactions_editpagedescriptionv4%>"

  35:                                 ImageUrl="/_layouts/images/ActionsEditPage.png"

  36:                                 MenuGroupId="100"

  37:                                 Sequence="110"

  38:                                 ClientOnClickNavigateUrl="javascript:ChangeLayoutMode(false);"

  39:                                 />

  40:                             <SharePoint:MenuItemTemplate runat="server" id="MenuItem_TakeOffline"

  41:                                 Text="<%$Resources:wss,siteactions_takeoffline%>"

  42:                                 Description="<%$Resources:wss,siteactions_takeofflinedescription%>"

  43:                                 ImageUrl="/_layouts/images/connecttospworkspace32.png"

  44:                                 MenuGroupId="100"

  45:                                 Sequence="120"

  46:                                 />

  47:                             <SharePoint:MenuItemTemplate runat="server" id="MenuItem_CreatePage"

  48:                                 Text="<%$Resources:wss,siteactions_createpage%>"

  49:                                 Description="<%$Resources:wss,siteactions_createpagedesc%>"

  50:                                 ImageUrl="/_layouts/images/NewContentPageHH.png"

  51:                                 MenuGroupId="200"

  52:                                 Sequence="210"

  53:                                 UseShortId="true"

  54:                                 ClientOnClickScriptContainingPrefixedUrl="if (LaunchCreateHandler('Page')) { OpenCreateWebPageDialog('~site/_layouts/createwebpage.aspx') }"

  55:                                 PermissionsString="AddListItems, EditListItems"

  56:                                 PermissionMode="All" />

  57:                             <SharePoint:MenuItemTemplate runat="server" id="MenuItem_CreateDocLib"

  58:                                 Text="<%$Resources:wss,siteactions_createdoclib%>"

  59:                                 Description="<%$Resources:wss,siteactions_createdoclibdesc%>"

  60:                                 ImageUrl="/_layouts/images/NewDocLibHH.png"

  61:                                 MenuGroupId="200"

  62:                                 Sequence="220"

  63:                                 UseShortId="true"

  64:                                 ClientOnClickScriptContainingPrefixedUrl="if (LaunchCreateHandler('DocLib')) { GoToPage('~site/_layouts/new.aspx?FeatureId={00bfea71-e717-4e80-aa17-d0c71b360101}&amp;ListTemplate=101') }"

  65:                                 PermissionsString="ManageLists"

  66:                                 PermissionMode="Any"

  67:                                 VisibilityFeatureId="00BFEA71-E717-4E80-AA17-D0C71B360101" />

  68:                             <SharePoint:MenuItemTemplate runat="server" id="MenuItem_CreateSite"

  69:                                 Text="<%$Resources:wss,siteactions_createsite%>"

  70:                                 Description="<%$Resources:wss,siteactions_createsitedesc%>"

  71:                                 ImageUrl="/_layouts/images/newweb32.png"

  72:                                 MenuGroupId="200"

  73:                                 Sequence="230"

  74:                                 UseShortId="true"

  75:                                 ClientOnClickScriptContainingPrefixedUrl="if (LaunchCreateHandler('Site')) { STSNavigate('~site/_layouts/newsbweb.aspx') }"

  76:                                 PermissionsString="ManageSubwebs,ViewFormPages"

  77:                                 PermissionMode="All" />

  78:                             <SharePoint:MenuItemTemplate runat="server" id="MenuItem_Create"

  79:                                 Text="<%$Resources:wss,siteactions_create%>"

  80:                                 Description="<%$Resources:wss,siteactions_createdesc%>"

  81:                                 MenuGroupId="200"

  82:                                 Sequence="240"

  83:                                 UseShortId="true"

  84:                                 ClientOnClickScriptContainingPrefixedUrl="if (LaunchCreateHandler('All')) { STSNavigate('~site/_layouts/create.aspx') }"

  85:                                 PermissionsString="ManageLists, ManageSubwebs"

  86:                                 PermissionMode="Any" />

  87:                             <SharePoint:MenuItemTemplate runat="server" id="MenuItem_ViewAllSiteContents"

  88:                                 Text="<%$Resources:wss,quiklnch_allcontent%>"

  89:                                 Description="<%$Resources:wss,siteactions_allcontentdescription%>"

  90:                                 ImageUrl="/_layouts/images/allcontent32.png"

  91:                                 MenuGroupId="300"

  92:                                 Sequence="302"

  93:                                 UseShortId="true"

  94:                                 ClientOnClickNavigateUrl="~site/_layouts/viewlsts.aspx"

  95:                                 PermissionsString="ViewFormPages"

  96:                                 PermissionMode="Any" />

  97:                              <SharePoint:MenuItemTemplate runat="server" id="MenuItem_EditSite"

  98:                                 Text="<%$Resources:wss,siteactions_editsite%>"

  99:                                 Description="<%$Resources:wss,siteactions_editsitedescription%>"

 100:                                 ImageUrl="/_layouts/images/SharePointDesigner32.png"

 101:                                 MenuGroupId="300"

 102:                                 Sequence="304"

 103:                                 UseShortId="true"

 104:                                 ClientOnClickScriptContainingPrefixedUrl="EditInSPD('~site/',true);"

 105:                                 PermissionsString="AddAndCustomizePages"

 106:                                 PermissionMode="Any"

 107:                             />                            

 108:                             <SharePoint:MenuItemTemplate runat="server" id="MenuItem_SitePermissions"

 109:                                 Text="<%$Resources:wss,people_sitepermissions%>"

 110:                                 Description="<%$Resources:wss,siteactions_sitepermissiondescriptionv4%>"

 111:                                 ImageUrl="/_layouts/images/Permissions32.png"

 112:                                 MenuGroupId="300"

 113:                                 Sequence="310"

 114:                                 UseShortId="true"

 115:                                 ClientOnClickNavigateUrl="~site/_layouts/user.aspx"

 116:                                 PermissionsString="EnumeratePermissions"

 117:                                 PermissionMode="Any" />

 118:                             <SharePoint:MenuItemTemplate runat="server" id="MenuItem_Settings"

 119:                                 Text="<%$Resources:wss,settings_pagetitle%>"

 120:                                 Description="<%$Resources:wss,siteactions_sitesettingsdescriptionv4%>"

 121:                                 ImageUrl="/_layouts/images/settingsIcon.png"

 122:                                 MenuGroupId="300"

 123:                                 Sequence="320"

 124:                                 UseShortId="true"

 125:                                 ClientOnClickNavigateUrl="~site/_layouts/settings.aspx"

 126:                                 PermissionsString="EnumeratePermissions,ManageWeb,ManageSubwebs,AddAndCustomizePages,ApplyThemeAndBorder,ManageAlerts,ManageLists,ViewUsageData"

 127:                                 PermissionMode="Any" />

 128:                             <SharePoint:MenuItemTemplate runat="server" id="MenuItem_CommitNewUI"

 129:                                 Text="<%$Resources:wss,siteactions_commitnewui%>"

 130:                                 Description="<%$Resources:wss,siteactions_commitnewuidescription%>"

 131:                                 ImageUrl="/_layouts/images/visualupgradehh.png"

 132:                                 MenuGroupId="300"

 133:                                 Sequence="330"

 134:                                 UseShortId="true"

 135:                                 ClientOnClickScriptContainingPrefixedUrl="GoToPage('~site/_layouts/prjsetng.aspx')"

 136:                                 PermissionsString="ManageWeb"

 137:                                 PermissionMode="Any"

 138:                                 ShowOnlyIfUIVersionConfigurationEnabled="true" />

 139:                         </SharePoint:FeatureMenuTemplate>

 140:                         </CustomTemplate>

 141:                       </SharePoint:SiteActions></span>

 142:             

 143:               <!-- global navigation dhtml popout menu -->

 144:               <asp:ContentPlaceHolder id="PlaceHolderGlobalNavigation" runat="server">

 145:                     <SharePoint:PopoutMenu

 146:                         runat="server"

 147:                         ID="GlobalBreadCrumbNavPopout"

 148:                         IconUrl="/_layouts/images/fgimg.png"

 149:                         IconAlt="<%$Resources:wss,master_breadcrumbIconAlt%>"

 150:                         IconOffsetX=0

 151:                         IconOffsetY=112

 152:                         IconWidth=16

 153:                         IconHeight=16

 154:                         AnchorCss="s4-breadcrumb-anchor"

 155:                         AnchorOpenCss="s4-breadcrumb-anchor-open"

 156:                         MenuCss="s4-breadcrumb-menu">

 157:                         <div class="s4-breadcrumb-top">

 158:                             <asp:Label runat="server" CssClass="s4-breadcrumb-header" Text="<%$Resources:wss,master_breadcrumbHeader%>" />

 159:                         </div>

 160:                         <asp:ContentPlaceHolder id="PlaceHolderTitleBreadcrumb" runat="server">

 161:                             <SharePoint:ListSiteMapPath

 162:                                 runat="server"

 163:                                 SiteMapProviders="SPSiteMapProvider,SPContentMapProvider"

 164:                                 RenderCurrentNodeAsLink="false"

 165:                                 PathSeparator=""

 166:                                 CssClass="s4-breadcrumb"

 167:                                 NodeStyle-CssClass="s4-breadcrumbNode"

 168:                                 CurrentNodeStyle-CssClass="s4-breadcrumbCurrentNode"

 169:                                 RootNodeStyle-CssClass="s4-breadcrumbRootNode"

 170:                                 NodeImageOffsetX=0

 171:                                 NodeImageOffsetY=353

 172:                                 NodeImageWidth=16

 173:                                 NodeImageHeight=16

 174:                                 NodeImageUrl="/_layouts/images/fgimg.png"

 175:                                 RTLNodeImageOffsetX=0

 176:                                 RTLNodeImageOffsetY=376

 177:                                 RTLNodeImageWidth=16

 178:                                 RTLNodeImageHeight=16

 179:                                 RTLNodeImageUrl="/_layouts/images/fgimg.png"

 180:                                 HideInteriorRootNodes="true"

 181:                                 SkipLinkText="" />

 182:                         </asp:ContentPlaceHolder>

 183:                     </SharePoint:PopoutMenu>

 184:                 </asp:ContentPlaceHolder>

 185:                 

 186:             <!-- save button at top of ribbon -->

 187:             <SharePoint:PageStateActionButton id="PageStateActionButton" runat="server" Visible="false" /></SharePoint:SPRibbonPeripheralContent>

 188:             

 189:             <!-- ribbon right side content starts here -->

 190:             <SharePoint:SPRibbonPeripheralContent

 191:                 runat="server"

 192:                 Location="TabRowRight"

 193:                 ID="RibbonTabRowRight"

 194:                 CssClass="s4-trc-container s4-notdlg">

 195:                 

 196:                 <!-- GlobalSiteLink0 delegate - the variation selector / shows nothing by default otherwise -->

 197:                 <SharePoint:DelegateControl runat="server" ID="GlobalDelegate0" ControlId="GlobalSiteLink0" />

 198:  

 199:                 <!-- GlobalSiteLink2 delegate default shows nothing -->

 200:                 <SharePoint:DelegateControl ControlId="GlobalSiteLink2" ID="GlobalDelegate2" Scope="Farm" runat="server" />

 201:                 

 202:                 <!-- link to launch developer dashboard if its activated by admin -->

 203:                 <span>

 204:                     <span class="s4-devdashboard">

 205:                     <Sharepoint:DeveloperDashboardLauncher

 206:                         ID="DeveloperDashboardLauncher"

 207:                         NavigateUrl="javascript:ToggleDeveloperDashboard()"

 208:                         runat="server"

 209:                         ImageUrl="/_layouts/images/fgimg.png"

 210:                         Text="<%$Resources:wss,multipages_launchdevdashalt_text%>"

 211:                         OffsetX=0

 212:                         OffsetY=222

 213:                         Height=16

 214:                         Width=16 />

 215:                     </span>

 216:                 </span>

 217:             </SharePoint:SPRibbonPeripheralContent>

 218:       </SharePoint:SPRibbon>

 219:       

 220:       <!-- end main ribbon control -->

 221:     </div>

 222:     <!-- dynamic notification area -->

 223:     <div id="notificationArea" class="s4-noti"></div>

 224:  

 225:     <!-- old navigation delegate? -->

 226:     <asp:ContentPlaceHolder ID="SPNavigation" runat="server">

 227:             <SharePoint:DelegateControl runat="server" ControlId="PublishingConsole" Id="PublishingConsoleDelegate">

 228:            </SharePoint:DelegateControl>

 229:     </asp:ContentPlaceHolder>

 230:     

 231:     <!-- top web part panel -->

 232:     <div id="WebPartAdderUpdatePanelContainer" class="grid_16 webPartAdderUpdatePanelContainerColor hide " >

 233:         <asp:UpdatePanel

 234:             ID="WebPartAdderUpdatePanel"

 235:             UpdateMode="Conditional"

 236:             ChildrenAsTriggers="false"

 237:             runat="server">

 238:             <ContentTemplate>

 239:                 <WebPartPages:WebPartAdder ID="WebPartAdder" runat="server" />

 240:             </ContentTemplate>

 241:             <Triggers>

 242:                 <asp:PostBackTrigger ControlID="WebPartAdder" />

 243:             </Triggers>

 244:         </asp:UpdatePanel>

 245:     </div>

 246: </div>

 247: <!-- =====  End Ribbon and other Top Content ============================================================ -->

Here’s an example of what the page looks like with the ribbon and a background image.

image

Once you get comfortable with the 960 grid system, you can place SharePoint tags and elements almost anywhere.

There are some challenges with using the 960 grid system.

1. When working with page layouts, if you’re not cognizant of the fact that your master page is using the 960 grid your layout will yield nasty vertical and horizontal scroll bars.

2. When editing the page, if you place the web part adder and it’s corresponding controls in their normal positions, the runtime web part design experience becomes non-existent. Basically it becomes practically   impossible to add, edit and remove web parts because their may not be any scroll bars and the design time controls flow off the page.

3. Attempting to do this for the System Master pages is also impossible for the same reasons mentioned above, and the mere fact that system pages were designed to use the whole width of the page {width: 100%}. Leaving anything off would severely hinder system admin functionality.

In my next post I’ll talk about ways around the first two issues. As far as the third challenge, if you find a elegant way to get around this let me know, but for right now I lean towards the philosophy that System administration pages are not “public” and should not be in a 960 Grid format anyway.

Until next time… Happy web surfing!

 
Leave a comment

Posted by on 2011/07/07 in Uncategorized

 

Tellago Studios Announces TeleSharp…

That’s Right Folks!!! We have done it again. We at Tellago have created another solution for your configuration challenges in the .Net World. If you need a central repository to store .Net Enterprise application assets, this is what you’ve been looking for.

You can check out our product, and more information here:

http://tellagostudios.com/products/telesharp%E2%84%A2

 
Leave a comment

Posted by on 2011/07/01 in Uncategorized

 

Changing the Gnome 3 Desktop with Images from Bing

This weekend I decided to take on a little challenge…

Question: What’s the Challenge?

Answer: Have any of you on Windows 7 or WIndows 2008 R2 noticed that there’s a background theme configuration selection that allows you to see a collection of Bing images? If so you probably already know that these images are downloaded from a Bing RSS feed and every minute of so and displays as the current wallpaper.

Well I wanted to see if I could get the same effect of building such a quick app for my Gnome3 desktops I run. It turns out that there are many ways to accomplish this. I could have written an Python script, Perl Script, Bash Script, C++ application, or just downloaded one of the few wallpaper changer Linux applications such as Webilder.

So, I decided to put on my developer hat and write one using one of the most difficult languages for a Microsoft raised and branded developer, Bash Script. The first thing I needed to do was determine, if it was indeed possible to do this. I binged around and found this: “Customizing the GNOME Shell”. by fpmurphy. I must say the read was thorough and complete enough for me to figure out all I needed was one line of code to change the desktop settings:

   1:  

   2: gsettings set org.gnome.desktop.background picture-uri “file:///home/dngoins/WALLPAPER/bingImage.jpg”

Basically now all I needed to do was to get this “BingImage.jpg”. Well this was rather simple as well. All I needed to do was figure out what and where the Bing RSS Feed uri is, then parse the RSS Feed to get the image url’s and simply download them every few minutes or so.

Question: How did you determine the Bing RSS Feed Url?

Answer: I used a little tool called Fiddler2. Well some of you know I’m a .Net Developer by trade and skill set, but a Linux developer by night, so I use tools from every platform to get a job done, and for my purpose of sniffing out the BIng RSS feed Url, this worked. I started up an instance of my Windows 2008 R2 vmware image, and I started Fiddler2. I then changed my background to use the Bing RSS feed wallpapers and I noticed this url:

http://themeserver.microsoft.com/default.aspx?p=Bing&c=Desktop&m=en-US

This Url yields the Bing RSS Feed which contain links to the Bing Images. I also noticed that this list does not contain the  “Today” image on the bing search site. The Current Bing image for “Today” can be found here:

http://www.bing.com/HPImageArchive.aspx?format=xml&idx=0&n=1

Question: After this what did you do?

Answer:  I parsed the RSS Feeds for the themes, and current today images, and simply downloaded and overwrote the “BingImage.jpg” file. You can see the BASH script here:

   1: #!/bin/bash

   2:  

   3: #Read more: http://blog.fpmurphy.com/2011/03/customizing-the-gnome-3-shell.html#ixzz1QdBESiym

   4:  

   5:  

   6: #change this to your user location

   7: cd /home/dngoins/WALLPAPER

   8:  

   9: #change this to set the time between background downloads in seconds

  10: changeBackgroundTime=300

  11:  

  12: #while [! ifconfig eth0 | grep "inet addr"] &;& [! ifconfig wlan0 | grep "init addr"  ] ; do

  13: #    sleep 1

  14: #done

  15:  

  16: #wait for the network to start...

  17: sleep 15

  18:  

  19:  

  20: #get the current Bing image on the search window

  21: #the current Search Bing Image can be found at HPImageArchive.aspx

  22: #extract the <;url/> content for the image link

  23: currentBingImage=$(curl "http://www.bing.com/HPImageArchive.aspx?format=xml&idx=0&n=1" |grep "<url>.*<.url>" |sed -e "s/^.*<url/<url/" | cut -f2 -d">"| cut -f1 -d"<")

  24:  

  25: #extract the <;copyright> information for the description of the current bing search image

  26: currentCopyright=$(curl "http://www.bing.com/HPImageArchive.aspx?format=xml&idx=0&n=1" |grep "<copyright>.*<.copyright>" |sed -e "s/^.*<copyright/<copyright/" | cut -f2 -d">"|cut -f1 -d"<")

  27:  

  28: #the InfoAboutBackground needs to have permissions so that this script can overwrite the contents

  29: echo $currentBingImage": "$currentCopyright >; /home/dngoins/Desktop/InfoAboutBackground

  30: #echo $currentBingImage

  31:  

  32: #set the whole currentImage path

  33: bingUrl="http://www.bing.com"

  34: currentImage=${bingUrl}${currentBingImage}

  35:  

  36: #download the current bing image and overwrite the bingImage.jpg file

  37: curl $currentImage -o bingImage.jpg

  38:  

  39: #use the gnome 3 settings utility: gsettings to change the background

  40: gsettings set org.gnome.desktop.background picture-uri "file:///home/dngoins/WALLPAPER/bingImage.jpg"

  41:  

  42: #get the rssFeed <;link ref="http://blah.com/image.jpg" /> link

  43: rssFeed=$(curl "http://themeserver.microsoft.com/default.aspx?p=Bing&c=Desktop&m=en-US"  |grep -o '<;link ref="[^"]*' | grep -o '[^"]*$' |sed -e "s/http:\/\/.*\.jpg/<url>&<\/url>,/" |sed -e "s/http:\/\/.*\.JPG/<url>&<\/url>,/" )

  44:  

  45: rssFeedParamountPictures=$(curl "http://themeserver.microsoft.com/default.aspx?p=Paramount&c=Dynamic&m=en-US"  |grep -o '<;link ref="[^"]*' | grep -o '[^"]*$' |sed -e "s/http:\/\/.*\.jpg/<url>&<\/url>,/" |sed -e "s/http:\/\/.*\.JPG/<url>&<\/url>,/" )

  46:  

  47: rssFeedAerial=$(curl "http://themeserver.microsoft.com/default.aspx?p=Bing&c=Aerial&m=en-US"  |grep -o '<;link ref="[^"]*' | grep -o '[^"]*$' |sed -e "s/http:\/\/.*\.jpg/<url>&<\/url>,/" |sed -e "s/http:\/\/.*\.JPG/<url>&<\/url>,/" )

  48:  

  49: #TODO: get the rssFeed desciption for each url - 

  50: #rssFeedAbout=$(curl "http://themeserver.microsoft.com/default.aspx?p=Bing&c=Desktop&m=en-US" |grep "<title>.*<.title>" |sed -e "s/<title>.*<.title>/&,/" )

  51:  

  52:  

  53: #remove all the spaces for the time being and replace with '~'

  54: removespaces=$(echo $rssFeed | tr ' ' '~')

  55: removespacesParamount=$(echo $rssFeedParamountPictures | tr ' ' '~')

  56: removespacesAerial=$(echo $rssFeedAerial | tr ' ' '~')

  57:  

  58: #create an array of <;url/>'s

  59: declare -a urlArray

  60: urlArray=(`echo $removespaces | tr ',' ' '`)

  61:  

  62: declare -a urlArrayParamount

  63: urlArrayParamount=(`echo $removespacesParamount | tr ',' ' '`)

  64:  

  65: declare -a urlArrayAerial

  66: urlArrayAerial=(`echo $removespacesAerial | tr ',' ' '`)

  67:  

  68:  

  69: #for each url in the array

  70: for url in ${urlArray[@]}; do

  71:  

  72:  

  73: #replace the '~' with url encoded %20 for spaces, and return just the actual url link: http://blah.com/image.jpg

  74: image=$(echo $url |grep "<url>.*<.url>" |sed -e "s/^.*<url/<url/" | cut -f2 -d">"| cut -f1 -d"<" | sed -e "s/~/%20/" | sed -e "s/~/%20/" )

  75:  

  76: #echo "Image: $image"

  77: #get the filename

  78: fileName=$(echo $image |sed -e "s/http:\/\/themeserver.microsoft.com\/themeserver\/\/Bing\/Desktop\/en-US\/Images\///" | tr '/' '_')

  79:  

  80: #echo "FileName = $fileName"

  81:  

  82: if [ -a /home/dngoins/WALLPAPER/$fileName ]; then

  83:  

  84:     echo "$fileName already found in directory, so skipping download"

  85: else

  86:     #download the image and save it to the WALLPAPER directory as [name of file].jpg

  87:     #for this to work you need to give permission to overwrite this file in the /home/user/WALLPAPER directory

  88:     curl `echo $image` -o $fileName

  89: #    echo "Doing Curl for $image and $fileName"

  90:  

  91: fi

  92:  

  93: #use the gnome 3 shell settings utility: gsettings to set the background image

  94: #gsettings set org.gnome.desktop.background picture-uri "file:///home/dngoins/WALLPAPER/"$fileName

  95:  

  96: #loop over and download the next image in Bing RSS Theme

  97: done

  98:  

  99: #wait for the allocated time to change to the Bing RSS Theme images

 100: sleep $changeBackgroundTime

 101:  

 102: length=$#

 103: random_num=$(( $RANDOM % ($length + 1) ))

 104:  

 105: if [ -a "/home/dngoins/WALLPAPER/${!random_num}" ] &;& [ "${!random_num}" != "currentWallpaper.jpg" ]; then 

 106:     cp "/home/dngoins/WALLPAPER/${!random_num}" ./currentWallpaper.jpg 

 107:     gsettings set org.gnome.desktop.background picture-uri "file:///home/dngoins/WALLPAPER/currentWallpaper.jpg"

 108: fi

 109:  

 110:  

 111: #for each url in the array

 112: for url in ${urlArrayParamount[@]}; do

 113:  

 114:  

 115: #replace the '~' with url encoded %20 for spaces, and return just the actual url link: http://blah.com/image.jpg

 116: image=$(echo $url |grep "<url>.*<.url>" |sed -e "s/^.*<url/<url/" | cut -f2 -d">"| cut -f1 -d"<" | sed -e "s/~/%20/" | sed -e "s/~/%20/" )

 117:  

 118: #echo "Image: $image"

 119: #get the filename

 120: fileName=$(echo $image |sed -e "s/http:\/\/themeserver.microsoft.com\/themeserver\/\/Paramount\/Dynamic\/en-US\/Images\///" | tr '/' '_')

 121:  

 122: #echo "FileName = $fileName"

 123:  

 124: if [ -a /home/dngoins/WALLPAPER/$fileName ]; then

 125:  

 126:     echo "$fileName already found in directory, so skipping download"

 127: else

 128:     #download the image and save it to the WALLPAPER directory as [name of file].jpg

 129:     #for this to work you need to give permission to overwrite this file in the /home/user/WALLPAPER directory

 130:     curl `echo $image` -o $fileName

 131: #    echo "Doing Curl for $image and $fileName"

 132:  

 133: fi

 134:  

 135: #use the gnome 3 shell settings utility: gsettings to set the background image

 136: #gsettings set org.gnome.desktop.background picture-uri "file:///home/dngoins/WALLPAPER/"$fileName

 137:  

 138: #loop over and download the next image in Bing RSS Theme

 139: done

 140:  

 141:  

 142: #wait for the allocated time to change to the Bing RSS Theme images

 143: sleep $changeBackgroundTime

 144:  

 145: length=$#

 146: random_num=$(( $RANDOM % ($length + 1) ))

 147:  

 148: if [ -a "/home/dngoins/WALLPAPER/${!random_num}" ] &;& [ "${!random_num}" != "currentWallpaper.jpg" ]; then 

 149:     cp "/home/dngoins/WALLPAPER/${!random_num}" ./currentWallpaper.jpg 

 150:     gsettings set org.gnome.desktop.background picture-uri "file:///home/dngoins/WALLPAPER/currentWallpaper.jpg"

 151: fi

 152:  

 153:  

 154: #for each url in the array

 155: for url in ${urlArrayAerial[@]}; do

 156:  

 157:  

 158: #replace the '~' with url encoded %20 for spaces, and return just the actual url link: http://blah.com/image.jpg

 159: image=$(echo $url |grep "<url>.*<.url>" |sed -e "s/^.*<url/<url/" | cut -f2 -d">"| cut -f1 -d"<" | sed -e "s/~/%20/" | sed -e "s/~/%20/" )

 160:  

 161: #echo "Image: $image"

 162: #get the filename

 163: fileName=$(echo $image |sed -e "s/http:\/\/themeserver.microsoft.com\/themeserver\/\/Bing\/Aerial\/en-US\/Images\///" | tr '/' '_')

 164:  

 165: #echo "FileName = $fileName"

 166:  

 167: if [ -a /home/dngoins/WALLPAPER/$fileName ]; then

 168:  

 169:     echo "$fileName already found in directory, so skipping download"

 170: else

 171:     #download the image and save it to the WALLPAPER directory as [name of file].jpg

 172:     #for this to work you need to give permission to overwrite this file in the /home/user/WALLPAPER directory

 173:     curl `echo $image` -o $fileName

 174: #    echo "Doing Curl for $image and $fileName"

 175:  

 176: fi

 177:  

 178: #use the gnome 3 shell settings utility: gsettings to set the background image

 179: #gsettings set org.gnome.desktop.background picture-uri "file:///home/dngoins/WALLPAPER/"$fileName

 180:  

 181: #loop over and download the next image in Bing RSS Theme

 182: done

 183:  

 184:  

 185:  

 186: #all images downloaded so now loop through images

 187: while [ 1 ]

 188: do

 189: set — *

 190: length=$#

 191:  

 192: random_num=$(( $RANDOM % ($length + 1) ))

 193:  

 194: #echo "file:///home/dngoins/WALLPAPER/${!random_num}"

 195: if [ -a "/home/dngoins/WALLPAPER/${!random_num}" ] &;& [ "${!random_num}" != "currentWallpaper.jpg" ]; then 

 196:     cp "/home/dngoins/WALLPAPER/${!random_num}" ./currentWallpaper.jpg 

 197:     gsettings set org.gnome.desktop.background picture-uri "file:///home/dngoins/WALLPAPER/currentWallpaper.jpg"

 198: fi

 199:  

 200: sleep $changeBackgroundTime

 201:  

 202: done

 203:  

 204: exit

Results:

BingRssGnomeWallpaper

Notice in the image above I have the WIndows Server 2008 R2 image with Bing as the wallpaper, along with the Gnome 3 desktop wallpaper on the Linux host.

 
Leave a comment

Posted by on 2011/06/27 in Uncategorized

 

Tellago Announces Technology Updates Webinar

If you’re intimately involved with computers, and you probably are because you’re reading this… you probably think you know your stuff!!!

After all you’ve been working with various systems for X amount of years and you have probably been burned to the cross, as well as been  raised up to the status of  “god-ship” in your career. The problem is, everytime you look around your shoulder there’s a new technology on the uprising which you haven’t heard about, nor know anything about. Then after a quick blog article, or magazine read, you say to yourself… “Oh that’s just this old technology revamped… I get it!!!”

We at Tellago would like to introduce to you a “virtual video blog” or virtual video magazine…! We  have many developers with a wide variety of skills sets on many platforms: Windows, Mac, Linux, you name it. We want to share these technology updates with you through webinars where you can stay up to date on the latest technology buzzes dealing with the 3 most popular platforms.

These webinar series will be a version of what we are doing with the Technology Meetups and Dojos but this time targeting customers, IT executives, etc. Our first two webinars are going to focus on NOSQL databases and Mobile applications. You can find the Technology Updates series at http://tellago.com/what_we_says/tellago-technology-updates

Read more about it here http://weblogs.asp.net/gsusx/archive/2011/05/04/announcing-tellago-technology-updates.aspx .

We hope to see you and hear your opinion on this . Thanks

 
Leave a comment

Posted by on 2011/05/05 in Uncategorized

 
 
Follow

Get every new post delivered to your Inbox.