Monday, December 17, 2012

Third Party Active Directory Password Management Web Parts for SharePoint 2010


As part of a project that I am currently working on, we need to allow users to manage their own Active Directory passwords on a SharePoint 2010 extranet. Ideally, the users will be able to change their password, reset their password (e.g. in case it is forgotten or expires), and be alerted as to when their password will expire.

After much Googling, I limited the options of possible Active Directory password management web parts for use with SharePoint 2010 to six. They all require licensing and generally break out the functionality into separate web parts. Below are my notes with little editorial. I'll eventually update this post with what I chose and why.

1.     Bamboo Solutions
i.            Password Change
a.   "Give your internal and external SharePoint users the power to change their SharePoint account passwords through SharePoint. No need to build a separate Web application to complete a simple, but essential security task. With the Bamboo Password Change Web Part, users can change their password on-demand and still comply with the defined password policy."
b.   Cost: $795 per server license; 30-Day Trial
c.    Comments: Probably the nicest looking of the bunch with a password strength indicator.

ii.           Password Reset
a.   "With the importance of login security growing and password requirements increasing, it is becoming easier for users to forget their passwords. With the Password Reset Web Part, users now have the ability to submit their own password reset requests through SharePoint, no longer requiring IT administration assistance. With two types of ID verification available, users can reset their password by email confirmation or by answering predefined security questions (Active Directory accounts only)."
b.   Cost: $795 per server license; 30-Day Trial

iii.          Password Expiration
a.   "Are you enforcing expiration of Active Directory Service account passwords, and as a result, your external users are having difficulty logging in to SharePoint due to expired passwords? Dramatically cut down on the overhead costs of troubleshooting login issues with the Password Expiration Web Part. The Password Expiration Web Part provides an early warning system for SharePoint users when their password is about to expire."
b.   Cost: $795 per server license; 30-Day Trial

2.     SharePointBoost
i.            Password Change and Expiration
a.   "Passwords management can represent a big deal of time and energy for Administrators. This password changing web part delegates most of the work to Users and takes in charge all notifications and confirmations. In this way Administrators can organize their work well in advance and simply monitor the process, thus being available for more rewarding tasks without compromising security."
b.   Cost: $599 per server (Farm and Site Collection licenses also available); 30-Day Trial

ii.           SharePoint Password Reset
a.   "A simple web part that lets users reset their password right on their SharePoint page without having to ask the administrator or IT for assistance. New password will be sent online or through email delivery."
b.   Cost: $599 per server (Farm and Site Collection licenses also available) ; 30-Day Trial
c.    Comments: Purchase together for $899.

3.     Virto Software
i.            Virto Password Change Web Part for Microsoft®SharePoint 2007 and 2010 
a.   "Virto Password Changer Web Part for SharePoint 2007 & 2010 enables Active Directory (AD) users and users with general accounts (FBAP) to change themselves their passwords when they are logged onto SharePoint Site."
b.   Cost: $295 commercial license per WFE server; development license $149; 30-Day Trial

ii.           Virto AD Password Reset and Recovery Web Part for Microsoft® SharePoint 2007 and 2010
a.   "Virto Password Reset & Recovery Web Part for Microsoft SharePoint 2007 and 2010 allows any user logged in to the SharePoint portal using Active Directory authentication to reset his password without contacting administrator. New temporary password will be shown online or sent to email box according to the web part configuration."
b.   Cost: $390 commercial license per WFE server; development license $149; 30-Day Trial

4.     HarePoint
i.            HarePoint Password Change for Microsoft SharePoint
a.   "HarePoint Password Change for Microsoft SharePoint 2007 / 2010 allows end-users to change their own password in a SharePoint site and notifies users when their password is about to expire. Simply add the web part to your SharePoint intranet or extranet portal and let authorized users easily manage their own passwords."
b.   Cost $649 per server; Per user license also available $1.70/user; 30-Day Trial
c.    Comments: There doesn’t seem to be a product for resetting passwords if expired or forgotten.

5.     ArtfulBits
i.            Password Change Web Part Version 1.0
a.   "ArtfulBits Password Change Web Part allows users to change their own passwords from within the SharePoint environment using standard text box interface (current password, new password and confirm new password). It supports Windows authentication and Forms-based which includes Active Directory (AD), Lightweight Directory Access Protocol (LDAP), SQL and other authentication providers."
b.   Cost: $200 per server; 30-Day Trial

ii.           Password Expiration Web Part Version 1.01
a.   "ArtfulBits Password Expiration Web Part enables notification of Active Directory users through the Web Part user interface along with a link to a web page to change their password and/or an email that is automatically sent to their inbox notifying the user that their password is about to expire within a specified grace period. Administrators also have an option to force the users to be automatically redirected to selected web page in order to change their passwords."
b.   Cost: $300 per server; 30-Day Trial

iii.          Password Reset Web Part Version 1.01
a.   "ArtfulBits Password Reset Web Part allows users to reset their forgotten passwords from within the SharePoint environment without administrator intervention. If user does not remember his password and wants to log in SharePoint site, he can reset his forgotten password via web part interface, passing through the various degrees of protection, included security questions and / or email confirmation. New password can be shown on page, or sent to user email, or even user can type new password manually."
b.   Cost: $200 per server; 30-Day Trial

 6.     The Dot Not Factory
i.            AD Password
a.   "AD Password is the only solution allowing end-users to reset forgotten Active Directory and AD LDS (ADAM) passwords and unlock their locked-out accounts while seamlessly integrating into your existing environment. AD Password offers multiple interfaces allowing users to change their passwords or enroll in the Password Reset Service from Microsoft SharePoint, a standard web interface and the Windows logon dialog. AD Password is a flexible solution that eliminates the source of the number one help desk call -- password resets."
b.   Cost: per user commercial license only starting with 50 users for $350; 15-Day Trial
c.   Not limited to just SharePoint 

If Password Change is the only functionality that you require, the following are two are free options:
o   "This web part enables users to change their local or Active Directory password from within a SharePoint Site Collection. It is designed for Windows SharePoint Services v3 and the Microsoft Office SharePoint Server 2007 as well."
o   Cost: Free
o   Comments: Apparently this can be successfully installed on SP2010 and is documented here: Add Change Password Web Part to SCSM 2012 Self Service Portal (SharePoint 2010)

·       SDS SharePoint Library
o   Active Directory Password Change
·       "Have remote users? Tired of logging into Outlook Web Access for password changes? This web part allows users to change their passwords."
·       Cost: Free; must compile

Finally, if you prefer, you can build it yourself. Here’s a blog entry by a Share Point Consultant and Architect based out of Chennai, India to get you started: ChangePassword Web Part for SharePoint 2010.

Wednesday, October 31, 2012

The Problems with PerformancePoint 2010 Stack Selectors


When I initially started using the PerformancePoint 2010 Stack Selector, I thought it was a great way to provide consumers more options of how they viewed data on a dashboard, without taking up more screen real estate or bandwidth. But I’ve finally come to realize that by using them, I was losing some web part features and introducing some erroneous ones. Below are the primary reasons that I have since removed them from my dashboards for the project that I am currently working on.

1. The Stack Selector does not show the appropriate menu items based on the web part being displayed
This occurs when, for example, you have Analytic Reports mixed with Reporting Services Reports located within the same web part zone below a Stack Selector. The Stack Selector menu will show the Export to PowerPoint menu item for Reporting Services Reports, which results in the following error.


With some jQuery, it is possible to locate the Stack Selector’s menu and remove the Export to PowerPoint menu item when a Reporting Services Report is displayed, seemingly fixing the problem. Switching to an Analytic Report using the Stack Selector will cause an asynchronous update and the Export to PowerPoint menu will once again appear (again, using jQuery, this time to show the menu item).

The problem occurs when then switching back to the Reporting Services Report: it will be cached at this point so that an asynchronous update (i.e. partial postback) is not occurring and my jQuery is not executed, resulting in the Export to PowerPoint menu item being available for a Reporting Services Report.

2. The Stack Selector does not show the web part’s description or icon
I initially wasn’t using descriptions or icons with my web parts being displayed by a Stack Selector. However, as the dashboards became more complicated and the reports more sophisticated, I realized a tooltip description of each PerformancePoint web part would be helpful. Additionally, for the novice consumers, an icon indicating the different kinds of web parts (i.e. Analytic Reports, Scorecards, Reporting Services Reports, etc.) would clue them in on the differences in their capabilities (e.g. don’t waste your time right-clicking a web part with an icon indicating that it is a Reporting Services Report).

3. The Stack Selector does not retain the web part selection
This seemed like a minor issue at first, but as I interacted more and more with the dashboards that I was creating, I realized that I appreciated that the PerformancePoint Filters retained their selections between dashboards and between sessions and postbacks (i.e. in the case of using a Query String (URL) Filter). With the Stack Selector, I found myself constantly having to re-select the web part that I was interested in at the time.

Additionally, by using the Stack Selector, I had to deal with the problem addressed in a previous blog post: SharePoint Designer and the PerformancePoint StackSelector’s CurrentSelection Property Error.

I still believe the Stack Selector is useful, however its not quite as robust a control as I had initially thought it to be. In the end, I have eliminated the use of the Stack Selector and more heavily relied upon the PerformancePoint Filter's connections and display conditions to control the visibility of web parts on a dashboard.

Sunday, September 23, 2012

Importing a SharePoint 2010 .CMP file and the “String was not recognized as a valid DateTime” Error

There are plenty of excellent posts out there on how to do a SharePoint 2010 granular backup and restore operation on a document library using PowerShell. A good overview is provided in this blog post on MSDN: SharePoint 2010 Granular Backup-Restore Part 1. I use this process to deploy a set of custom dashboards that I’ve created.

I've put together a couple of PowerShell functions to export (i.e. backup) and import (i.e. restore) a .CMP file (again, plenty of great examples out there), and they work great. However, I ran into a problem when importing one of my document libraries, which lead me to discover an error, similar to the following, in the corresponding log file:

[9/19/2012 1:21:50 PM] [ListItem] [MyDashboard.aspx] Progress: Importing
[9/19/2012 1:21:50 PM] [ListItem] [MyDashboard.aspx] Verbose: List URL: /aSiteCollection/aSite/DashboardPages
[9/19/2012 1:21:50 PM] [ListItem] [MyDashboard.aspx] Error: String was not recognized as a valid DateTime.
[9/19/2012 1:21:50 PM] [ListItem] [MyDashboard.aspx] Debug: at System.DateTimeParse.Parse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles)
   at System.String.System.IConvertible.ToDateTime(IFormatProvider provider)
   at ...

After a little Googling, I discovered this forum post on TechNet which identified the problem and a workaround: String was not recognized as a valid DateTime on import of site
.

The problem turns out to be in the Manifest.xml file located within the .CMP. The actual line in the .XML causing the problem contains an erroneous year (i.e. 60354):

<Property Name="vti_syncwith_smartbidev\:80/ymus" Type="Time" Value="29 May 60354 05:36:10 -0000" Access="ReadWrite"/>

And now for the purpose of this post: the following PowerShell script basically renames the .CMP file to a .CAB, extracts the files into a folder, searches and replaces the erroneous date in the Manifest.xml and imports it using import-spweb with the NoFileCompression switch.
 
function ImportCAB {
    param(
        [Parameter(mandatory=$true)] [string]$webUrl,
        [Parameter(mandatory=$true)] [string]$fileName
    )    

    try
    {
        $cabFile = $fileName.Replace(".cmp", ".cab")

        if(!(test-path $fileName)) 
        {
            write-host "$fileName does not exist. Exiting..."
            return
        }

        write-host "Copying $fileName to CAB file"
        copy-item $fileName $cabFile
        write-host "Copied $fileName to CAB file"

        $cabFolder = "$(split-path $fileName -Parent)\$((Get-Item -path $fileName).basename)"
        
        if(test-path $cabFolder) { remove-item $cabFolder -recurse }
        
        New-Item -ItemType directory -Path $cabFolder
    
        # Creating CAB Files with Windows PowerShell
        # http://lab.technet.microsoft.com/en-us/magazine/dd547834#id0070049
        $comObject = "Shell.Application" 
        write-host "Creating $comObject" 
        $shell = New-Object -Comobject $comObject 
        if(!$?) { $(Throw "unable to create $comObject object")} 
        write-host "Creating CAB object for $cabFile"
        $sourceCab = $shell.Namespace($cabFile).items()
        write-host "Creating destination folder object for $cabFolder" 
        $DestinationFolder = $shell.Namespace($cabFolder)
        write-host "Expanding $cabFile to $cabFolder" 
        $DestinationFolder.CopyHere($sourceCab)
        
        # Search Manifest.xml for the following and replace "60354" with a valid year
        $findText = "Value=`"29 May 60354 05:36:10 -0000`""
        $replaceText = "Value=`"29 May 2012 05:36:10 -0000`""
        
        (Get-Content "$($cabFolder)\Manifest.xml") | 
            Foreach-Object {$_ -replace $findText, $replaceText} | 
            Set-Content "$($cabFolder)\Manifest.xml" -encoding UTF8

        import-spweb -identity $webUrl -path $cabFolder -force -UpdateVersions 2 -nofilecompression #-whatif
    }
    catch [Exception]
    {
        write-host $_.Exception.ToString() -ForegroundColor Green
    }
}

This works rather well, but does not address the real issue of how to fix the source so that the export produces a valid .CMP file in the first place. In theory, I can import this back into my development machine and fix the issue (try at your own risk).

Thursday, August 23, 2012

Default SSRS 2012 Parameters Pane to Collapsed in a PerformancePoint Reporting Services Web Part


Using PerformancePoint Reporting Services web parts on a dashboard is a great way to display information alongside Analytic Reports, in ways that aren’t supported by Analytic Reports (e.g. maps or scatter charts) or for data that doesn’t exist in your Analysis Services cubes. Offering visible parameters for your users to manipulate can additionally increase the value and interactivity of a report. However, when displaying a PerformancePoint Reporting Services web part with parameters, the parameters pane defaults to being expanded. Below is an example of a line chart that wouldn’t be easily possible using an Analytic Chart, with the parameters pane obscuring half of it.

Generally this is good (i.e. having the parameters pane defaulting to expanded), but if real estate is an issue (like in the image above), you may want that pane collapsed in its initial state. To work around this issue, we can use the NotifyBrowserOfAsyncUpdate event and some jQuery to locate a PerformancePoint Reporting Services web part and collapse the parameters pane, if it exists. Note, that this event is triggered for every PerformancePoint web part that is updated on a page.

function NotifyBrowserOfAsyncUpdate(elem) {
    // id of web part being updated
    var elemId = $(elem).prop('id');
    // find iframe sources that contain .rdl
    $('#' + elemId).find('iframe[src*="%2Erdl"]').attr('src', function(i, val) {
        return val.replace('&rv:ParamMode=Displayed&','&rv:ParamMode=Collapsed&')
    });
}

Now when your dashboard is displayed, the parameters pane will default to being collapsed, showing your chart, map or tablix in all of its glory.

Saturday, July 28, 2012

SharePoint Designer and the PerformancePoint Stack Selector’s CurrentSelection Property Error


For a project I'm currently working on, I needed some functionality that isn't (easily) supported by the dashboards that you can create with PerformancePoint Dashboard Designer. This includes adding non-PerformancePoint (custom and OOTB) web parts to the dashboards and making connections between PerformancePoint and non-PerformancePoint web parts. It is certainly  possible to add web parts and create connections after you save a dashboard in Dashboard Designer, but you would have to repeat the process anytime you needed to republish (i.e. save) your dashboard from PerformancePoint. The alternative is to use a web part page to create your dashboard, adding web parts and creating your connections through the browser.

Unfortunately, however, if you have to use SharePoint Designer 2010 for any of your dashboard customizations, you will run into some of the lack of support that it has for PerformancePoint. This posting has to do with one of the more minor annoyances.
When working with a web part page utilizing PerformancePoint web parts in SharePoint Designer 2010, you may notice the following error in the Design Page View after saving a page that contains a PerformancePoint Stack Selector:

Cannot create an object of type 'System.Collections.Generic.KeyValuePair`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]' from its string representation '[, ]' for the 'CurrentSelection' property.

A similar error message is displayed in place of each Stack Selector on the page when it is viewed in a web browser.
A workaround is to remove the following attribute from each of the StackWebPart tags on the page and save again.

CurrentSelection="[, ]"
Unfortunately, as this is merely a stopgap fix, this has to be done every time you open, edit and save a web part page containing PerformancePoint Stack Selectors. Hopefully this is addressed in some future cumulative update (as a note, I am currently developing using the Feb 2012 CU (v14.0.6117.5002)).

Thursday, June 21, 2012

Setting a Default Selection on a PerformancePoint Scorecard


Depending on the design of your dashboard, you may want to set a default selection on a PerformancePoint Scorecard that is used as a filter for other web parts on a dashboard page.
As an example, consider a dashboard that contains a PerformancePoint Filter, Scorecard and an Analytic Report (Grid or Chart). The filter is used to filter the scorecard and the report. Additionally, the scorecard is used to filter the report based on a row member connection. The filter contains a list of manufacturers, the scorecard provides KPI for a list of products a manufacturer carries and the report displays the count of a selected manufacturer’s product sold by state. “Manufacturer 1” sells products A, B and C and “Manufacturer 2” sells products B, C and D.

One approach is to set the default of the Analytic Report to something that could make sense without a Scorecard filter being applied. By selecting default Members for the Analytic Report in Dashboard Designer, the dashboard defaults to displaying information, even without a scorecard selection. Depending on the complexity of your dashboard, the data, etc. maybe this is acceptable (this approach did not make sense for my particular dashboards).
Another approach is to select a Member (e.g. “Unknown” product that no manufacturer carries) that won’t produce any data in the Analytic Report. The resulting chart would look something like the following (note, I’m using a PerformancePoint Stack Selector, hence the web part title within a dropdown box):



Not great, but at least we aren’t misleading the dashboard user. I initially took this approach and went so far as to add a message in any PerformancePoint Reporting Services (i.e. SSRS report) web parts that were connected to the scorecard telling the user that they had to select a product (i.e. row) in the scorecard, if one wasn’t selected.
In the end, I wasn’t satisfied with this approach either, so I went Googling and stumbled across this question and response (http://stackoverflow.com/questions/3372565/performancepoint-sharepoint-2010-and-jquery) which turned up the NotifyBrowserOfAsyncUpdate event. This event is triggered for every PerformancePoint web part that is updated on a page. By using some jQuery and by identifying some PerformancePoint CSS classes, we can determine when the scorecard has been updated and whether or not we need to select a default row member by triggering a cell click event. I use the function below in an external script for use with multiple dashboards (I’ll leave it to you to streamline the jQuery as I have attempted to make it more understandable by adding comments and removing additional functionality).

function NotifyBrowserOfAsyncUpdate(elem) {
    var elemId, selector, rows, row;
    // id of web part being updated
    elemId = $(elem).prop('id');
    // .sctb is a PerformancePoint Scorecard class
    selector = '#' + elemId + " table.sctb";

    if ($(selector).length != 0) {
        // scorecard web part found! get rows that have a class that begins with "r-" (i.e. class|="r")
        rows = $(selector).find('tr[class|="r"]');
        // .scs is a PerformancePoint Scorecard’s selected row class
        if ($(rows).find('.scs').size() == 0) {
            row = $(rows)[0];
            // find head cell in first row and click
            if ($(row).children('th').size() != 0 && $(row).children('th')[0].length != 0) {
                $(row).children('th')[0].click();
            }
        }
    }
}


Because the cell click event is only triggered when a scorecard row is not selected, this will usually only happen when the page loads for the first time. This event would also be triggered when changing, for example, the manufacturer filter from “Manufacturer 1” with “Product A” selected in the scorecard to “Manufacturer 2”. As “Manufacturer 2” does not produce “Product A”, the click event is triggered and “Product B” would be the default scorecard selection.

Edit: June 14, 2014

When drilling up on a Scorecard from a root item that is not the first item, the "elem" element will be undefined and therefore a default row member will not get selected. In this case, which is likely to be infrequent, you can just use "table.sctb" as the selector. The revised function is provided below:

function NotifyBrowserOfAsyncUpdate(elem) {
    var elemId, selector, rows, row;

    if (typeof elem === 'undefined') {
        // occurs when drilling up to All in scorecard
        selector = "table.sctb";
    }
    else {
        elemId = $(elem).prop('id');
        selector = '#' + elemId + " table.sctb";
    }

    if ($(selector).length != 0) {
        // scorecard element found! get rows that have class that begin with "r-" (i.e. class|="r")
        rows = $(selector).find('tr[class|="r"]');
        if ($(rows).find('.scs').size() == 0) {
            row = $(rows)[0];
            // find head cell in first row and click
            if ($(row).children('th').size() != 0 && $(row).children('th')[0].length != 0) {
                $(row).children('th')[0].click();
            }
        }
    }
}

Wednesday, May 30, 2012

Breadcrumb Bar Style Dashboard Navigation

I recently needed to provide a breadcrumb on a SharePoint dashboard page which uses web parts to provide information about a sales territory area. Because the sales territories are defined as a hierarchy consisting of thousands of areas (e.g. regions which contain districts, districts which contain trade areas, and trade areas which contain counties), I chose to use a Query String (URL) Filter to pass an area to the dashboard page, rather than trying to load the areas into a PerformancePoint tree filter or multiple cascading filters. As a result, the page is much more light weight and easy to navigate, however, at the expense of having to do full postbacks to navigate between areas.

Conceptually, the area breadcrumb needed to show the area being viewed and the path to that area (i.e. all of its parents). Additionally, the parents could be links, providing a way to navigate to any of the parent areas. A very simplistic approach could display the information in a manner similar to the following:

National > Region 1 > District 1D > Trade Area 1D2 > Orange County, CA

But then I thought of the Breadcrumb Bar that was originally introduced with the Windows Vista version of Windows Explorer. These aren't drives, folders and files, but the hierarchical nature of the sales territories fit perfectly. The benefit of this approach would be to allow additional navigation possibilities to any of an area's parent's children (read on if that's not clear).

With a bit of Googling, I found a nice basis for my breadcrumb bar with this example: CSS-Only Dropdown Menu. It basically provides a very simple, yet elegant, drop down menu with a little javascript to handle the mouseover and mouseout events.

Breadcrumb Bar Example for Orange County, CA (this example should be interactive... at least it was when I originally posted it):




After dummying up an example of how I wanted the breadcrumb bar to look, I then had to decide how I would need to format the data to populate such a control. I came up with the following which required a stored procedure that basically has to determine each of the selected area's parents and the children of each of those parents (you'll have to design your own query based on your database design). Again, the following is what would be needed when passing "Orange County, CA":



AreaName
AreaType
AreaLevel
IsSelected
National
National
1
1
Region 1
Regions
2
0
Region 2
Regions
2
1
District 1A
Districts
3
0
District 1B
Districts
3
0
District 1C
Districts
3
0
District 1D
Districts
3
1
District 1E
Districts
3
0
District 1F
Districts
3
0
Trade Area 1D1
Trade Areas
4
0
Trade Area 1D2
Trade Areas
4
1
Trade Area 1D3
Trade Areas
4
0
Trade Area 1D4
Trade Areas
4
0
Los Angeles County, CA
Counties
5
0
Orange County, CA
Counties
5
1
Santa Barbara County, CA
Counties
5
0
Ventura County, CA
Counties
5
0


As an example, if I pass "District 1D" to the stored procedure, it would return "Region 2" and "National" (i.e. the parents of "District 1D") and "Region 1" (the additional child of "National") and the other children Districts of "Region 2".

Finally, I needed to build the control. I could have easily written a custom web part, but opted for a Data Form Web part instead. This basically required a bit of XSL to build the HTML. Again, I'll leave that exercise to you, the reader.

The final control also included an "enabled" flag that would allow me display the hierarchy, but disable parent areas that users did not have access to. This required an additional argument to the stored procedure of the user accessing the dashboard.

Although this post is light on code, I hope that it may help in creating your own breadcrumb bar for the navigation of a PerformancePoint dashboard.