End-To-End SharePoint 2010 User Profile Photos & AD
During a recent WSS3 to SharePoint Server 2010 upgrade, the need arose to move roughly 600 user photos into Active Directory and implement user profile photos for SharePoint. While user photos existed, they were stored in a SharePoint library which would be sunset following the build of the new 2010 environment. Additionally, the user photos needed to be available for a custom web part solution highlighting employee birthdays and anniversaries. Initially, thoughts were to follow the old model and store the photos in a picture library, but with the organization’s IT strategy and upcoming deployment of Lync 2010, using Active Directory as the central repository for photos made the most sense.
Step 1: Getting Photos into Active Directory
There’s a ton of blog posts and articles available on how to use PowerShell and Exchange tools to import photos into Active Directory. Normally I’m the first person to jump on the PowerShell bandwagon, but in this instance there are a few constraints. Pushing thumbnails to AD with this method requires your images to be less than 10kb in size, and a fixed size of 96 x 96px. If you intend to reuse these images outside of Exchange or Lync, you likely want a higher quality of image. You certainly don’t want to be using unedited photos right out of a digital camera, but something more along the lines of a 300px image is going to give you greater quality and reuse.
Due (primarily) to this constraint, we opted to use a third party tool that gave a little more control over the image format and size, while still offering a bulk load ability. We grabbed the trial version of AD Photo Edit from Chris Wright, and put it through it’s paces. The trial lets you execute just 5 users at a time, but once we validated it would do what we wanted we purchased a copy of the full version. At just $49, it’s significantly cheaper than the manual effort of doing this one at a time for 600 users. This particular tool had the ability to specify the naming format of our photos, so we could point it to the folder of 600 photos and it would automatically reconcile to the correct AD user and import the photo. Once you confirm that your photo names conform to a naming convention that matches an AD property, you’re off to the races.

Step 2: Mapping the AD Photo into SharePoint 2010
Once you’ve pushed all of your photos into Active Directory, you must tell SharePoint they are there. By default, SharePoint will not just grab the photos from AD. Head into Central Administration and navigate to your User Profile Service Application. From the main UPS screen, pick “Manage User Properties” and edit the “Picture” property. Set the “Edit Settings” radio button to not allow users to change their photos, ensure that your “Source Data Connection” is set to your Active Directory UPS connection, set the “Attribute” to “thumbnailPhoto” and the “Direction” to “Import”. Finally, click “Add”, then “OK”.

Since UPS didn’t know about this field previously, we must now perform a synchronization and allow UPS to fetch the data for this newly mapped field. From your User Profile Service Application, click “Start Profile Synchronization”, select a full synchronization, then click “OK”. This first synchronization since the field was mapped must be done as a full sync because that field previously was un-mapped. During an incremental synchronization, UPS will update the values for all mapped fields, but it will not look for new ones. Once a full sync completes, incremental will be sufficient for future updating of the individual account details.

If you think back to step one, you’ll remember that we chose this method because wanted a better quality of photo than a 10kb 96px image. As SharePoint will be looking for a specific size to use in thumbnails and user profile pages, we must now tell SharePoint to generate the appropriate sized images from the original in Active Directory. Before you can perform this task, ensure that the user you’re logged in to the SharePoint server with has “Full Control” on the User Profile Service Application. From the main “Manage Service Applications Screen”, select the User Profile Service Application, and then click “Administrators”. Confirm that the account you’re logged in as has the “Full Control” role, and if not add it now.

Next, open a new PowerShell session and run the following commands:
Add-PSSnapin Microsoft.SharePoint.PowerShell -EA 0 Update-SPProfilePhotoStore -CreateThumbnailsForImportedPhotos 1 -MySiteHostLocation http://mysites
The first command simply loads the SharePoint PowerShell Snapin if you haven’t already loaded it. The second command physically tells UPS to iterate through the photos in the user profiles and generate the thumbnails if they don’t already exist. Obviously if you’ve bulk loaded a large number of photos this will take a few minutes. Be sure to include the correct path to your MySite host. If you get an error about an object reference not set to an instance of an object, you likely have a permissions issue, and the user you’re logged in as doesn’t have full control of UPS.
Once this operation completes you should see user photos in SharePoint. Note that the best way to verify this is to look at the actual personal profile (person.aspx). Performing a search will still show you the old photo (or no photo) until the next incremental search crawl takes place on the content source with your sps3:// provider mapped.
Step 3: Ongoing Maintenance
This is fabulous, I’ve bulk loaded my 600, 1000, 2000 users and we’re up and running; but what happens when I change 10 of my photos tomorrow, or process a new hire next week? First of all, you’ve got to put that user’s photo in Active Directory. Many of the tools that offer bulk loading of photos will also allow you to manage one-off uploads or additions. Once the photo has been added to Active Directory, SharePoint User Profile Synchronization will grab that image on it’s next incremental synchronization (typically nightly). The piece that is most easily forgotten is this: UPS may have that image, but it cannot use it until the thumbnails are generated by running the Update-SPProfilePhotoStore cmdlet in PowerShell. Essentially, that cmdlet needs to be run after every UPS sync completes to ensure that the current photo is actually displayed.
The easiest way to accomplish this is to setup a scheduled task that calls your PowerShell script. First things first, create a new PowerShell script containing the following commands, and save it (ie: C:\Solutions\Update-SPProfilePhotoStore.ps1):
Add-PSSnapin Microsoft.SharePoint.PowerShell -EA 0
Update-SPProfilePhotoStore -CreateThumbnailsForImportedPhotos 1 -MySiteHostLocation http://mysites
$event = New-Object System.Diagnostics.EventLog("Application")
$event.Source = "SharePoint"
$infoEvent = [System.Diagnostics.EventLogEntryType]::Information
$event.WriteEntry("User Profile Service Photos Updated", $infoEvent, 5000)
Note that the first two lines of this script are identical to our previous execution of the Update-SPProfilePhotoStore cmdlet. The lines after it log the event to the system’s application log using a source application of “SharePoint”, an event description of “User Profile Service Photos Updated”, and an event ID of 5000. We add this simply as a way of verifying that the PowerShell script is actually being run (and at the correct time).
With the script saved, head over to Windows Scheduled Tasks, and create a new task. Set the task to execute a program and provide the path to powershell.exe as well as your script:
c:\windows\system32\WindowsPowerShell\v1.0\powershell.exe "& 'C:\Solutions\Update-SPProfilePhotoStore.ps1'"
Schedule your task to run even if the user is not logged on, and ensure it happens sometime after the nightly User Profile Synchronization Timer Job. For example, if your UPS job runs at 1:00 AM, you may want to schedule your task to fire at 3:00 AM, giving ample time for UPS to finish processing before user profile thumbnails get updated. You must also ensure that the task is executed by a user that has “Full Control” to the UPS service application, or the script will fail to process.
SharePoint Branding & CSS Specificity
We all know that best practices SharePoint branding avoids the use of !important in your CSS, but how do you correctly control the specificity of your CSS to mitigate the need for it?
The order of operations for your CSS depends on a number of factors, including the loading order of the stylesheet, the order of the styles within that stylesheet, and lastly the specificity of the style. SharePoint allows us to use the <SharePoint:CssRegistration> tag to help provide greater control over the loading order of stylesheets and ensure that your custom style sheet is loaded after all of the core ones. This allows us to easily override the out of the box classes easily, since styles loaded later will override matching properties of identically named styles loaded previously.
I recently ran into a problem when branding SharePoint 2010 MySites for a client. The SharePoint core CSS has classes for branding the “Add New” links on the bottom of list/library web parts (.ms-addnew a:visited, .ms-addnew a:active, .ms-addnew a, etc.). Simple enough, my custom stylesheet that is loaded after all of the core ones overrides the link color to my desired color. But on the MySite, there’s another core stylesheet (portal.css) that gets loaded as part of the layout of the MySite. The CSS link is actually rendered inside the main content placeholder, not in the head. These same few styles are redefined in portal.css, and since that is loaded later, it overrides my override of the core style.
Some people might now stand up, voilla… this is one of those cases where “you HAVE to use !important”, but this is not the case. Remember that little thing called specificity? A style loaded later will not override a previous style if that previous style has greater specificity. Since .class .class element is more specific than .class element, the browser will always choose a more specific style over a newer one.
This being said, crack open your custom master page, and find the opening <body> tag. If your masterpage has been derived from the default out of the box master, you’ll likely see that the body tag has a class attribute with a value of “v4master“. Add a second value to the class attribute (ie: class=”v4master customBranding”). We can now define more specific styles using the .customBranding selector. Using .customBranding .ms-addnew a will always take precedence over the .ms-addnew a in portal.css purely because it’s more specific than any styles already defined in the core stylesheets. No !important here.
User Profile Services via Client Object Model
I was recently thinking through ways to help drive adoption of an intranet and engage users to explore the various capabilities of the system. One thought was to alert users if they have not supplied a profile photo, or a short bio in their MySite. Sure we could do this with web services, but I thought I’d figure out how to do it with the client object model with ECMAScript. After a lot of searching, I kept finding blog posts that said I was out of luck and there was no way to query User Profiles via the client object model. At a high level, that assessment is correct, but what we can do is query the user info list of the current site.
When I first started this, none of the test users in my lab had a profile picture, so I added one and found that my script kept returning a null object instead of my picture. The hidden Easter egg here is that the site’s user info list isn’t updated in real time. If you head over to Central Administration -> Monitoring -> Review job definitions and dig down the list you’ll find a job called “User Profile Service Application – User Profile to SharePoint Full Synchronization“. This timer job will execute every hour and synchronize the properties of your User Profile Services to the site user info list, so the picture that was set on the MySite is now accessible via the user info list.
First things first, we need to find out the ID of the user that’s currently viewing the page (this is the physical numerical record of the user in the site’s user info list, not the login username). Credit to Mike Oryszak (@next_connect) and his blog post on using the status bar to display active workflows for getting me in the right direction on this piece. We’ll start out by grabbing the current web context and fire off that query. If the query is successful in executing, it’ll call the onUserSuccessMethod function.
var context = null;
var web = null;
var curUser = null;
function getUser() {
context = new SP.ClientContext.get_current();
web = context.get_web();
curUser = web.get_currentUser();
curUser.retrieve();
context.load(web);
context.executeQueryAsync(Function.createDelegate(this, this.onUserSuccessMethod), Function.createDelegate(this, this.onFailureMethod));
}
Now that we have our context we’ll create a variable called user and assign it to the current user object, and call our loadProfile function to do the profile query.
function onUserSuccessMethod(sender, args) {
var user = web.get_currentUser();
loadProfile();
}
The loadProfile function defines the user info list, builds the CAML query to get the record for the current user, and fires that query off. If the query is successful in executing, it’ll call the onProfileSuccessMethod function.
function loadProfile() {
context = SP.ClientContext.get_current();
web = context.get_web();
userInfoList = web.get_siteUserInfoList();
camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml('<View><Query><Where><Eq><FieldRef Name=\'ID\'/><Value Type=\'Number\'>' + curUser.get_id() + '</Value></Eq></Where></Query><RowLimit>1</RowLimit></View>');
this.listItems = userInfoList.getItems(camlQuery);
context.load(listItems);
context.executeQueryAsync(Function.createDelegate(this, this.onProfileSuccessMethod), Function.createDelegate(this, this.onFailureMethod));
}
Now that we have the result set from our query (in the form of a listItems object), all we need to do is grab the first (and only item), this will be on index 0 in the array, and analyze the picture field to see if there’s a value there or not. If there is a picture object, we’ll grab the Url to it and save it in a new variable (pictureURL) just in case we want it. If there is no picture object, we’ll fire off a call to SP.UI.Status to add a new status bar telling the user they don’t have a photo, with a link to their profile where they can add one.
function onProfileSuccessMethod(sender, args) {
var item = listItems.itemAt(0);
var picture = item.get_item('Picture');
if (picture) {
var pictureURL = picture.get_url();
} else {
noPicture = SP.UI.Status.addStatus('Profile Photo', 'You have not added a profile photo to your account. <a href=\'http://mysites/person.aspx\'>Add one now!</a>');
SP.UI.Status.setStatusPriColor(noPicture, 'blue');
}
}
You’ll notice that both getUser() and loadProfile() have references to an onFailureMethod function, in the event that our query fails. This will be a simple function to just alert our error.
function onFailureMethod(sender, args) {
alert('Error: ' + args.get_message() + '\n' + args.get_stackTrace());
}
Now that we’ve got all of our functions written, all we need is a simple call to our getUser() function (after the core SharePoint JavaScript has loaded, of course).
ExecuteOrDelayUntilScriptLoaded(getUser, "sp.js");
Putting it all together:
My “Michael Greene” account has a user profile image, so we just see normal SharePoint with no profile photo alerts.

My “Setup Account” account does not have a profile image, so SharePoint prompts us that we should add a photo.

Due to the fact that we have to wait on the timer job to run and update the user info list with the new photo, it’s possible that the user could add a photo then still see the prompt telling them they haven’t. In a true application of this, we could add a condition to check the Modified time of the user info list record to see if the record has been “updated” in the last hour, to avoid that false positive. Only if the record has been updated within the hour and has no photo, should we alert the user.
People Picker Woes
On my last project I ran into the chasm of the SharePoint 2010 people picker resolving to users across multiple domains. There’s loads of blog posts out there (first, second, third), plus the Microsoft documentation, but there’s one important piece missing to all of these posts.
In my scenario, corp.domainA.com contains all of the users (~1,600 in this case), and domainB.com contains all of our SharePoint servers, service accounts, etc. Now, the documentation states that if you have a two-way trust in place, then you don’t have to do anything special to make SharePoint resolve those accounts within the trusted domain. In this scenario, a two-way trust is in place, but the trust is between the root (domainA.com), and domainB.com. I’ll preface this with the fact that I’m not an Active Directory guy, but my “expectation” would be that if the root domain is trusted, the child domain is also trusted. That seems to be the case, but SharePoint will not resolve down to “corp\user” accounts when searching for a user in the people picker. My assumption is that despite the trust, SharePoint doesn’t dive into a child domain of a trusted domain during the query, unless you tell it you want it to.
The solution is to use the peoplepicker-searchadforests STSADM operation (yes, this is one things that you still have to use STSADM for–no PowerShell equivalent yet). The other thing to note, which I didn’t see mentioned in any of the blogs or documentation I found, is that you must run the STSADM operation against every URL for your web app. So if you have one or more Alternate Access Mapping setup on your web application, you must run the STSADM operation against those AAMs.
So in our case:
stsadm -o setproperty -pn peoplepicker-searchadforests -pv domain:corp.domainA.com;domain:domainB.com -url http://intranet stsadm -o setproperty -pn peoplepicker-searchadforests -pv domain:corp.domainA.com;domain:domainB.com -url http://intranet.domainB.com
Create SharePoint Groups with PowerShell
It wasn’t until I looked into this tweet that I realized there was no “New-SPGroup” type cmdlet that ships with SharePoint out of the box. Instead, we have to call the SiteGroups.Add operation on the web where we want to make the group. While this isn’t terribly intuitive for people new to PowerShell, this post should help to walk you through it.
Firstly, we’re adding groups to webs, not sites, so we need to identify the web where the group is going to exist. While groups are available site-wide, they’re actually stored at the web level, which explains why when you create a subsite (a web), you get the three default groups created. Yes, I realize it’s confusing that a web has a property of “SiteGroups”, and a site doesn’t–but that’s just the way it is. Before we can do anything, we need to create a variable and save our web object into it.
$web = Get-SPWeb http://intranet
In addition to a title and description, we also need to specify the owner and any members of our group when we call the SiteGroups.Add operation; those users must be valid SPUser objects, not a “domain\username” string. To keep things simple for this example, let’s assume they’re the same person, since the owner is typically also a member of the group. We’re going to create a user variable, and pipe our web object to the Get-SPUser cmdlet (with a user string). This will tell PowerShell to iterate through every user in our web until it finds the one we’ve specified, and save that SPUser object to our user variable.
$user = $web | Get-SPUser "domain\username"
Now that we have our user captured, we can go ahead and call the SiteGroups.Add operation, passing to it the title of the group, the owner of the group, the members of the group, and the description of the group (in that order).
$web.SiteGroups.Add("Group Name", $user, $user, "Group Description")
Now it’s a simple matter of heading on over to your groups list and validating that it’s there.
If, like Rebecca, you had a lot of these to do, you could store the details in a CSV file and handle your inputs from there. Let’s assume you had a CSV with columns of “Web”, “GroupName”, “User”, and “GroupDescription” that was stored in C:\Groups.csv, we can make a simple script to loop through all of the lines in the Groups.csv file and create each group.
$groups = Import-CSV c:\Groups.csv
foreach ($group in $groups) {
$web = Get-SPWeb $group.Web
$user = $web | Get-SPUser $group.User
$web.SiteGroups.Add($group.GroupName, $user, $user, $group.GroupDescription)
}
Dynamic Master Page Logic
I recently had a need to set a specific master page based on a query string. In this particular example, a SharePoint page needed to be loaded within a frame which presented the need to load a custom master page without navigation, header, ribbon, etc. Initially, I took the approach of simply turning off the unwanted elements with CSS but this approach means those DOM elements are still loaded behind the scenes, even if they’re hidden. This produced a higher than desirable load time and I went off looking for a way to set the master page within my page layout, but doing so in such a way that the master used when the page was “framed” would only be used in that scenario, as opposed to all the time. The solution turned out to be quite simple…
On initialization, the page will grab the MasterPageFile property as set by the web’s configuration. Within my custom page layout, I added the following simple script block to override the default OnPreInit of the page and set my custom master.
<script runat="server">
protected override void OnPreInit(EventArgs e) {
base.OnPreInit(e);
if (this.Request.Url.AbsoluteUri.Contains("frame=true")) {
this.MasterPageFile = "framed.master";
}
}
</script>
I’m using the AbsoluteUri property to check the URL for my “frame=true” reference, which is what ultimately triggers the change in master page. If you go to http://lab/Pages/Test.aspx the Test.aspx page will be rendered using the master page the site is configured for. If you go to http://lab/Pages/Test.aspx?frame=true it will be rendered using the “framed.master” master page.
For some additional background, you can take a look at this post by Eric Overfield, and this post by Juan Larios.
Custom CSS and SharePoint Branding (The Right Way)
There was a post on Stack Exchange this morning that struck a bit of a nerve with me. I don’t aggravate easily, but I’m a firm believer that the purpose of public discussions is to promote best practice methods and share that knowledge with people that have asked for answers to their problems. When best practice approaches were suggested by James Love (@jimmywim) and myself, we were practically attacked by people insisting that their practices were the way things should be done. I’m not naive–there’s a lot of people that make a lot of bad decisions–but the purpose of the community should be (and largely is) to help share the right way things should be done. The size of the deployment or scope of the customizations shouldn’t be an excuse for making bad decisions and following bad practices. At the risk of beating a dead horse, this is the best practices approach for deploying custom CSS styling in SharePoint (and why you shouldn’t be using these other methods).
Suggested Method 1: Write your own custom CSS selectors, and put !important on every selector.
The first suggestion on Stack Exchange was that you had to put !Important on all of your selectors to override any SharePoint styles. If you find that you need to use !important to make your CSS take priority over the out of the box CSS, either your selectors are wrong, or your custom CSS is being loaded before the core CSS. When CSS is rendered, the highest priority selectors will be those that are the last to be loaded (unless an !important declaration exists). Not as big of a deal here but in terms of the actual order of operations, your browser will also treat any inline style attribute as a higher priority than your stylesheet (be it embedded or linked). SharePoint’s core CSS uses nested selectors, so the selectors for your custom CSS must follow suit. If SharePoint us using “body .s4-ca” and you make a custom selector called “.s4-ca”, the browser will render the more specific selector since it has a higher priority. Using !important is a bad practice (for all CSS/web development, not just SharePoint), because it drastically changes the approach you need to use to override that selector/class later. Finally, you need to think about cross-browser compatibility. In SharePoint 2010, this absolutely applies. In a lot of cases, you must write a style one way, then write a modifier to make that style render correctly in older browsers. Flagging !important on all of your styles makes this a real mess.
The use of the !important flag is simply a lack of understanding for how the browser will prioritize CSS markup. There’s a lot of resources out on the web that cover this, but in a nutshell: more specific selectors have priority over less specific ones, and in a scenario where two rules have the same weight, the last one specified will have a higher priority. Use debugging tools such as those in Internet Explorer or the ones within Google Chrome or the Firebug extension for Firefox to identify the selectors that SharePoint uses. Personally, I prefer Chrome because the developer tools are included without the need of an add-on, and you can make real-time changes to the CSS which are rendered in the browser as you edit (making it an excellent development companion when authoring new CSS). Once you know what selector SharePoint is using, use that same selector. Lastly, make sure that your custom style sheet is being loaded into the master AFTER SharePoint’s core files because remember, when rules have the same weight, the last one loaded takes priority. This ensures that your styles take over, without filling your markup with !important flags.
Suggested Method 2: Just modify the core files in SharePoint Designer.
Obviously it’s a bad practice to edit any core files, be it Master Pages, CSS or JavaScript. A particular user was adamant that it was an acceptable method because when you customize a file in SharePoint Designer a local copy is created just for that site, so you’re not affecting any other sites on the farm. While this is true, updates to core files can still be made during service packs or patches, leaving your customized file behind. Granted your custom master pages are never going to be updated, but keeping the core files uncustomized ensures you have a supported rollback plan–something you obviously loose when you start customizing the core files. There’s a lot of talk about SharePoint upgrades these days, and this is one of the things that will potentially make your upgrade an utter nightmare. Sure, you can go in and reset all of the customized files to their definition, but should you have to? Making a copy of a file takes all of a couple seconds and it will make your life 10 times easier if you need to reset to vanilla SharePoint. Can you just edit files, yes. Does it work, yes. Should you do it, no.
Best Practice Method 1: Branding Deployed via Solution
Hands down, the best practice for branding deployment is a Visual Studio solution packaged into a WSP and deployed to the farm. This method makes maintenance and updates to your branding solution easier, gives you more robust change control, and integration with source control (such as Team Foundation Server). Deployment via solution also makes your branding reusable between multiple site collections. Unlike modification of files in SharePoint Designer, you no longer have to touch 10 master page files to brand 10 sites; simply activate the solution. If you need to deploy an update to your solution, the update will automatically be pushed to each site where the solution is active (assuming you haven’t customized the files in SharePoint Designer). A correctly built branding package will also give you the capability to rollback to vanilla SharePoint with just a few clicks. It may not seem like an important thing now, but when you go to upgrade to the next version of SharePoint you’ll be glad you can do that.
Best Practice Alternative: SharePoint Designer
SharePoint Designer is a tool that has a lot of functionality. Yes, you have the ability to modify master pages and things of that nature, but it doesn’t mean that you should. Simply because you can do something doesn’t make it a best practice. That said, in certain environments you may not have the ability to deploy a solution; either due to a lack of staff with the know-how, a policy restriction, or lack of the necessary access to the server. In those scenarios (and only in those scenarios) should SharePoint Designer be used for branding. If you must use SharePoint Designer, you should follow some common-sense guidelines, one of the fundamental ones being to not modify out of the box files. If you need a custom master page, make a copy of the v4.master and work from that.
Where Should the CSS Live?
The purpose of a stylesheet is to promote reuse. It doesn’t make much sense to include your styles in every page, and in SharePoint 2010 where we have standard and minimal masters, it doesn’t make sense to duplicate your common styles by including them in each master page. Your stylesheet should be an external file, stored where it can be used by all instances of the masterpage(s) using them. If you’re deploying your branding using a solution, then most likely these files should live in a folder within the 14 hive. I’m personally not a fan of putting them in the style library, since (despite being able to manage it from the 14 hive), your browser will treat them as separate files for each site collection. This means that my browser will re-cache my stylesheet for each site I go to, even though they’re exactly the same file. If it’s 10 lines of CSS then this is negligible, but if I’ve got a few hundred it makes a difference.
Continuing Education
I’m not one of those people that usually promotes books, but if this topic is something that you wish to brush up on I suggest you get your hands on a copy of Randy Drisgill’s (@drisgill) book. He covers (in detail) processes for branding as well as the issue of CSS priority.
Demo
James created a great screencast that shows the process for correctly referencing external CSS files using the SharePoint:CSSRegistration tag. Check that out below, and visit his blog at http://e-junkie-chronicles.blogspot.com/.
Validate Application Pools & Identities
I ran into a scenario where I needed to validate what application pool and identity a particular service application was running as. While you can do some round about poking through the UI or through IIS, it’s also pretty simple to grab this information using PowerShell.
Service Applications
First things first, we need to grab a list of all of our service applications. We can skip this step if you already know the name of your service application.
Get-SPServiceApplication
Get-SPServiceApplication will output a list of all service applications configured on your farm. You’ll notice that by default you see three columns (DisplayName, TypeName and Id). As a result of the three columns, PowerShell will truncate the contents of the columns to allow them to all display. This means that if you have long service application names, you probably won’t see the full name. To get around this, we can specify the column(s) we want to see.
Get-SPServiceApplication | Select DisplayName, Id
Once you’ve identified the service application you want to validate (or if you already knew it), we can create a variable containing all of the properties for that particular service application. The “Identity” parameter should match the DisplayName of the service application.
$serviceApp = Get-SPServiceApplication -Identity "My Service Application"
Alternatively, you can also use the GUID to select the service application.
$serviceApp = Get-SPServiceApplication 00000000-0000-0000-0000-000000000000
Now that we have our $serviceApp variable containing all of the properties for our service application, we can view (or set) any of the available properties. The Get-Member cmdlet allows us to view a list of all objects, properties and methods that are children of the current object. In this example, it would list all of the objects, properties and methods of our selected service application.
$serviceApp | Get-Member
We can now determine the application pool and the identity of that application pool by viewing the ApplicationPool property of our service application.
$serviceApp.ApplicationPool
Web Applications
Much like we did with service applications, we first need to identify the web application that we want to work with.
Get-SPWebApplication
Get-SPWebApplication will output a list of all web applications configured on your farm. The nice thing is that web applications are a little more intuitive because we can use the URL of the web application to identify it, and that’s almost certainly something you’re going to know off the top of your head. Once you’ve identified the web application you want to validate, create a variable containing that web application.
$webApp = Get-SPWebApplication http://mywebapp.corp.tld
Just like we did with our service application, we can use the Get-Member cmdlet to list all of the objects, properties and methods of our web application.
$webApp | Get-Member
We can now determine the application pool and the identity of that application pool by viewing the ApplicationPool property of our web application. Note that Microsoft hasn’t been this consistent throughout SharePoint as a whole, and there’s a lot of cases where you’ll find differences between property names on objects where you’d think they would be the same. Learn to love the Get-Member cmdlet, which will always show you what you’ve got to work with.
$webApp.ApplicationPool











