Consulting 101: 25 Pro Tips

Pre Engagement

Consulting 101 Research

  1. Go beyond the project

    Research about your immediate project but don’t stop there.
    Understand your client’s overall business, their finances, their top services/products, and their top competitors.
    If your consulting firm has worked with them earlier, read up on previous engagements and reach out to those team members – that’s a gold mine of pro-tips tailored to your client.

  2. Be Google-able

    Not everyone at the client will have access to your resume or know exactly what qualifies you as the “expert” in the room.
    Having an online presence, such as on LinkedIn or a professional blog, that propagates your experiences and credentials will establish your credibility.

  3. Know the Who’s Who

    Get acquainted with your client’s organizational structure, names, and faces. Walk the halls. Most companies have their top management listed on their websites.
    This squad calls the shots and you want to know who they are. It will help manage client relationships later on.

During Engagement

  1. Have an Elevator Pitch
    Consulting 101 - Office Space - What Would you Say You Do Here?

    You’ll bump into two kinds of people in a client elevator.
    The ones who know you and wonder, “So what are you working on today? ” and the ones who don’t know you and wonder, “So what do you do here? ” Have a 30 second pitch that warrants your presence with the value that your work is adding to their business.

  2. Holster Business Cards

    Despite all the LinkedIns and contact sharing bump apps out there, nothing beats the tangibility and effortlessness of a business card.
    Don’t be the “lemme take my phone out and give you a missed call ” consultant, especially if you are in a group setting.

  3. Dress the part

    Consultants are an expensive investment by the client, so look worthy of that hourly rate. Dressing well is the most noticeable thing about you. Dress at or above client’s dress-code. But don’t overkill it.

  4. Blend in but don’t make yourself at home

    You are a consultant, not an employee. You will be held to a higher standard. Keep your desk clean and don’t use client’s time and resource for personal activities.

  5. Be ridiculously easy to find.

    Reply to your emails and phone-calls within 1 business day. Get your presence noticed and be in attendance when expected (e.g during core business hours.) Keep your individual/team calender application updated. Do use the “Out-of-Office” auto-reply feature.

Client Meetings

Consulting 101 IT Crowd Meetings

  1. Keep it lean

    Only invite people to meetings or email threads who are absolutely necessary. Keep it concise. Ideal meeting length is <= 45-minutes.

  2. Never go to a meeting empty-handed.

    At a minimum, bring a pen and paper

  3. Learn to summarize

    Every conversation, meeting, and email chain HAS to be “closed” with a summary. Save the unnecessary re-loops.

  4. Lose the battle, win the war

    You are not here to win trivial arguments or fortify your ego. You’re here to conclude the project successfully. With this objectivity, recognize when to stand-your-ground and when to retreat.

  5. It’s not “I don’t know,” it’s “I’ll find out”
  6. Under promise and over deliver. Always.
  7. Get it written

    Any piece of information that has the slightest potential of being referenced at some point in future needs to be documented TODAY. If it’s not written, it never happened.

  8. 1 Meeting in person > 10 Phone calls > 100 Emails

    Especially during conflict resolution.

Email

Consulting 101 - Email

  1. Defer Sent Messages

    If you’re on MS Outlook, make use of the delay delivery feature. It can hold your sent emails up to 2 minutes before delivering them. In case you discovered something, you would be able to retract in time.

  2. Don’t add the recipients of your email before you have typed it all up and proofread.

    Use Spelling and Grammar Check. Never misspell names. Never mix type faces or point sizes.

  3. Compose your emails assuming they get forwarded to the CEO
  4. Use the “Reply All” and “Forward” button sparingly and carefully. See #9

Socialization

  1. Stay neutral when it comes to discussing Politics and Religion
  2. The odds of you and your team bonding over such affairs are not worth risking the engagement.

  3. Know a few good happy-hour spots in the area
    Aroragary-Consulting-101-Social

    Socialization is a vital investment. Pick up the tab sometimes. A drink or two is enough. Don’t buy shots.

Post Engagement

  1. Thank You notes

    Send out thank-you notes/farewell messages to everyone you have worked with on the project. Make peace with the ones you didn’t get along with, in person.

  2. Positive Feedback

    For every deserving member, pass on a positive feedback to their managers, in writing. #Karma

  3. Keep in touch

    Leave your contact information and keep in touch with your team. For e.g via LinkedIn. It pays dividends.

Retrieve Site Template name using CSOM or REST on SharePoint 2013 (Online/OnPrem)

In the SharePoint on-premise world with Server-Side privileges, finding trivial details like Site Template name (also referred to as Site Definition name or Web Template name) of a SiteCollection or a Subsite is fairly straightforward with following 2 options:

But having access to server-side or powershell may not always be your luxury. In cases such as having a strict governance or using SharePoint Online on O365.

And that’s when you have CSOM and REST to your rescue.

Method 1: REST

Endpoint URI structure: http://<sitecollection>/<site>/_api/web/webTemplate
For my site, it’s:
https://aroragary.sharepoint.com/sites/dev/subsite_1/_api/web/webTemplate

Executing the query gets me the following output. Your’s may look a bit ugly & unformatted and that’s because I’m using Postman

Browser Output showing Web Template name using REST

Web/Site Template name retrieved using REST

The Web/Site Template name in this example is “SRCHCEN”, which refers to Enterprise Search Center template.

PRO-TIP: Use Postman to run/test your REST queries. The output is neatly formatted (like above) and the user-interface to manipulate queries is much nicer.

Method 2: CSOM (<cough> JSOM <cough>)

Although REST gets the job done in a single line, if you’re a stickler for CSOM then here’s how you can achieve the same result:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var website;
var clientContext;

//to make sure sp.js is loaded or you’ll hit a wall of errors
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', FindMyWebTemplate);

function FindMyWebTemplate() {

    //Create Instance of current context
    clientContext = SP.ClientContext.get_current();
    website = clientContext.get_web();

    clientContext.load(website);
    clientContext.executeQueryAsync(onRequestSucceeded, onRequestFailed);
}
function onRequestSucceeded() {
    alert(website.get_webTemplate());
}
function onRequestFailed(sender, args) {
    alert('Error: ' + args.get_message());
}

This gets me the following alert notification:

Get Web/Site Template Name using CSOM on SharePoint 2013

Web/Site Template name retrived using CSOM

Both methods will yield you the shorthand web template name. You can find their full titles by using one of the following links:

Modify User Profile Properties on SharePoint Online 2013 using SPServices

The Use Case: SharePoint 2013 users need to modify (specific) user-profile-properties client-side without having to navigate away to their ‘MySite’ site and swift through rows of user properties.
(Following is an mock-up showing a simple interface to update a user profile property via CEWP)

Modify User Profile Properties on SharePoint using SPService

Simple interface to update Fax number from a CEWP. (Basic demo)

The Usual Solution: In the SharePoint 2013 universe there are 2 ways to read/write data client-side. CSOM and REST. Unfortunately CSOM and REST are not fully there yet when it comes to matching the server side functionality.

In this specific case, one could use CSOM or REST to retrieve (read) User Profile Properties but there is no way to modify (update) these properties from client-side. Here’s Microsoft’s official position.

Not all functionality that you find in the Microsoft.Office.Server.UserProfiles assembly is available from client APIs. For example, you have to use the server object model to create or change user profiles because they’re read-only from client APIs (except the user profile picture)

Hence The Dirty Workaround: So our workaround is SOAP, the forgotten granddaddy of Web services. The User Profile Service web service, from the SharePoint 2007 days, has a method called ModifyUserPropertyByAccountName which functions exactly as it sounds. But since SOAP can be a bit intimidating & ugly to write, we’ll use SPServices, “a jQuery library which abstracts SharePoint’s Web Services and makes them easier to use”

So here’s how we’ll use SPServices to modify User Profile Properties. The method is applicable to SharePoint 2013 & 2010 (online & on-prem) versions.

1. Reference SPServices library

You have two options here. You can either download the SPService library and reference it locally or reference it from its CDN:

1
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery.SPServices/2013.01/jquery.SPServices-2013.01.min.js"></script>

2. Create updateUserProfile() Function

The following function simulates the ModifyUserPropertyByAccountName method on the User Profile Service web service.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function updateUserProfile(userId, propertyName, propertyValue) {

  var propertyData = "<PropertyData>" +
  "<IsPrivacyChanged>false</IsPrivacyChanged>" +
  "<IsValueChanged>true</IsValueChanged>" +
  "<Name>" + propertyName + "</Name>" +
  "<Privacy>NotSet</Privacy>" +
  "<Values><ValueData><Value xsi:type=\"xsd:string\">" + propertyValue + "</Value></ValueData></Values>" +
  "</PropertyData>";
 
  $().SPServices({
    operation: "ModifyUserPropertyByAccountName",
    async: false,
    webURL: "/",
    accountName: userId,
    newData: propertyData,
    completefunc: function (xData, Status) {
      var result = $(xData.responseXML);
    }
  });

}

3. Invoke updateUserProfile() Function

This function takes 3 parameters.

  • userId: Your userID. The format is “domain\userId” for on-prem and “i:0#.f|membership|<federated ID>” for SharePoint Online.
  • propertyName: The user profile property that needs to be changed
  • propertyValue: The new user profile property value

Example:

1
2
3
updateUserProfile(
  "i:0#.f|membership|garya@aroragary.onmicrosoft.com",
  "Fax", "555 555 5555");

Note: The above code works but notice that you are passing a hardcoded userId.

To pass the current userId dynamically, we can use CSOM’s get_currentUser(). But since that’s based on the successful execution of ClientContext query, we need to “defer” invoking “updateUserProfile()” until we have received current userId. Therefore we’ll create a Deferred object as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function getUserLogin() {
  var userLogin = $.Deferred(function () {
    var clientContext = new SP.ClientContext.get_current();
    var user = clientContext.get_web().get_currentUser();
    clientContext.load(user);
    clientContext.executeQueryAsync(
      function () {
        userLogin.resolve(user.get_loginName());
      }
      ,
      function () {
        userLogin.reject(args.get_message());
      }
      );
  });
  return userLogin.promise();
}

Now when we invoke updateUserProfile(), it will execute getUserLogin() first, implying that the ClientContext query was successful :

1
2
3
getUserLogin().done(function (userId) {
  updateUserProfile(userId, "Fax", "555 555 5555");
});

4. Full working code

Steps to replicate the demo

  1. Copy the following code snippet and save it as a text file (.txt)
  2. Upload this text file anywhere on your SharePoint site (e.g. Site Assets). Remember its path.
  3. On the same SharePoint site, add/edit a page and insert a CEWP (Content Editor Web Part)
  4. On the web part properties of CEWP, add the path to the text file under “Content Link” section
  5. Click Ok, and save the page.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery.SPServices/2013.01/jquery.SPServices-2013.01.min.js"></script>
<script type="text/javascript">

//updateUserProfilePreFlight defers until getUserId() is "done"
//then it invokes updateUserProfile
function updateUserProfilePreFlight(){
  getUserId().done(function (userId) {
    var propertyName = "Fax"
    var propertyValue =  $("#Fax").val();
    updateUserProfile(userId, propertyName, propertyValue);
  });
}

//getUserLogin() uses CSOM to retrive current userId.
function getUserId() {
  var userLogin = $.Deferred(function () {
    var clientContext = new SP.ClientContext.get_current();
    var user = clientContext.get_web().get_currentUser();
    clientContext.load(user);
    clientContext.executeQueryAsync(
      function () {
        userLogin.resolve(user.get_loginName());
      }
      ,
      function () {
        userLogin.reject(args.get_message());
      }
      );
  });
  return userLogin.promise();
}

//updateUserProfile updates the userprofile property
function updateUserProfile(userId, propertyName, propertyValue) {

  var propertyData = "<PropertyData>" +
  "<IsPrivacyChanged>false</IsPrivacyChanged>" +
  "<IsValueChanged>true</IsValueChanged>" +
  "<Name>" + propertyName + "</Name>" +
  "<Privacy>NotSet</Privacy>" +
  "<Values><ValueData><Value xsi:type=\"xsd:string\">" + propertyValue + "</Value></ValueData></Values>" +
  "</PropertyData>";

  $().SPServices({
    operation: "ModifyUserPropertyByAccountName",
    async: false,
    webURL: "/",
    accountName: userId,
    newData: propertyData,
    completefunc: function (xData, Status) {
      var result = $(xData.responseXML);
    }
  });

}


</script>

<input id="Fax" type="text" placeholder="Update Fax" />
<input onclick="updateUserProfilePreFlight()" type="button" value="Update" />

Note

  • You can only edit the user profile properties that are editable (unlocked) on your MySite. Certain fields like department are usually locked for editing as per company policy

What is AngularJS and why is it Awesome?

Just got back from an awesome event at Microsoft Technology Center in Cambridge – The 2013 Boston Code Mastery, which is a full day of deep-dive sessions on cutting edge web technology.

I had the opportunity to speak about my experience with AngularJS – the JavaScript MVC framework by Google. Appropriately titled “What is AngularJS and Why is it awesome” with some demos sprinkled-in to showcase key features of AngularJS.

Gary Arora presenting on AngularJS at Microsoft Technology Center in Cambridge

Gary Arora presenting on AngularJS at Microsoft Technology Center in Cambridge

Since AngularJS is all Javascript, I decided to skip the PowerPoint route and run the slides on a JavaScript framework called Reveal.js. This allowed me to add interactivity and embed AngularJS demos directly on the slides.

The interactive version with AngularJS demos can be found here.

A power-point version is also available on slideshare:

Hope you find the brief information on AngularJS helpful enough to get started :)