Wednesday, December 12, 2012

SharePoint 2010 - Alternate Access Mappings, Fully Qualified Domain Names, and Access Denied Errors

Back in the good old days of SharePoint Portal Server 2003 and Microsoft Office SharePoint Server 2007, Alternate Access Mappings (AAM) were easy. All you did was add a binding to your IIS web site, add a mapping in Central Administration and you were good to go. Not so in SharePoint 2010. The new Claims Based Authentication structure changes the ballgame considerably. Now, Zones are much more important, and because everything is a claim now, the ability to change authentication methods in a different zone is much more complex. From a SharePoint Architecture point of view. From an Administration point of view, you just need to know a couple of gotchas to avoid getting tripped up.

Let's start with a fairly common situation. Your company uses SharePoint as its intranet. You only have one domain, so you can keep things simple on the DNS host names. You call your site SP2010. Then, for what ever reason, you need to make your site resolve to the fully qualified domain name (FQDN), SP2010.MyCompany.com. Easy enough, right? First you attempt to hit the site with the FQDN. You get the IIS 7 Welcome screen, or a 404 error.
You check the Application log on your SharePoint server and find an error that says:
A request was made for a URL http://SP2010.MyCompany.com which has not been configured in Alternate Access Mappings. Some links may point to the Alternate Access URL for the default zone http://SP2010. Review the Alternate Access mappings for this Web application at http://CENTRALADMINISTRATIONADDRESS/_admin/AlternateUrlCollections.aspx and consider adding http://SP2010.MyCompany.com as a Public Alternate Access URL if it will be used frequently.
Ok... Awesome.

You go to Central Administration, click on System Settings, and then Configure alternate access mappings, and are greeted with the AAM page.

Things are a little confusing here. To be honest, this page is just plan awful, especially if you have never made an AAM in SharePont 2010. After you know a little about what is going on, it makes more sense, but at first look... Terrible.
There are several buttons across the top allowing you to edit Public URLs and adding internal URLs and Mapping to External Resources. Don't worry about these for now.

The first thing we need to do is to change the view so that we only see the URLs for the Web Application that we are working with. On the right side of the screen, use the drop box to change the view from "Show All" to "SP2010." You click on the drop box and click the button that appears. A selection screen shows up, and you can pick the AAM collection that you will be working with. AAM collections are named according to the Web Application that contains them, so we click on SharePoint - 80, the name of our Web Application. Straightforward right? Ha! At least they give us the default URL so that we know a little bit about what is going on.

Now the AAM screen is back with just the URLs we are worried about.

What to do? First things first... We click on Edit Public URLs. (Disclaimer: After I get done with all of this, you are going to ask why I do my change this way, an not just add an Internal URL. You could. I am configuring this way to demonstrate the differences in zones and use the most confusing pages so that the explanation is clear, and can be used in multiple situations. It also looks a lot cleaner to have your FQDN as the public URL. ;-P)
If the AAM page was bad this page is much much worse.

What now??? It looks like we could just add a new URL here and everything will be cool right? No. Microsoft should have had some sort of validation or something here, because you can't just add a URL for a zone. You have to create the zone first. And... zones are not created in this area. If you want to create a new zone, you have to extend your Web Application in to a new IIS web site. If you add a URL in to one of the zone boxes provided, and try to hit the site, SharePoint and IIS don't know what to do with the traffic. If you are using Host Headers, you are likely to get the IIS 7 Welcome screen. If you are using ports or individual IP addresses, you are likely to get 404 or access denied errors. All this page does is tell SharePoint that traffic for a specific zone will come in over a specific URL. Nothing else.
Right now, we only have one zone defined for this Web Application, the Default zone. So, we can adjust that one. Change the default URL to have the FQDN address, and click Save. Remember that NO validation, other than a check to see if URL that you have saved matches another URL in any collection, is done on these URLs. SharePoint doesn't add anything to IIS in terms of bindings. No host headers are added. Your URL could be completely bogus, and SharePoint won't care.


Now we can do something that is actually pretty cool. In SharePoint 2010, you can have a many to one relationship with internal URLs to a single public URL. So, really you can define any URL you want for your SharePoint sites. As long as you add them to IIS and DNS. More on that later. For now, click on Add Internal URLs.

Here we get a new and somewhat less confusing page, but Microsoft gives us enough ambiguity and lack of validation to hang ourselves with.


Enter in any URL you wish. In our case we want the short URL of http://SP2010. The area that can get us in to trouble, again, is the Zone drop box. Remember we only have one zone defined, the Default zone. So even though you can change the zone, if you haven't extended your web application to create that zone, DON'T CHANGE it from Default. Click save and you go back to the AAM screen, provided that the URL you typed isn't in use by another Web Application.


You now see that we have definitions for both URLs, associated with the same Public URL. This is all we need to do to define our AAM. There is a bit of housekeeping you need to do though...

What we have just done is a SharePoint specific activity. It changes how SharePoint routs its own traffic and how SharePoint handles its own authentication. What we did does NOT change how DNS or IIS works. Those are separate process. If your URLs are not registered in DNS you will need to contact your DNS administrator to add them for you. If you are on your own for DNS work, and you don't know how to add a Host record (also called an "A" record), go here: DNS How To from Technet

For adding a host header in IIS go here: How to add a Host Header binding from Technet

If you have DNS, IIS, and AAM all configured correctly you now have your site set up to use both the short host name and FQDN for SharePoint. You also know some more about SharePoint zones, and how you can very quickly, and easily, add a URL to a SharePoint site.

Saturday, November 10, 2012

How Obamacare Will Help You

By YOU I mean if you have a few years of experience in the IT world. If you are brand new to the game... Sorry, but you are going to have a hell of a time just finding a job. What we will see now that Obamacare is a certainty, is that many companies are going to be laying off people. Companies, especially small business, especially will be working hard to shed workers off their roles to reduce their costs. This is bad. So, how can I work this to my advantage? Well, companies will still need IT work to be done. If they intend to stay in business, they will need MORE IT to automate processes that normally would be filled by workers. This means things like collaboration solutions, workflows, and administrative scripting will become very hot. Since business can't hire FTEs to do this work, who will do it? Contractors, consultants, and other temp workers can fill the personnel void without having to hire them full time. BUT, since most consulting agencies are, in fact, small business, it will be difficult to find a position at an actual consulting company. So how does this help me? Enter independent consulting. With a little leg and research work, you can set yourself up with your own company, with one employee, you. If you do the leg work before 2013, you can get ahead of the game and be ready if you are laid off. Companies will be looking for consultants, and you will be set up and ready to go. Now, working as an independent consultant means that you will have to pay for your own... everything. Insurance, taxes, social security, blah blah blah. You will have to figure out how much to charge per hour so that you can turn a profit. In this case profit means personal income, so remember that you are negotiating for bread on the table. HOWEVER, it is important that you keep your income below $250,000 after that amount you will really take it in the shorts from the tax man. Good luck in the coming months. They won't be easy for any of us. IT is seen as overhead for many business, so you can guarantee if cuts are to be made it will be with us.

Monday, October 1, 2012

Windows 2012 / 8 HID Service and Fancy Keyboards

After a catastrophic crash of my Windows 2008 R2 server, read I screwed up a BIOS update *sigh*,  I migrated my OS to Windows 2012.  The install of the Desktop experience was fairly straight forward, very similar to the procedure for Windows 2008, the only gotcha involved was finding the feature (it's under the User Interfaces and Infrastructure heading).

The big gotcha so far has been with my fancy keyboard. I have a Microsoft Natural Ergonomic Keyboard.  It is awesome.  Not only is it nice on the wrists, but it has handy dandy hot buttons that control volume, mute, launches the calculator, and other programmable buttons.  They are really handy.  BUT they didn't work after I migrated.

Everything I checked seemed to be working well, correct drivers were installed, nothing funny going on in the  event logs, the buttons just didn't work.

I then looked a bit harder at what showed up in the Device Manager:

HID keyboard...  Hummm....  There was a service in Windows 2008 that was HID.  In Windows 2012 the service is, Human Interface Device Access service.


As soon as I started that guy, all of the little buttons started to work.  An easy fix, but a necessary one if you have anything on Windows 2012 that has extras, you will need to start this service.  What is the service?  From Microsoft:
Enables generic input access to Human Interface Devices (HID), which activates and maintains the use of predefined hot buttons on keyboards, remote controls, and other multimedia devices. If this service is stopped, hot buttons controlled by this service will no longer function. If this service is disabled, any services that explicitly depend on it will fail to start.

So... The default in Windows 2012 is that this service is set to Manual(Trigger Start) so if your device does not have software to trigger this service, like my you will need to start it manually. I set my service to start automatically, so that I won't loose my buttons when I restart the server.

Monday, September 24, 2012

Copying Permissions From One List To Another List... In Separate Site Collections

My client has a aggregate list that is fed from several lists in many different site collections.  This list is populated by select fields from the feeder lists by an event receiver that fires when a list item's approval status is set to Approved.

The big gotcha here is that permissions and groups are handled at the Site Collection level.  So they do NOT transfer between the site collections.  This is not very intuitive, because...  well...  The permission levels all sound, look, and act the same.   BUT they are all exist in a separate context.  So, you need to do a little bit of code magic to make it happen.

Here we start the code.




private void ConfigurePermissions(SPListItem targetListItem, SPListItem sourceListItem) {
            SPSecurity.RunWithElevatedPrivileges(delegate() {
                using (SPSite sourceSite = new SPSite(sourceListItem.Web.Site.ID)) {
                    using (SPWeb sourceWeb = sourceSite.OpenWeb(sourceListItem.Web.ID)) {
                        sourceWeb.AllowUnsafeUpdates = true;
                        if (sourceListItem.HasUniqueRoleAssignments && sourceListItem.RoleAssignments != targetListItem.RoleAssignments) {
                            SPRoleAssignmentCollection sourceRoles = sourceListItem.RoleAssignments;
                            PropogatePermissions(sourceRoles, targetListItem);
                            targetListItem.Update();
                        } else if (sourceListItem.ParentList.HasUniqueRoleAssignments && sourceListItem.ParentList.RoleAssignments != targetListItem.RoleAssignments) {
                            SPRoleAssignmentCollection sourceRoles = sourceListItem.ParentList.RoleAssignments;
                            PropogatePermissions(sourceRoles, targetListItem);
                            targetListItem.Update();
                        }
                        sourceWeb.AllowUnsafeUpdates = false;
                    }
                }
            });
        }




First, you see that we are wrapping all of the code in a SPSecurity.RunWithElevatedPrivileges delegate.  You need to do this, otherwise the code would run as the user, and that user may not have permissions to execute everything that needs to happen.
Next, you have the standard "using" statements.  Even though the SPListItem object has a reference to the parent SPWeb object, and through that, the parent SPSite object, the SPListItem was instantiated under the user context, and therefore we need to create new objects under the elevated account.  The good news is that we can create the objects using the IDs contained in the SPListItem object, making it very easy and very safe to instantiate the correct site and web.
You'll notice that I have two places that a SPRoleAssignmentCollection could have come from. This is if the list item inherits its permissions or if it has unique permissions.

Now we get in to the meat of the code. I separated the code out in to two methods to help ease readability and debugging. It also made it easier to pass in the correct SPRoleAssignmentCollection, be it from the SPList or the SPListItem

private void PropogatePermissions(SPRoleAssignmentCollection sourceRoles, SPListItem targetListItem) {
            SPSecurity.RunWithElevatedPrivileges(delegate() {
                using (SPSite site = new SPSite(targetListItem.Web.Site.ID)) {
                    using (SPWeb web = site.OpenWeb(targetListItem.Web.ID)) {
                        if (sourceRoles != null) {
                            if (targetListItem.HasUniqueRoleAssignments) {
                                for (int i = 0; i < targetListItem.RoleAssignments.Count; i++) {
                                    targetListItem.RoleAssignments.Remove(i);
                                }
                            } else {
                                targetListItem.BreakRoleInheritance(false);
                            }


I do a check to make sure that the source SPRoleAssignmentCollection has some data.  This is nothing more than a data validation check.  If the object is null there is no reason to go on and face all of the exceptions right?

Next, I check to see if the target SPListItem is inheriting from the parent list, or if it has unique permissions of its own.  The handy dandy HasUniqueRoleAssignments bool property makes this a snap.  If the SPListItem is not inheriting, we simply call the BreakRoleInheritance method passing in false as the property.  This bool property tells the method to copy the existing inherited permissions or to start fresh.  Since we are going to replace the permissions with the permissions from the other list, we pass "false."
If the item already has unique permissions, we need to remove them.
Permissions, weather it be for the list itself or the list item, are kept as SPRoleAssignments in the object's SPRoleAssignmentCollection.  Much like the SPWebCollection object that keep references to all of the SPWebs in a SPSite object, so it goes with the SPRoleAssignmentCollection and SPRoleAssignments.  If the object already has a bunch of SPRoleAssignments in the SPRoleAssignmentCollection, we get rid of them by removing each one.  I do this quickly with a for loop using the SPRoleAssignmentCollection's Count property.

Now that we have a clean SPRoleAssignmentCollection we need to go about populating that collection with the SPRoleAssignments that come from the other list.  Like I mentioned before, permissions are Site Collection based, and, worse yet, SPUser objects are SPWeb based. What does that mean?  If there is no corrisponding SPUser object for your user or group, you can not assign permissions to them.  Even if your list inherits its permissions from the web, and your web is set to allow all Authenticated Users, if the particular user that you want to assign permissions to has not accessed the target web, there is no SPUser object for that user.  As far as the SPWeb is concerned the user doesn't exist.  This can be a real problem.
How do we get around it?  Well, we need to first add the user or group to the web, then create a SPRoleAssingment that will contain that user and map permissions.  That brings us to the next section of code:


foreach (SPRoleAssignment role in sourceRoles) {
                                SPUser newUser;
                                try {
                                    newUser = web.EnsureUser(role.Member.LoginName);
                                    web.EnsureUser(role.Member.LoginName);
                                } catch {
                                    continue;
                                }
                                web.AllowUnsafeUpdates = true;
                                SPRoleAssignment newAssignment = new SPRoleAssignment(newUser.LoginName, newUser.Email, newUser.Name, "");
                                foreach (SPRoleDefinition sourceDef in role.RoleDefinitionBindings) {
                                    string defName = sourceDef.Name;
                                    if (defName == "Limited Access") {
                                        continue;
                                    } else {
                                        try {
                                            SPRoleDefinition newDef = web.RoleDefinitions[defName];
                                            newAssignment.RoleDefinitionBindings.Add(newDef);
                                            targetListItem.RoleAssignments.Add(newAssignment);
                                        } catch {
                                            continue;
                                        }
                                    }
                                }
                            }
                        }
                        web.AllowUnsafeUpdates = false;
                    }
                }
            });
        }


First, I create a loop that will take me through each SPRoleAssingment that the source SPListItem or SPList object has.  Then I create a SPUser.
Now is where things get sticky.  The way I have this code really isn't the best way to solve this, but it worked for me, and I will fix it another time...  Maybe...
What I do first is to fill out the SPUser object by calling the SPWeb.EnsureUser method.  This is a very handy method that will check if the user or group exists in the current context, then add it to the current context if it does not.
If you have any SharePoint groups associated with your permissions you are going to have a hard time.  You will either need to write code to create groups with the same name and permissions in your web, or create these groups ahead of time.
I use Active Directory groups for my permissions, so I don't care at all about SharePoint groups that may be in the SPRoleAssignmentCollection.  I just ignore them, thus the try\catch block that does nothing other than go on to the next permission if there is an exception.  Really, the only exception that can occur is the one that says that the SharePoint group does not exist in the current context.  I don't care about that, because AD groups, as long as they are in AD, can be added directly.

Next we make sure that the Unsafe Updates, like permission changes, are allowed.  One minor gotcha is that if the SPRoleAssingmentCollection.Add method is called, the AllowUnsafeUpdates bool is switched back to false automatically.  We need to confirm that it is True so that we can do our permissions update.

Now we create the new SPRoleAssignment that we will join up this SPUser that we just created with its proper permissions on the SPListItem.  We pass in the properties of the SPUser in to the SPRoleAssignment  object.  Now, it might be tempting to simply pass the SPRoleAssignment.Member object to the new SPRoleAssignment object that we are trying to create.  BUT remember that the SPRoleAssignment.Member is a member of the OTHER site collection.  Not the site collection that houses the target list item.  If we do pass in the SPRoleAssignment.Member from the source site collection, the code will build and it will even execute, BUT the results will NOT be what you are expecting.  In my development envornment I saw the proper object being passed in to the target item's SPRoleAssingmentCollection, but when I checked the collection after the add method was called, I saw that the Member had changed to be the first SPUser that had the same permissions in the web.  Very strange!!
So, to avoid this very real and very dangerous gotcha, we create a brand new SPRoleAssignment and pass in the SPUser properties.

Next I pick apart the actual permission bindings in the form of SPRoleDefinitions.  First, off...  What really annoys me about this particualr section is that Microsoft changed the way they name their collections.  Nearly every collection they have they name so it is very easy to deduce what the colection contains.  The SPSite.Webs is a collection of SPWebs.  The SPList.Items is a collection of SPListItems.  What is the SPRoleAssignment.RoleDefinitionBindings a collection of?  SPRoleDefinitionBindings?  No such object.  It is a collection of SPRoleDefinitions.  Not terribly different from the standard naming convention, but still enough to mess with you and prevent your code from building.
 Anyway, because the same user or group can have multiple permissions assigned to it, you need to create a SPRoleDefinition for each permission and add it to the collection.
Now, a show stopping gotcha appears.  There may be a user, like the System Account or the Search Account, that gets added to the list by the system, and is assigned "Limited Access."  Limited Access is a special permission type, that you can not add a role.  It is a system reserved permission level.  But, it will show up in the RoleDefinitionBindings collection.  It will cause your code to fail if you try to assign this permission level to a user, so, you need to have some code that will handle this possibility.  I simply continue my foreach loop if I encounter it.  You could use some LINQ to filter it out or something else, but, since the foreach loop is pretty performant, I just move on to the next one.

Now we get to the business binding a permission to a user.  We have our user created and added to the web, we have our user added to to the SPRoleAssignment, now we create the SPRoleDefinition to add the permission to the collection.  Because our permissions are going to be named the same, unless you created your own permission levels, then you would need something that would add a similar permission level to your target web, we can just grab the name of the permission from the source web and look it up in the target web.  Like most objects in SharePoint the SPWeb.RoleDefinitions object has an index that you can pass the string name in to.  Here I assign the name of the source definition to a string variable and pass that as the index to the SPWeb.RoleDefinitions object.
Now that I have a RoleDefinition, I add it to the SPRoleAssignment.RoleDefinitionBindings collection.  Then, finally, I add the SPRoleAssignment to the target SPListItem.RoleAssignments collection.
I continue all the way through for all of the objects that are in the source SPListItem.
Cleaning up, I make sure that the target SPWeb has its AllowUnsafeUpdates flag set to false.
Returning to the calling method, I call the SPListItem.Update() method to commit all changes, and finally make sure that the source SPWeb has its AllowUnsafeUpdates flag set to false.

Not horrifically difficult, but there are several gotchas that tripped me up.  I hope you are able to step around them!!!
Here are both of my methods in full form:
private void ConfigurePermissions(SPListItem targetListItem, SPListItem sourceListItem) {
            SPSecurity.RunWithElevatedPrivileges(delegate() {
                using (SPSite sourceSite = new SPSite(sourceListItem.Web.Site.ID)) {
                    using (SPWeb sourceWeb = sourceSite.OpenWeb(sourceListItem.Web.ID)) {
                        sourceWeb.AllowUnsafeUpdates = true;
                        if (sourceListItem.HasUniqueRoleAssignments && sourceListItem.RoleAssignments != targetListItem.RoleAssignments) {
                            SPRoleAssignmentCollection sourceRoles = sourceListItem.RoleAssignments;
                            PropogatePermissions(sourceRoles, targetListItem);
                            targetListItem.Update();
                        } else if (sourceListItem.ParentList.HasUniqueRoleAssignments && sourceListItem.ParentList.RoleAssignments != targetListItem.RoleAssignments) {
                            SPRoleAssignmentCollection sourceRoles = sourceListItem.ParentList.RoleAssignments;
                            PropogatePermissions(sourceRoles, targetListItem);
                            targetListItem.Update();
                        }
                        sourceWeb.AllowUnsafeUpdates = false;
                    }
                }
            });
        }

        private void PropogatePermissions(SPRoleAssignmentCollection sourceRoles, SPListItem targetListItem) {
            SPSecurity.RunWithElevatedPrivileges(delegate() {
                using (SPSite site = new SPSite(targetListItem.Web.Site.ID)) {
                    using (SPWeb web = site.OpenWeb(targetListItem.Web.ID)) {
                        if (sourceRoles != null) {
                            if (targetListItem.HasUniqueRoleAssignments) {
                                for (int i = 0; i < targetListItem.RoleAssignments.Count; i++) {
                                    targetListItem.RoleAssignments.Remove(i);
                                }
                            } else {
                                targetListItem.BreakRoleInheritance(false);
                            }
                            foreach (SPRoleAssignment role in sourceRoles) {
                                SPUser newUser;
                                try {
                                    newUser = web.EnsureUser(role.Member.LoginName);
                                    web.EnsureUser(role.Member.LoginName);
                                } catch {
                                    continue;
                                }
                                web.AllowUnsafeUpdates = true;
                                SPRoleAssignment newAssignment = new SPRoleAssignment(newUser.LoginName, newUser.Email, newUser.Name, "");
                                foreach (SPRoleDefinition sourceDef in role.RoleDefinitionBindings) {
                                    string defName = sourceDef.Name;
                                    if (defName == "Limited Access") {
                                        continue;
                                    } else {
                                        try {
                                            SPRoleDefinition newDef = web.RoleDefinitions[defName];
                                            newAssignment.RoleDefinitionBindings.Add(newDef);
                                            targetListItem.RoleAssignments.Add(newAssignment);
                                        } catch {
                                            continue;
                                        }
                                    }
                                }
                            }
                        }
                        web.AllowUnsafeUpdates = false;
                    }
                }
            });
        }

Thursday, September 20, 2012

Recruiters

Recruiters...  You guys can really get under my skin.  I get that you have a job to do, and that job entails getting me to leave mine.  I know that you only get paid if I leave my job, and your bonus depends on how much in salary I get paid.  It is a tough job, because the work is on both ends, you need to sell the job to me, and then sell me to the employer.  There is a lot that can go wrong, and I understand that it can be frustrating for you.
HOWEVER, if you are a professional IT recruiter, you need to do a little bit of research in to the actual IT world to know what the hell you are talking about.  There are several things you do that drive me up a wall, and a few that will make me want to never ever use you to nail down an opportunity, no matter how lucrative.
Since this is my blog, and I am a nice guy, Imma give you all some great advice instead of a listing of my pet peeves about recruiters.  In all seriousness, this will help you do better at your job, and will help you gain the trust of your candidates.


  • Know SOMETHING about the skills you are recruiting for.
    • This has got to be my absolute biggest pet peeve about recruiters.  When they call/email me asking about my skill set, and have absolutely no clue about what they are asking about.  I loose all confidence in you representing me when you first ask me if I know .NET, then ask me if I know Visual Studio.  Visual Studio is the programming platform for .NET.  Yes, I know you could use something else to write code in, but NOBODY does.  Don't ask me if I have worked in the Windows Communication Framework, then ask me if I know WCF.  They are the same thing.  Don't listen to my expereince in designing service frameworks using WCF, and ask me if I have ever done SOA development.  Don't ask me if I have developed web parts for SharePoint, then ask me if I know ASP.NET.  SharePoint IS ASP.NET.  ARRRGGGHHH!!!!
    • With just a little bit of reading, and I mean just a little bit, less than 1/2 hour, you could look up those terms on the internet and know, at a very high level, EXACTLY what they are about.  You are a damn professional, do your research!!!!
    • I will forgive a recruiter a lot.  You are not truly IT people, so I don't expect you to know what the MVVM patter is, or where to go when implementing a Managed Metadata Taxonomy.  I do expect you to know the very very very basics so you don't ask any redundant or misguided questions.  If you don't know what my skills are, how can I trust you to find a position that I will fit in to?  If I am hiring you to find me someone, how can I trust you to find me the right person?
  • Never cold call someone to ask them what a technology is.
    • I must get one of these every month.  "Hey, this is Bob from Bob's Tech Recruiting Company.  I saw your resume on line and I wondered if you could tell me what 'SharePoint' is."
      This gives me NO confidence in you representing me.  I will politely direct you to Microsoft's web site for your information after a very short description of what SharePoint is.
      If you have a need for a SharePoint professional, simply come out and say it.  If you don't know what it is, GOOGLE!  Do your research.
  • Look at the candidate's resume first to determine experience.  Make an educated guess as to weather the job that you are looking to fill will fit in to the candidate's experience level.
    • I have written my resume to be very easy to go through.  You can easily see with just a glance that I have many years experience in the stated technologies.  You inspire very little confidence as someone who takes their job seriously if you submit to me entry level jobs when my experience is clearly senior level.  The same is true for an entry level guy getting submitted for senior level positions.
  • Do not balk when you hear salary requirements. 
    • Yes, I might make more than you do.  I also have more experience than you do.  Don't make snide comments, cough, say wow, or make any other comments.  I might be tougher to place than you think.
      I realize the difficulty of finding a job that will keep me in the same pay scale that I am accustomed.  I have been in that position before.     
  • Never simply drop a correspondence if the employer isn't interested in the candidate.  
    • Let me know that the client is no longer interested in me and the reason why.  It is a courtesy call.  It let's me know that we are in this together and that I can trust you to let me know the hard news.  Knowing the reason why helps me become a better candidate in the future, because I will know what I need to do to sharpen my resume, interview skills, or my personal attitude.
      Remember, the better candidate I am, the more likely YOU are able to place me.
  • This is a business deal.  Do not take rejection personally.
    • You are a professional.  You are working on sealing a business transaction.  If I don't like the job or company that you are submitting to me, how is that a personal attack on you?  Don't get upset if I am not ready to leave my current position, or I just don't like what you have put in front of me.  
  • Money is not the only thing that will motivate a candidate to switch jobs.   
    • I have had HUGE numbers thrown at me to work for companies.  I have turned them down.  The reason is that I didn't like the company culture, or some other facet of the job smelled wrong to me.
      I really hate it when recruiters ask over and over again, how much is it going to take to get you to move?  Or this employer is willing to pay more for you.  Blah blah blah.
      Find out what the candidate needs to move.  For me, I will take a significat hit on my salary if more vacation time is offered.  I will sacrifice salary AND vacation time if the opportunity will gain me experience in something that I really want experience in.
      I moved from my last job because my current job offered global deployment experience.  My last job didn't pay me more, but gave me a bunch of vacation time and full benefits.  I don't get benefits now.
      Find out what is important to that candidate and see if the employer will move their direction.

Monday, September 3, 2012

ItemDeleting Event Not Firing

I have written many event receivers.  I have written them for just about every conceivable business use, and for some that are not so conceivable.
I am a MCPD, passing both tests in the 90% range.  I have written these receivers for SPS 2003, MOSS 2007, SharePoint 2010, and even on SharePoint 2013 Beta.

I'm kind of a big deal.

So, why, when I was writing such a mundane application as an event receiver, did one of the events not fire? I overrode the proper method.  I used the correct syntax.  I had no runtime exceptions, and everything built and deployed just fine.  During debugging, as this was a farm deployed solution, I attached to the correct w3wp.exe worker process application (if it would have been a sandboxed solution I would have attached to the user worker process application, SPUCWorkerProcess.exe).  I knew this, because the other events I overrode were firing and doing their jobs just fine.  BUT when it came to the delete events nothing...  What the heck?????????

After looking around and pulling out more than a little bit of hair, out of frustration I created a new solution with just the delete events.  This solution worked just fine.  No muss no fuss.  So, why would the very same code not work in one solution, but not in another???   I did a file comparison of the wsp files to find out what was up.

What happened was this...  When I initially created the project in Visual Studio, I checked the box for just the ItemUpdating event.  Nothing else.  What Visual Studio does with this setting is it adds in the Elements.xml a <Receiver> section in a <Receivers> block.  In that block is an element called <Type>.
What I had forgotten to do with my first solution was to add a <Type> element for my ItemDeleting event.  The Elements.xml file registers the receiver with SharePoint.  If it doesn't have a <Type> section for your events, it doesn't matter how much code you have written in as many overridden methods, the will not fire.
Now, the ItemDeleting event is a separate receiver event, thus it does need its own <Receiver> section.
I just copied my ItemUpdating receiver, and pasted it below.  Then I changed the name and the <Type>.  Everything else can remain the same.

After realizing my mistake, I added the proper <Type> elements to register my deleting events, and BLAMO, they fired just as they should have.
One little trick that may catch many people is that you may have to deactivate then re-activate your feature in order to register the new receiver section, and get the event to fire.  For whatever reason, SharePoint may not load the new XML, even after the IIS Application Pool is recycled.  It can be very annoying, ESPECIALLY if you are trouble shooting other reasons why your event is not firing.

It was a rookie mistake that I made.  Nearly every part of SharePoint development has two parts to it.  The code or assembly part, and the declarative XML part.  The code never works without the XML letting SharePoint know what's up.

One of the good things about software development is that the code will always find away to keep you humble.

Wednesday, August 22, 2012

Managed Metadata, Lists, and the TaxonomyField

My client has several document libraries in many different Site Collections.  All of the site collections use a global Managed Metadata Service.

My client very much likes how lists can be filtered by the Managed Metadata Navigation on SharePoint 2010 Lists.  So, with all of those document libraries scattered all over the place, and the ease with which we can use Managed Metadata Navigation, why not create a list in the root site of the portal site collection that has links to ALL of the documents in ALL of the Site Collections???  You can do that right????  Sure, I say, sounds like fun.  Woof.

I am not a fan of duplicating data, especially when that data is potentially very large documents.  However my client simply wanted a link back to the original document and the ability to filter the documents just on the Global Managed Metadata...  So, what to do?  Essentially we create a list that has two fields, besides the title, a hyperlink field and a Managed Metadata field. Great!!  That's easy.  Now we need to populate it...  Boooo!!!  That's not so easy.
Well...  I will qualify that.  It wasn't easy until I finally got my head around just what the Taxonomy Fields were, how the Managed Metadata service worked, and all of the gotchas that surround it.

My solution was to create an Event Receiver that would look at document libraries, and if the list's ID matched one in a configuration list, an item would be created in the Master List that had a link to the document on the source list and a managed metadata field that corresponded with the term in the source list. Getting the URL to the document was easy. The tough part came with the Manged Metadata field.

First, because this was a big part of my problems, you have to get your head around the fact that the Managed Metadata fields are VERY different from any other SPField object you have ever worked with.  It is essential to look at them as completely separate entities from the normal SPFields out there.  Your first clue to this is that you can't just start declaring things as TaxonomyFields, that is what the SPField.Type is that contains the Managed Metadata stuff...  For one, TaxonomyFields do not reside in the normal Microsoft.SharePoint namespace, like the SPField objects do.  You need to create a reference to the Microsoft.SharePoint.Taxonomy.dll.  That is where those guys live.

Next, when you are typically using the object model to set a list item equal to another list item, it is pretty elementary.  You have your SPListItem, you use the handy dandy index to set your field, you do it for the other item as well and you set them equal to one another.  Easy peasy.
SPListItem.Items["Goof"] = SPListItem.Items["Ball"]

Sometimes the list items get a little bit more complex, and you have to use a SPFieldValue object to populate them.  Like a SPFieldUrl field.  You set it using the SPFieldUrlValue object.
SPFieldUrlValue.Url = "http://ramblingsofamadcomputerguy.blogspot.com/"
SPFieldUrlValue.Description = "Some Jerk's Blog"
SPListItem.Items["HyperLink"] = SPFieldUrlValue

In both cases you are simply setting the value with some strings that are associated with that SPField's type.  This is NOT the case when you are dealing with Managed Metadata.   Microsoft wanted to make things extra specially vague by adding things to site collections such as hidden text fields hidden lists.  And then requiring that you know these hidden things before you can set values of anything.  Way to go Microsoft.  Imma yell at you at the next SharePoint Conference ...  Not that you will care, but it will make me feel a whole lot better.

So we come to our first and most serious gotcha.  Metadata terms, like nearly all of SharePoint's things, all have a GUID.  In Managed Metadata terms this is called the SSPID.  These are easy to find, and actually can be brought up from your TaxonomyField object.  You would think that this, Global Unique IDentity , along with a friendly name, would be all that you need.  After all the ID is GLOBAL!!!!  SharePoint could just look it up in the store.  Right??  Right?????   Nope.  You also need something called a WSSID.
A what now??  Just as it implies the WSSID is an ID unique to the site collection with with the term is being used.  See where the gotcha is coming?
What if the term has never been used in the Site Collection?  How are we supposed to know what the WSSID is if it does not yet exist???  Bingo.  The million dollar question.

So this is what you need to set your TaxonomyField correctly.  A term name, a term GUID, and a WSSID.  Great.  All is not completely lost, our friends at Microsoft have given us away out of the woods.

So, there are a few things that we need to do.  First, we need a TaxonomyField set to the TaxonomyField in our list.  Notice something very critical here.  It is called a TaxonomyFIELD.  Because it IS a specific type of SPField object.  So when you are instantiated your TaxonomyField from a list you must use the FIELD object in the list. Lets look at some code. First we instantiated the TaxonomyFields from the list


SPField list1Field = item.Fields["Source"];
 SPListItem itemToAdd = list2.Items.Add();
 itemToAdd["Title"] = "Source";
 TaxonomyField list1TaxField = (TaxonomyField)item.Fields["Source"];
 TaxonomyField list2TaxField = (TaxonomyField)itemToAdd.Fields["Target"];


In the code you can see that the TaxonomyFields are instantiated by using the Fields collection of the SPListItem, NOT from setting it equal to the the VALUE of the item. This is important. You are instantiated a FIELD. We will set the value of this field later on.

Next we need to create the very thing that will populate the field we just instantiated. It is called a TaxonomyFieldValue object. Remember that C# is a strongly typed language, so if you are setting the TaxonomyFieldValue object equal to a value that you already have, you do need to cast objects correctly.
After you have the TaxonomyFieldValue object, we need to create a new one for the list item in our target list. This is where a second gotcha comes in. You can't just cast the source value as TaxonomyFieldValue and set it equal to the new TaxonomyFieldValue. Why? Because the values are NOT the same. For one, if you are crossing Site Collection boundaries, you won't have the same WSSID. Thought I wouldn't get to that didn't you??? There are some other things wrong, but rest assured setting them equal isn't the way to go.

Now I have been focusing a lot on what if the term hasn't been used before. What if it has been used, or if you are coping to another list in the same site collection. How would I get the WSSID? I'll go over this quickly, because you really don't want to be messing too much with where you get the WSSID, because there are much easier ways to go about it.

First the WSSID is a numerical field that represents the term in a very secret list. It is called the TaxonomyHiddenList. Sounds spooky right? You can look up the term in that list, just as you would any other SharePoint list. You take the ID of the SPListItem that holds the term and you have the WSSID. NEVER MESS WITH THE TaxonomyHiddenList!!!!!!!!!!! It will seriously ruin you day. Just stay away from it. It is one of those things behind the scenes that makes SharePoint work. Just don't go looking for it. It is bad news. Instead, use the API that comes with the Microsoft.SharePoint.Taxonomy namespace.

You can use the TaxonomyField.GetWssIdsOfTerm method to look up the WSSID in the TaxonomyHiddenList, without actually writing code to directly access the TaxonomyHiddenList. But if you use that method, you will need to write logic to do something else if the term does not exist. There is an easier way. It works in all situations and is elementary to use. It is the TaxonomyFieldValue.PopulateFromLabelGuidPair method.

The TaxonomyFieldValue.PopulateFromLabelGuidPair method will add the the term to the TaxonomyHiddenList if it does not exist, or it will automatically populate your TaxonomyFieldValue object with the proper WSSID if the term does exist. It is a very handy tool. It does everything you want, nothing you don't. Use this guy!!!
Now, you could set the WSSID to -1 and that will work similarly to the TaxonomyFieldValue.PopulateFromLabelGuidPair method, but... I don't like that as much. Microsoft is reluctant to change the way their methods work for backwards compatiability reasons, but seem to have no problem messing with how it uses "reserved" values such as -1. I think that the TaxonomyFieldValue.PopulateFromLabelGuidPair method is the best way to go.

Ok, all of that said, what does the TaxonomyFieldValue.PopulateFromLabelGuidPair use? It uses a delimited string of the friendly term name and the term GUID. The dilimter is the pipe "|".

I typically use the TaxonomyFieldValue.Label and the TaxonomyFieldValue.TermGuid properties put together with string.Format. It makes it very easy.

After that we have everything we need to set the value of our TaxonomyField. We use the TaxonomyField.SetFieldValue method and pass in the SPListItem that contains our TaxonomyFiled along with the TaxonomyFieldValue. Update the SPListItem and we are done!!!

//Set the TaxonomyFieldValue with the value of the first list item
TaxonomyFieldValue list1TaxFieldValue = (TaxonomyFieldValue)item["Source"];

//Create a new TaxonomyFieldValue with the TaxonomyField in the target list
TaxonomyFieldValue value = new TaxonomyFieldValue(list2TaxField);

/*Create the WSSID using the values for the term name and its GUID.  Notice that the values are seperated by the pipe.*/
value.PopulateFromLabelGuidPair(string.Format("{0}|{1}", list1TaxFieldValue.Label, list1TaxFieldValue.TermGuid));

//Use the SetFieldValue method with the SPListItem and the TaxonomyFieldValue
list2TaxField.SetFieldValue(itemToAdd, value);

//Update the SPListItem
itemToAdd.Update();



Not very straight forward, but not excessively difficult either. I don't know if this is changed in SharePoint 2013, but I would expect that it isn't. Microsoft, reportedly, makes much greater use of Managed Metadata in SharePoint 2013, so it would be a good idea to familiarize yourself with it.

Thanks to Nick Hobbs. His blog post showed me the way!!

Wednesday, August 1, 2012

MCPD SharePoint 2010!!

As you can see to the right, I passed exam 70-576 PRO: Designing and Developing Microsoft SharePoint 2010 Applications.  With that I have earned a Microsoft Certified Professional Developer certification.

Microsoft has said that the PRO tests are supposed to be the ones that are the most difficult, and for 70-668 Microsoft SharePoint 2010 Administrator I definitely agree, but this one, in my opinion, really wasn't that tough.  I had a difficult time with 70-573CS Microsoft SharePoint 2010, Applications Development.  Mainly because that one focused on the massive SharePoint API.  I don't really understand why Microsoft wants to test on minute aspects of the API though.  Most of the minutia you will get out of Intelisense, so why test over it?  The App Dev test should focus on core concepts, and the high level classes that need to be used and referenced.
The  Designing test, I think, did a good job of covering all of the bases, but I think more time, and questions should have been spent on, when to use the Property Bag, web.config, Hierarchical Object Store, and lists for configuration settings.  Also more time could have been spent on classes that are and are not available in Sandboxed solutions.  I might have thrown in a question or two on how to deploy sandboxed solutions while getting around some of the limitations of sandboxed solutions.
Inexplicably, time was spent on external BLOB storage.  I would have thought that this would have been a topic for the administration tests rather than the App Dev ones.  Sure, you may have to build your own provider using the ISPExternalBinaryProvider, but how often is that going to come up?  Stratigies to deal with sandboxed solution limitations are much more likely to be addressed by developers than deciding if External BLOBs are going to be used.  That is much more an Admin issue.

Anyway, the tests are in the books, and now I have to decide if I want to go a head and peruse a Microsoft Certified Master in SharePoint.  I really want to, but I don't know if I have the time and money to do so.  Also, what will it gain me?  I really don't want to be an independent traveling consultant, so why do I need the cert?  The boot camp that you have to attend is in excess of $18K, not counting travel expenses, they are held on the Microsoft Redmond campus, and are THREE WEEKS long, so why??  Just to have the initials after my name?  I have to admit that I do want the recognition...  However there are downsides to having such an advanced certification level.  A job might be willing to look at me because I have both MCITP and MCPD certs, but might think I am overqualified if I have the MCM.  Also if I apply for a leadership or manager position, the MCM might make a potential employer believe that I would be TOO involved in the day to day tech side of things, and neglect the manager work that I was hired to do.
If, perhaps, a company wanted to pay for this training I would do it, but right now...  No, I don't think so.  The cost is too high, and the benefit too small.  For now, I am content with my existing certification level.  It won't be long until I have to start boning up for the next series of exams on SharePoint 2013.

Thursday, June 21, 2012

SharePoint 2010 and SAP's Integration Option for Microsoft SharePoint

I am currently on a contract that has me working to integrate SharePoint 2010 and SAP's Business Objects Enterprise suite of products.  In our first phase of deployment, we are simply working on the surfacing of reports using SharePoint as our portal server.  The easy way to do this is to use SAP's Integration Option for Microsoft SharePoint (IOMS, or IPoint).

Overview

IOMS is a set of internal and external (to SharePoint, more on that later) services, some web parts, application pages, and a site collection layout.  All of this is presented in to SharePoint with a solution file.

IOMS directly surfaces reports in a couple of different ways.  First you have the Report Repository view, that is, essentially, just a representation of your BOE folder hierarchy presented in a web part.  Navigate through the folders and click on the report you want.
Easy enough, right?
The other way is to use a viewer web part (part of IOMS) and, using an ID property for the specific report, directly present the report to the user.
All of this makes it very easy to directly surface reports, however we run in to some problems that, as SharePoint users, we don't expect.

First and foremost, it must be stressed that the IOMS product is just a "window" in to the BOE system.  You are using SharePoint to look in to your BOE deployment.  Because of this, you don't get the nifty features that we are used to in SharePoint.  The Report Repository is NOT a SharePoint library.  You can't add metadata to the library, you can't filter the results, you can't group the items, and you can't create document workspaces for the reports.  In fact NONE of the whiz-bang features that we have come to use and love in SharePoint are available.  What see is only what you get in BOE.  
IOMS does give you a "discussion" feature for the reports, BUT, again, it is not a SharePoint discussion, so you don't get all of the features that we are used to in a discussion list.  Users of SharePoint using IOMS out of the box will be immediately frustrated, especially if they are used to the new SharePoint 2010 features of metadata filtering, workflows, and external data columns.

Technical Stuff

IOMS is actually pretty interesting under the hood.  It is as if the IOMS development team looked at the development story for MOSS 2007 and said "Let's do one of each!"  There are web parts, internal services, external services, site layouts, content types, feature sets, and all sorts of other goodies.  

Installing IOMS you will find that the majority of the code goes to the SAP Business Objects folder in the Program Files directory.  At its heart, IOMS is a Java based application, and all of those java jars need to go somewhere.  In this folder are the external services and other things that make IOMS work.  SharePoint sees them via virtual directories in IIS in the _layouts folder.  These are all treated as IIS applications, sharing the same Application Pool as the SharePoint Web Application. 
The problem with this is that each application in IIS requires its very own web.config file.  So you constantly need to go back to this folder to adjust the settings.  It wouldn't be so bad if there was only one or two applications.  However, SAP has a separate application for each type of report they offer.  So, there are applications for the Web Intelligence reports, the Crystal Reports reports, the flash dashboards, etc.  Each one has its own unique configuration, and you need to make changes in each web.config file to ensure that each type of report will load properly.  

One other annoyance that I found was that the IOMS installer will deploy a bunch of stuff in to SharePoint directly, but the thing that it needs to work correctly is deployed via solution...  AND they don't deploy the solution for you.  You have to manually deploy the solution.  That kind of sucks...   You see in your site templates the SAP site, but you get errors when you try to deploy it, because the assemblies haven't been deployed yet.  Same thing with several of the features and web parts.  It is a big pain.  

Claims Authentication Mode

Now to the big kicker...  Claims Authentication Mode is new to SharePoint 2010.  It gives the most flexibility for authentication, while still providing the ability to use Windows Authentication.  Most SharePoint administrators and architects recommend that you create your Web Applications as Claims Based.  
This does some things internally to SharePoint.  When a Web Application is set to Claims Mode, all internal authentication happens via claims.  Your windows tickets are converted in to claims tokens.  This works all well and good for any SharePoint service, as they are all claims aware.  However if you have a third party service that is deployed to SharePoint as an internal service, i.e. in the _vti_bin without being recognized as an application in IIS, it must be claims aware, or authentication will fail.  
There are two very important WCF services that IOMS deploys to the _vti_bin as internal SharePoint services.  
Remember when I said that IOMS is simply a "window" to your SAP deployment?  I am not kidding.  The report viewers do not actually exist on the SharePoint server.  They exist on the SAP server.  IOMS has code that opens a connection to the SAP server's web interface and presents the viewer in kind of a goofy Iframe setup.  The service that starts all of this nonsense is this internal SharePoint service.  Guess what?  It is NOT claims aware.  Therefore, no mater what you do, if your Web Application is set to Claims Authentication Mode, authentication will fail to this service.  In order to use IOMS, your Web Application MUST be set to Classic Authentication mode.

This is a big gotcha, and in order to understand what is going on, you need to brush up on what is actually hapening under SharePoint's hood.  First read about Planning Authentication, then read all about Claims Authentication Mode and what it means to you.   

My Deployment

I like all of the SharePoint features...  So does my client.  So, I am doing my best to create a happy medium for surfacing their reports, AND using SharePoint features.  
For the initial deployment, we will be creating a list that will have an entry for each report that exists in BOE. This will be a SharePoint list all of the neat things that SharePoint has can be used.  For the time being, when a new SAP report is published, an administrator will have to go in and create a new list item for that report.  In the future, when a new report is published, I will have some sort of job on the SAP side that will kick off a workflow in SharePoint to create the list item automatically, then inform the administrator for approval, and to fill in any blanks left by the SAP side.  
Of course all of this is just marking time until my client purchases the Duet Suite developed by Microsoft and SAP in tandem.  Duet creates connections in SharePoint's Business Content Services enabling us to create external content types and columns for our lists.  Once that happens we can develop custom lists that will directly surface reports and metadata from SAP automatically.  

Tuesday, May 22, 2012

Interviews and Responding to Job Postings

I do a lot of interviews.  Both for jobs, and interviewing others for jobs.  It is par for the course when you are in the consulting world.  I have noticed a disturbing trend, and, if you are looking for a job, perhaps I can give you some tips on standing out.
First, people are replying to job postings as if they are replying to a text message or an email to a friend.  They don't check their work, they use familiar names, they use text message shorthand.  When showing up to an interview, people show up in ill fitting clothes, revealing clothing, and just generally unpresentable.

The first thing that you must understand about the job process is that the company is looking to find someone they can entrust to do a job and make them money.  You need to present yourself as the kind of person that the company can trust to make them money.  If your writing style or your personal style is not matching what they have in mind as a responsible, serious person, you will not get the job.

When you are looking through job postings, read them.  If you have around 50% of what the posting asks for, and if you have heard of the other 50%, go ahead and apply.  A posting, for the most part, is a list of requirements that the employer wants in an ideal candidate.  You may not be the ideal candidate, but you might be close enough to get an interview, or to even hire based on your salary requirements and your willingness to get up to speed.
If you DON'T have at least 50% of the requirements, move on.  The employer will just round file (trash can) your resume.

When you decide you are going to reply to the posting, look through it to find the person's name who authored the posting.  This is very important.
Use the name that you found and address your reply directly to that person.  Use the formal presentation of their name in your greeting:  Mr. Donaldson, Ms. Takayama, Dr. Jones.  DO NOT use the author's first name. You don't know them, and they might be sensitive to that kind of thing.
Personally, I do my greetings with just the author's name, I don't put a "Dear" in front of it.  The word implies a closeness that does not exist, and just doesn't belong in a business setting.

I like to write out my responses to job postings in a word processor program.  I use Microsoft Word, because it has both grammar and spell check.  I want to make sure that my replies are grammatically correct, has correct punctuation, correct word usage, and proper spelling.  In other words proof read your reply before sending.  This is not a text message, it is not an email to your friends.  This is the very first contact with a potential employer, and you want to sound like a person that they would want to give thousands of dollars a year to.  Nearly every job posting has the requirement that the candidate have outstanding written and verbal skills.  This reply is the very first impression of your written skills.  Take it very seriously, because the business certainly will.

Remove any type of slang or personal jargon from the reply.  I immediately discard any replies that use "u" for you, "ur" for your, or use its, it's, your, you're, and to, too, and two improperly.   Its basic English, guys.  If you can't figure those things out, I have little hope that you can tackle the requirements of the job.
Having a reply that is correct grammatically tells me that you are through, pay attention to detail, and care about your impressions.  That is the kind of person I want on my team.
Do not use "What's up?" as your greeting...  Ever.  Do not use the phrase "Hit me back." at any point as well.  These also are immediate round file triggers.

So, you sent a reply and now you have an interview.  Sweet!!  Take out any piercings that may be seen as unusual.  Women, take out all but the bottom couple of your earrings.  Guys, if you have those gauges in your ears, you are doomed to working at the coffee shop for the rest of your life.  Way to go dumbass.

Look at your wardrobe while you still have time to shop.  Make sure you have a suit that fits.  This goes for men and women.  make sure to wear something that covers ALL of your tattoos.  If you have ink that shows on your neck or your hands, you will be working at the coffee shop the rest of your life.  Way to go dumbass.

If you haven't worn your suit in a while, get your suit cleaned and pressed.  It makes the creases look sharp, and gives the look that you prepared very specifically for this interview.


Men:
Take a good long look at your dress shirts.  Ignore any shirt that has an obvious stain or discoloration.    The choice of color is yours, but you should go with a conservative white or blue.  Stripes are ok as long as they are subtle, and try and stay away from the pinks and lavenders.  I like these colors, ESPECIALLY with a black suit, but you don't know they type of person you will be interviewing with.  They may have an open mind, but they also have an idea of what a man should be wearing.  They may not find favor with these colors.
Make sure that the shirt fits well.  Fitting well means that it is not billowing out at the waist, or straining at the buttons.  It should form nicely around your body.  If your shirt doesn't, go to a men's clothing store, not a big box store, and buy one that fits you properly.
Choose a good tie, and learn how to tie a proper knot.  They can help you at the men's store.  It isn't difficult to learn how to do, and it is a very important detail to your look.  Not just any tie knot will do.  The knot that you use will be dependent on the type of shirt collar that you have chosen.  A skinny knot will not go with a wide collar, and a wide knot will not look right on a narrow collar.  Again ask the men's store clerk for some guidance.
I don't mind a bit of whimsy in a tie, as long as it was subtle and the knot was properly made.  I have been known to wear little airplanes, little Tiggers, and Batman ties to interviews.  The key is not use the over stated ones, but the ones where the whimsy is woven almost imperceptibly in to the tie.
Here is a great example of a subtle Star Trek tie:

DO NOT go for the skinny ties.  They are not the look that you want for the interview.

Women:
Your job is much harder than the man's.  I'm sorry, and I wish it wasn't so, but this is the way it is.  Women have to run the balancing act of looking nice with out flaunting any sexuality, but, at the same time, come across as very feminine.  Very tough.  The toughest people to deal with when it comes to how a woman dresses for an interview are other women.  I have seen candidates get eliminated because of the brand of shoes they chose to wear.  The men didn't notice but the women did, and they couldn't get their minds off of it.

If I were a woman, and I am not, take that in to consideration if you are...  I would wear a pants suit.  There are too many ways to go wrong with a skirt.  Length, tightness, cut, pleats, on and on and on.  Go with the pants.
Blouse should be business style, again color is up to you, but make sure it is subtle, can't go wrong with a nice light blue, or white.
Be careful of the buttons...  Too few and you won't be taken seriously, too many and you end up looking like you have something to hide, or that you are not a very confident woman.
Shoes...  I don't know anything about woman's shoes, but I do know that too much heel is a very bad thing. Very bad.  Also flats are a very bad thing.
Go for a shoe that has a bit of a heel, and is a closed, rounded toe.  Be sure that the heel is wide, not super thin.  The super thin ones are what got the woman above discarded...

Back to everybody:
Remember that how you dress is a reflection of your personality.  If you come in looking bad, or a detail is overlooked, that is how you will come across as behaving in your personal and professional life.

If the job comes down to two equally qualified candidates the one who presented himself better at the interview will get the job.

If you come in looking nice, put together and confident, you have an advantage over most of the candidates that will be interviewed, who will come in looking like they threw something on at the last moment.

Tuesday, April 24, 2012

Want To Have User Profiles, But Don't Want To Deploy MySites Yet??

Well, you don't have to!!
Many companies are understandably nervous about deploying MySites. BUT nearly every company wants the benefit of User Profiles. However, in SharePoint 2010, a MySites host is a requirement for Profile Synchronization. What to do?

First and foremost, you DO need to provision a MySites host for Profile Sync... It is a hard requirement and there is absolutely no getting around it. However, there is nothing that says you have to publish the MySites links. In an environment where I need to sync profiles, but do not want to deploy MySites, I normally create the MySites Web Application with a host header, then create the MySites host Site Collection inside that new web application. This gives me everything I need to create the User Profile Service, BUT, because I am using a host header, the URL is unavailable to the outside world until I register the host header with DNS.
I can provision my profile import without worry that a user will create a MySite before my enterprise is ready.

"BUT!!!!" Someone in crowd yells, "What about the MySite and MyProfile links that are created in the user's drop down menu?? They will point to dead links, and then users will call me about not being able to get to places that they shouldn't go!! How do I get rid of those links???"

Well, I am glad you asked!! Normally when I need to get rid of, or add, something in a SharePoint menu, I need to create a feature with a CustomAction or HideCusomAction element in the feature's elements.xml file. The scope of the feature would depend on exactly how deeply I want to apply the change to the menu. In this case I would want to apply it from top to bottom, so I would scope it at the Web Application level.
BUT in this case the trusty HideCustomAction element will fail us. We need another approach. No, don't go looking for the welcome.ascx control. It is better to leave that alone, unless you are doing some major revisions, then it is better to replace it all together.

After you provision your User Profile Service, User Profile Service Application, User Profile Synchronization Service (check out Spencer Harbar's site for an EXCELLENT step by step guide to this confusing process... then when you screw that up, Spencer wrote another post on how to fix what is wrong.), AND do your first profile sync, you go back in to the User Profile Application page and click on "Manage User Permissions" under the People heading. From there a little window will pop up:

And you will see that All Authenticated Users have rights to User Personal Features, Create Personal Site, and Use Social Features. What are these?
  • Use Personal Features
    • Contains Memberships, such as SharePoint sites and distribution lists; Colleagues, such as the My Colleagues list and colleagues recommendations; My Links; My Personalization links, such as personalization site pinning; and User profile properties.
  • Create Personal Site
    • Creates a My Site, which includes a personal, private My Home page and a public My Profile page.
  • Use Social Features
    • Includes social tags, Note Board, and ratings.
Unchecking the boxes turns off the links, and you have just provisioned your User Profile Service, but did not deploy MySites!

Thanks to How to SharePoint for images!!

Tuesday, April 10, 2012

SharePoint PowerShell Command Builder

I can't believe that I just found this... Microsoft's SharePoint PowerShell Command Builder. All of the SharePoint commands at your fingertips. No more hunting around for the correct command or the switches that run them. A great tool!!

Friday, March 23, 2012

Need a Connection String?

This handy little trick has helped me for years. I have used it so much and so often, that I forget that it really is almost a "hidden" part of Windows.

So, you need a connection string to a database, AND you would like to test that string before you plug it in to your application. Doing this is actually very easy. First right click on your desktop and create a new text file. Name the file what ever you want, but change the file extension to be ".UDL." This stands for Universal Data Link. Now double click on the file. This is what you will see:

The Provider tab will list all of the available providers installed on your computer. Choose the one you want. In this case we are going with the ODBC provider for SQL server.
The next tab is the Connection tab. This is what you see:

Here, you put in the server name, choose the type of authentication, and select the default catalog. The best part is that little button towards the bottom right "Test Connection." With the simple press of this button, a connection attempt is made using the settings and credentials you have provided. If the test succeeds, you are good to go, if not, well then you know you have a problem.

The advanced tab really isn't that interesting, you can set your impersonation level and other things if the provider supports that kind of thing, but really, it isn't vital to the success of your connection string. The really interesting tab is the All tab.

This tab has all of the settings you can tweak for your selected provider type. If you need to set an Application Type, you can do that here, time outs, Network Address, whatever you need to set here is the spot.
After you have everything set, and the test connection succeeds, click OK. That will save all of your settings. Then right click on the file and select "Rename." Change the file extension back to ".txt" Now double click on the text file. TA-Freaking-DA!!!

There is your tested, working connection string all ready for you to copy and paste in to your application.

Monday, March 5, 2012

Big Things Coming!!!

It seems as if the thing at Microsoft over the past 10 years or so was to sync major updates to their products every three years or so. So, in keeping with this new tradition, Microsoft is releasing a TON of products over the next year.
Take a look a what will be rolling out in the coming months:
  • Windows 8 Desktop
  • Windows 8 Tablet
  • Windows 8 Server
    • HyperV
  • Internet Explorer 10
  • IIS 8
  • Office 15
    • Word 15
    • Excel 15
    • Access 15
    • Visio 15
    • Outlook 15
    • InforPath 15
    • OneNote 15
    • Publisher 15
    • Office 365 Updates
  • SharePoint 15
  • FAST Search For SharePoint 15 (I haven't seen anything on this yet, however I assume that a new version would be released with SharePoint 15)
  • .NET Framework 4.5
  • Visual Studio 11

What do I find most exciting about each of the releases? Well, I haven't really done much other than read about enhancements, and new features, but some of the reading I have done had gotten me excited about many things.

Windows 8 Desktop and Tablet

I am really excited about Windows 8 for Desktops and Tablets. I think that the touch interface is going to revolutionize the notebook and tablet industry. Think about a Tablet, like the iPad that has all of the power and usefulness as a desktop computer, AND has the touch screen usability and app interface that you have come to love. Think of a notebook computer that can give directions and do text messages, yet still has a keyboard for typing documents. It all rolls in to one with Windows 8. I can't believe that Apple did not do something like this amalgamation before. They are the hardware company that builds their own OS after all. But they wanted to keep their OSes separate, and now they will be playing catch up with Microsoft, again.

Windows 8 Server

I am just starting my preview of Windows 8 Server. Right off of the bat, there are somethings that you notice about Windows 8. First and foremost, after you get past the new UI, you notice that there is a theme of Local Server and All Servers. Previous versions of Windows were designed to be islands of functionality. Servers could be linked together, but only as an afterthought. All services needed to be installed on each individual server, and then connections could occur. In Windows 8 the central theme is that there is more than one server that will be joining in the roles that you will be deploying on the server. So on servers that you deploy with GUI are designed to act as central hubs for the deployment and administration of other similar role servers. New is an interface that can report events from several servers, as well as an interface to administer these servers from.
Dynamic Access Control is a new feature that allows admins better control over the permissions inside of your file structure taxonomy. Rules and policies are much more friendly to layer on top of file structures.
There are so many changes to HyperV that I added it as a bullet under Win 8 Server. HyperV steps up with the big boys allowing for large clusters, fiber optic support, and many performance increases. Combine that with Live File Migration and HyperV addresses many of the advantages VMWare had over the Microsoft technology.
Microsoft listened, and stole, all of VMWare's advanced networking features and integrated them in to the new HyperV Virtual Network Switch. In 2008, the virtual switch was introduced to deal with multiple computers sharing a single networking interface. Outside of that, it really didn't do much. Combine it with RRAS and you really had some confusing and difficult configuration on your hands. Those days seem to be behind us with the implementation of port ACLs, private VLANs, per-vNIC bandwidth reservations, QoS, metering, OpenFlow support, VN-Tag support, and network introspection. I admit that I haven't had time to play with all of this stuff yet, but I have been very vocal with Microsoft on the lack of private VLANs on their virtual "switch" in Server 2008. Why call it a switch if it has none of the functionality of a modern network switch? Should have called it a virtual hub. It would have been more accurate.

Internet Explorer 10

IE 10 changes are mainly to incorporate all of the changes to the "Metro" UI that comes with Windows 8. Support for HTML5 is the big game changer, especially with support for Web Sockets. More on that later.
Performance was the name of the game with this release. Microsoft was looking to take down its major competitor, Chrome, and beat it by being the fastest browser on the market. Did they do it?? No. I don't think so. I'll test again when the RTM version is released, but the latest beta isn't nearly as fast as Chrome.

IIS 8

I am primarily a web guy and the first thing I did when I installed Windows 8 was to add the IIS role so that I could get a look at IIS 8. On the surface, there isn't a whole lot of difference. However if you do a lot of work with large site deployments, or if you host a good number of sites, you would definitely notice a difference!
The biggest change for "normal" users of IIS, the ones who run in house corporate intranet or SharePoint deployments, is going to be Application Initialization Module. Ever since the first version of the .NET framework users have complained that the first time the hit an ASP.NET site it takes forever to load. This is because a bunch of things happen behind the scenes to make the web site work. Check Just In Time compilation if you want to know more. (This should get you started)
This delay is supremely annoying, and the worst part is, the more complex the application is the longer the wait. Add that wait to all of the supporting services and applications, and the first time a user hits a complex site,like SharePoint, they could be sitting for quite a while. With IIS 8, Microsoft has finally solved the problem. Applications and sites can now be set to always run, essentially never allowing the worker processes to expire, and automatically starting up if the IIS services are restarted.
This is a big deal, and one that has to be undertaken with careful planning. One of the major reasons for JIT in .NET is to save on resources, and if you set all of your applications to always run, you will waste resources on applications that don't necessarily need to be running.
If you do a lot of work with SSL and certificates then you will be happy to know that Microsoft has done quite a bit to aid you with SSL. SSL can now use host headers so that multiple SSL sites can be run over the same IP address. IIS 8 also has a feature, called Central Certificate Store, that will allow you to store certificates in a centralized place, allowing for easier deployment as well as easing use in a cluster.
The last big change is for companies that have a lot of sites, and each site has a lot of custom configuration. This custom configuration of many sites makes the IIS XML configuration files, such as applicationHost.config, grow to be very large files. These large configuration files caused IIS to start very slowly and, in some cases, could even cause IIS service to time out during start up. IIS 8 is designed to load these large configuration files easily and quickly, making this particular problem a thing of the past.

Office and SharePoint 15

Not a whole lot is known about the next version of Office and SharePoint. Many things are speculated, but only a few are known for sure. For sure SharePoint 15 will have an "App" store. This means that companies can release "Apps" for SharePoint. This will allow users to connect directly to SharePoint via the Windows 8 "Metro" interface without having to go through a browser. I am interested about this particular piece of SharePoint 15, especially how it will tie in with the already familiar web interface.
Information Rights Management will FINALLY be a first class citizen in SharePoint 15, and will deploy as an Application Web Service. With all of the document retention and record center stuff put in to MOSS 2007 and SharePoint 2010 IRM should have been integrated in to SharePoint many years ago, BUT I guess Microsoft was too busy creating the ribbon interface to bother with something so obviously needed in ANY records management system. Sheesh.
Because SharePoint is being used more and more as a Knowledge Repository, a new module will be released that will make SharePoint a true Learning Management System. There are a TON of LMS out there, and I find it odd that Microsoft is only now trying to get in to the market. The real interesting thing to see will be if the current LMS companies will embrace SharePoint and move their functionality over to it, or if they will see SharePoint as a threat and attempt to compete with it.
It is also widely speculated that SharePoint 15 is being built on the 4.5 framework. I'll get in to this a bit more below, but with the 4.5 framework's heavy emphasis on HTML 5, could it be possible that Microsoft thought ahead and built SharePoint 15 using Web Socket technology??? That would be super cool!!

Not a whole lot is known about Office 15. What is known for sure is that all of the office apps will be created to actively interface with the "Metro" UI. That means that their UI will specifically be developed so that you can use the applications with just your fingers. I don't know if this will do away with the ribbon, but it just might.

.NET Framework 4.5

Lots of really cool updates to the .NET Framework 4.5. Of course 4.5 will support the creation of Windows 8 apps and the Metro UI. I don't think anyone used Microsoft Touch to do anything at all, so it should be a relatively new API to play around with. New to us anyway.
The Managed Extensibility Framework (MEF) becomes a first class citizen in the new framework, moving up from an add on in framework version 4.0. (check this out for information on MEF)
Changes to ASP.NET surround HTML 5. This makes sense, as IIS 8 now supports HTML 5. I see what you did there Microsoft... Very sneaky!!
The last super cool thing in the 4.5 framework is additional support for parallel computing. I haven't done any work with parallelism, but I have always been intrigued by it. Check out this blog for the skinny on what is new in the 4.5 framework

Visual Studio 11

With the release of a new framework, a new OS, a new UI, AND a new version of SharePoint, there must be a place where developers can create all sorts of new stuff for them. In short a TON is new in Visual Studio to accommodate all of the new developer stories for the new products. I really don't want to list them all here, So you can go here to check out all the cool new stuff.

It's a brave new world out there, and, if you are smart, you will begin to look in to how you can learn about the new stuff that will soon be in great demand. I am just upset that I will have to take all of the tests over again... Maybe I will wait a year or so this time... but I know I won't...

Tuesday, January 10, 2012

Working From Home

I do a lot of work from home... In fact the last several contracts I have had I have worked out of my home office. Before that I worked for a company 400 miles away as a remote employee. All told I have about two years of experience working from my home. It is an interesting situation, and I am going to outline some of my personal findings.

Who Can Work From Home?

Working from is a very strange dynamic. If you want to work from home first and foremost, you MUST be a self motivated person. You have to be the person who does not need outside accolades to keep you moving. The completion of a job and self excellence must be your major motivators, or you will not succeed working from your house.
You have to be the kind of person who is OK with being alone for very long periods of time. In the same vein, you have to be the type of person who doesn't mind that the only people they interact with in person are their family members.

Loneliness

When you work from home, loneliness is a constant theme in your life. When you work in an office, there are always people around and things to do. If you get crazy and just want to goof off for a bit, you can always find someone to talk to for a bit, or you can find someone making coffee, or you can just do something other than work. At home, your distractions are much more dangerous, and there is nobody around. When you get up to do something besides work, there is nobody around. Nobody.
You miss all of the daily things that happen in people's lives when you work from home, however you will know that these things are happening through your normal office email. You can't see Bob's new car, but you will be invited to take a look at it at 10am today!! You won't taste Marry's famous lasagna, but you know what room your coworkers are eating it, and you will see all of the thank you and accolade emails that come afterward. You won't see Jon and Sally's new baby that they brought in to meet everyone. And you certainly won't go to HuHot for Jenifer's birthday. You won't be there.

Out of Sight Out of Mind

If you are set on moving up in your company, you will want to avoid Teleworking like the black death. Even the lazy guy in the mailroom will get more exposure and face time with the bosses than a Teleworking employee. You aren't there. Everyone forgets you even existed. When the bosses are thinking about who to give that new kick ass position to, they will not be thinking of you. Even if you turn in your work on time, and it is awesome, you will not be considered.
This goes for the cherry new projects as well. You aren't there, you won't be called in to the spur of the moment meeting where the project suddenly gets assigned. The only meetings you will be a part of are the ones where you are scheduled to attend and they actually remember to call you.

Dangerous Distractions

Home has the most dangerous distractions. That is where your TV is. That is where your bed is. That is where you keep all of the stuff for that hobby that you love so much. All of that stuff is just a couple of steps away. A distraction at work, is still at work. It doesn't really distract you for long. A distraction at home, will suck away at your time for hours.

Unrealistic Expectations

People, especially managers, will expect more out of you because you are working from home. It is important that you manage expectations so that you can deliver your work on time and with consistent quality.

How to Succeed Working From Home

It sounds stupid, but it is very difficult to do. To succeed working from home, you have to treat your home office like you do your office at work. You have to treat your work time specifically as WORK time, and you have to let your self off of work at the proper time as well. It is just as easy to work too much, when you work from home, as it is to work too little. An example I give is that I used to get up in the morning at about 6am, work until about 7am, go work out, come back home start working again, break just long enough to make a sandwich, work until my wife got home at 6pm, hang out with her for a while, then go back to work from about 8pm to 10pm or later then go to bed. On the weekends, I would get bored, and work for several hours. In the end I was working 80 hours or more a week. That is not good for you.
This is what I did to keep sane while working from home:
  • Create a set work schedule, just as you would in the office. Show up on time and LEAVE on time.
  • Constantly send emails and instant messages out to managers and project leads to make sure I was working on what needed to be worked on, and that I was kept in the loop with all decisions.
  • Cut out all dangerous distractions while at work. Treat work time just as I would in the office. If you have kids or pets, they have to go on the same schedule as they would if you were in the office. They are very dangerous distractions.
  • Time and expectation management is vitally important. Give yourself enough time to do your projects working a normal 8 hour shift. Manage expectations with management to make sure that they are not asking more of you because you are working from home.
  • Make time to do something outside the home at some point during the day. In other words, take a lunch. Go talk to somebody. Go do something. Personally, I go to my gym everyday. I have a group of guys that I work out with, and that I can talk to. It gives me some personal contact and keeps me sane.
  • Embrace the fact that you will not be there for the little things that happen in the office, however make an effort to go to the events that you are invited to for the major events. Birthdays of teammates, office project celebrations, retirements, new employee get to know you lunches, these kind of things help you keep connected to your office and keeps you in everybody's mind.
  • Treat your work time just as you would if you were in the office. If you have to run an errand, let your boss know, just as you would if you had to leave the office.
  • If you are sick, take a sick day. Don't work on the days where you wouldn't go in to the office. Not only do you let your body recover, you let your soul recover as well, and you will turn in your best work.
  • Keep the same grooming habits that you had when you went in to the office.
    • Get up, and take a shower
    • If you shaved everyday going in to the office, shave everyday.
    • I know that women may have an elaborate makeup scheme that they would do for work, you don't have to go that far BUT you should do the minimum makeup. If you have to go somewhere during the day it will cut down on your "get ready" time, AND you still want to keep a routine that prepares you for your work day.
  • Get dressed for work. Do NOT start working in the clothes you wore to bed. Get dressed. It can be more casual than what you would wear in to the office, but get dressed. You want to create some separation between your home life and your work life and getting dressed is a BIG part of it.
Working from home can be very rewarding, but there are many pitfalls. Know that if you fail in your teleworking arrangement, it won't be just you who suffers. One bad apple will spoil teleworking for everyone. Supervisors and management HATE teleworking. It is understandable, as they are controlling type of people and teleworkers are very difficult to control. I have seen entire teleworking programs get scrapped because of a single person who took advantage of the freedom. Do the right thing by everybody and recognize that if you can't resist the dangerous distractions, STOP teleworking.

Allowing remote employees is also a big plus for companies as well. The biggest advantage is that when you are hiring for a position, you no longer have to worry about talent in your specific geographical area, rather the entire world is available for your hiring. Of course, there are time zone considerations to think about. If you are on the east coast and your employee is on the west coast, contact and meeting times have to be specifically mapped out.