Monday, August 6, 2012

Permanently Delete Office 365 MsolUser without waiting 30 Days

I have been working on a transition from Exchange 2010 to Office 365, doing a cutover conversion so that I can decommission my current Exchange Server.

The documentation, while there is a lot of it, is conflicting, misleading, and sometimes just wrong.

In any case, one of the most useful things I learned in this process was how to permanently delete MSOL users. Users that have been deleted and recreated with the same UserPrincipalName can cause all sorts of havoc.

Are you experiencing one of these problems:

  • DirSync reports:

Unable to restore user from a deleted state because of following error(s):
Value 'xx@yy.com' for property 'UserPrincipalName' conflicts with another object in the directory.
Value ‘xx@yy.com’ for property 'ProxyAddress' conflicts with another object in the directory.

  • Users can sign into https://portal.microsoftonline.com but not able to connect with a desktop client or mobile phone.
  • Multiple users show up in your Global Address List (GAL)
  • In Lync you see a the same user multiple times or you see deleted users

Well, all of these problems can be a result of deleting an account and recreating it with the same UserPrincipalName or ProxyAddress as the deleted version. Most documentation reports that the accounts will stick around for 30 days and there’s nothing you can do but wait or put a ticket into support. However, the latest version of MSOL PowerShell Tools has a fix—the latest is available from: http://onlinehelp.microsoft.com/Office365-enterprises/ff652560.aspx#BKMK_DownloadTheMOSIdentityFederationTool

The fix “Remove-MsolUser –RemoveFromRecycleBin –ObjectId ObjectId

If you don’t have the “-RemoveFromRecycleBin” parameter option, then you are not using the latest version of MSOL PowerShell Tools.

To see if this is affecting a particular user, do the following in MSOL PowerShell

Connect-MSOLService
Get-MsolUser –ReturnDeletedUsers –SearchString UserPrincipalName | select UserPrincipalName, ObjectId

The result will display all deleted mailbox containing the search string UserPrincipalName and their corresponding ObjectId’s.

To permanently delete one of the results, use the returned ObjectID in above statement in the Remove-MsolUser statement:

Remove-MsolUser -RemoveFromRecycleBin –ObjectId ObjectId

Note—this just deletes the already deleted mailbox from the recycling bin. It doesn’t do anything with the active (non-deleted) MsolUser if one happens to exist.

I ended up having a ton of deleted users from various failed attempts at migrating, and trying out SSO, so I wrote a simple PowerShell script to aid in the clearing out of deleted mailboxes. It should go without saying that if you do this, the deleted mailbox is no longer recoverable—it’s permanently deleted. For that reason, I have it show you the active user as a precaution so you can make sure the ObjectId that is about to be deleted permanently is not in fact the ObjectId of your currently active user. This script also prompts you twice to ensure you really want to permanently delete the MsolUser.

Param($searchString = $null)

function O365Logon
{
 #Must be ran from MSOL Shell
 Connect-MSOLService
}

function Main
{
 
 if ($searchString -eq $null) {
  $DeletedMailUsers = Get-MsolUser -ReturnDeletedUsers | select UserPrincipalName, ObjectId
 } else {
  $DeletedMailUsers = Get-MsolUser -SearchString $searchString -ReturnDeletedUsers | select UserPrincipalName, ObjectId
 }
 foreach($DeletedUser in $DeletedMailUsers) {
  Write-Host "The active account for" $DeletedUser.UserPrincipalName " is:"
  Get-MsolUser -UserPrincipalName $DeletedUser.UserPrincipalName | select ObjectId
  $a = Read-Host Delete $DeletedUser.UserPrincipalName $DeletedUser.ObjectId ('y/n')?
  if($a.ToLower() -eq 'y')
  {
   Remove-MsolUser -RemoveFromRecycleBin -ObjectId $DeletedUser.ObjectId
   Write-Host "Removed User " $DeletedUser.ObjectId
  }
 }

}

O365Logon
Main

To run this script, copy and save the script in notepad as PermanentlyDeleteADeletedAccount.ps1 and start an Administrative MSOL PowerShell session.

The command syntax is:

.\PermanentlyDeleteADeletedAccount.ps1
or
.\PermanentlyDeleteADeletedAccount.ps1 UserPrincipalName

Friday, January 27, 2012

Combining Technology and Food

I came across a unique opportunity to combine a few of my favorite things: .Net, Mobile Development, and EATING! One of my close friends, Jimmy Crippen, owns a fine dining restaurant, Crippens Country Inn and Restaurant in Blowing Rock, NC. This year he is hosting the seventh annual Fire on the Rock competition, where local chefs compete in a tournament style bracket to find the best chef in the High Country. The competition is expanding this year to include venues in other areas of North Carolina.

The dinners are awesome—but, the automation angel in my head has been nagging me for years about the old school pencil and paper voting mechanism used during the competition. Each diner (averages about 130 per night) votes on six different categories for six different courses—that’s nearly 5,000 scores to tally for each leg of the contest and comes to a whopping 70,200 manually tallied score per competition bracket!

This year I set out to help. With mobile devices becoming so popular, it’s fair to say that most folks attending these competitions will have a web capable phone or tablet—but I needed something super simple if guests were to participate. If it’s all complicated, people won’t use it. So I started out with several prerequisites:

  1. Must work on all common smartphones and tablets, including Android and IPhone, and IPad.
  2. No application to install
  3. No complicated logins or long cryptic strings to enter or register
  4. Secure against cheating or outside hacking
  5. So easy my mom could use it (sorry Mom… don’t mean anything negative!! At least I was thinking of you)

What I came up with was Jquery Mobile application, utilizing .Net in the background, and a standard .Net Web Application for administrative functions. This solves the issue of compatibility, so I meet my first 2 criteria. For security and to prevent users from having to login, create new accounts, etc., I came up the idea that the administrative interface would create “tickets,” each of which would have QR codes that would be uniquely linked to that specific ballot and event. For old school folks, the ticket would also contain old school voting sheet.

image

Now, simply by scanning the QR code, the diner is directed to their specific ballot—no need to create another new account, remember any new passwords. Also, an astute observer may have also noted that there is also a shortened goo.gl url that the user could type into their browser if their mobile device is not equipped with a QR code reader.

Only the number of tickets that are sold for the event are created, so this addresses criteria 3 and 4. While, yes, you could scan someone else's ballot and vote for them, but they would know because when they went to vote, selections would already be made for them! In fact, this is a beneficial side effect, because now a more technologically inclined diner can easily assist others at their table, or even pass their device around for others to use to submit their votes, thus meeting criteria 5, just for my mom! Votes are saved to the database after each change, so at any time a diner could close close their browser, help out a friend, and when ready to vote on their next course, simply rescan their ballots QR code. For clarity, the voters name associated with the ballot is always included in the footer of every voting page, thus ensuring you’re voting on the correct ballot.

So.. This is a lot easier to show than talk about. Here are the UI screens from the diners perspective.

1. User receives voting ballot, and scans their QR code. They enter their name and email address.

voterlogin

2. User is presented with the different courses to be served:

selectCourse

Note that some of the courses have checkboxes that are checked next to them—this means they have voted for all items in that category, and their vote has been saved. It even presents them with their ranking of that course on the right hand side:

image

3. User eats a delectable course prepared by one of the chefs, and selects that course to cast their vote:

vote

4. When all done eating and voting, user clicks “Commit Ballot,” after which their ballot is marked as final, locked from editing, and will be included in the results:

 

commit

5. Done. Prepare for announcement of winners, and think of what a good night sleep you’re going to get with such a good and full belly.

Note… now, if the person were to go back to the event and change their votes, they would get an message indicating their votes are locked. Administratively, before results are posted, there is also an event lock that the competition administrator sets before showing results, which locks out any additional changes to voting, even if the voter’s ballot is not yet committed. Users may still click through to review their votes, but not change them:

nochangesaftercommit

---- that’s it!

The first test run, Battle of the Chef’s, January 24, 2012

So on Tuesday, we put this new system to the test. In a preliminary battle prior to the 2012 competition tournament starting, we introduced digital voting for the first time. It was a huge success, with 90% – 95% of diners opting to vote electronically.

The Blowing Rock News stated:

"I am most pleased," Crippen continued, admitting, "with how the digital voting went.  It went without a hitch. I cannot say enough about my friend Derek Sanderson who made the digital voting and tabulations possible."

Check out the full Battle of the Chef’s news article posted on Blowing Rock News.

 

And… Stay tuned, I’ll post more on the administrative side of things in a future post. Oh… and, thanks to Fendy Huang for helping me test application and providing screenshots!!

Thursday, October 13, 2011

Local, Cloud or Mixed Environment for your SharePoint BI Solution

Today at noon I’ll be presenting a webinar on hosted options for business intelligence solutions in SharePoint.

Sign up for live webcast here (Thursday, October 13 12:00 noon):
image

Environments considered:

  • Office 365
  • Windows Azure
  • Datacenters
  • On Premise

BI Tools considered:

  • User Interface:
    • Out of the Box SharePoint Components, including Charting and Business Connectivity Services
    • Performance Point
    • Excel Services
    • PowerPivot
    • Back End
    • SSRS
    • SSAS
    • SSIS
    • SSDE
    • SQL Azure
  • Infrastructure items considered:
    • High Availability
    • Network Performance
    • Security
    • Cost

Sunday, May 15, 2011

“Know the Unknown” When Developing in SharePoint 2010

Thanks to everyone who attended Melissa’s and my presentation yesterday at Carolina Code Camp 2011. And, of course, an extra special thanks to the organizers of this great event, and to my partner in crime on this presentation, Melissa Coates. Be sure to check out her blog as well, where she is better known as “SQL Chick!”

image

The slide deck in its entirety is avalable on Google Docs: SP2010-KnowTheUnknown-SandersonCoates.pdf.

Here is an excerpt of the material covered in the presentation:

Overview of Session

This session is based upon things we have learned & dealt with during two BI-oriented SharePoint 2010 implementations late 2010-early 2011.

  • One implementation:  SharePoint Foundation on a public facing site
  • The other:  SharePoint Enterprise on an internally authenticated site

Agenda

  • Figuring out Unexpected Errors
    • Web Config Updates
    • Using SPDiagnosticsCategory to Write to the ULS Log
    • Web Part Maintenance Page
  • Development Environment
    • Developer Dashboard
    • PowerShell for deployment
  • Choosing Technologies
    • Dashboards, Scorecards, Reports
    • SSRS Native Mode vs. SharePoint Integrated Mode
    • PowerPoint for Quick Branding
  • Dealing with Limitations
    • Performance Issues with Report Viewer Control 10
    • Foundation Limitations
  • Q&A

Log Everything with Google Analytics

Thanks to all who attended my session yesterday at the Carolina Code Camp 2011.

image

The presentation slide deck is available in it’s entirety on Google Docs: LogEverythingWithGoogleAnalytics.pdf

Here’s an excerpt of the Agenda covered:

  • Using Asynchronous Calls
  • Utilizing web.config for various deployment environments
  • Tracking individual session data
  • Debugging / Tracing / Verifying GA calls in real time
    • Demo – using Fiddler
  • Event Tacking
    • Tracking arbitrary events
    • Demo in Google Analtyics
    • Demo with Fiddler
  • Tracking External Page Links (with Jquery)
    • Demo using FireBug
  • Tracking Internal Links
    • Demo in Google Analytics with In-Page Analytics
  • Tracking Videos
    • Demo using Fiddler and YouTube video
  • Tracking  Session Info
    • Demo of GA custom report
  • Ecommerce Tracking
    • Demo/code with GA, Fiddler, Google Checkout
    • Demo/code for Thank You page (PayPal, custom cart)
  • Adwords Tracking
    • Injecting Adwords Code

Tuesday, February 15, 2011

How to remove a bad Web Part from SharePoint 2010

More often than I would like, a custom web part I’ve added to a page throws an exception. If you followed my previous blog on “An unexpected error has occurred,” and enabled CallStack, then any unhandled exception will cause the whole page to fail—and there is no obvious way to remove the web part from the page.

Well, there is actually a simple way to remove the offending web part via the Web Part Maintenance page. Simply add a querystring parameter right on the offending page’s URL of “?contents=1".

So I am on a web part page:

image

Append parameter to querystring:

image

You will then be redirected to the appropriate Web Part Page Maintenance:

image

Now you can easily remove the offending web part.

Just to note, if the url of the page you are on already has existing querystring parameters, you should use “&contents=1” instead of “?contents=1”.

Wednesday, February 2, 2011

SharePoint 2007/2010–“An unexpected error has occurred.”

Want a real error message instead of “an unexpected error has occurred?”—read on, this post will describe how to do just that.

I’m sure every SharePoint developer has run across the infamous “unexpected error:”

image

So… All you have to do is look in the extremely friendly ULS logs, conveniently located at:

For SharePoint 2010:

%Program Files%\Common Files\Microsoft Shared\Web Server Extensions\14\LOGS

For SharePoint 2007:

%Program Files%\Common Files\Microsoft Shared\Web Server Extensions\12\LOGS

And then, starting from the most recent file, start searching for the “Correlation ID” mentioned in the error. Note, there are quite a few ULS readers available that can make this a bit easier. However, also note, that, if you have multiple web front ends, it can be a task just figuring out which server logs to even look at.


When I eventually found the right log file and searched through using that Correlation ID until I found an error, I discovered this:

02/02/2011 13:53:00.91  w3wp.exe (0x1A80)                        0x0464 SharePoint Foundation          Runtime                        tkau Unexpected Microsoft.Reporting.WebForms.MissingReportServerConnectionInformationException: In remote mode, the Report Viewer control requires session state be enabled or Report Server connection information specified in the config file.    at
Microsoft.Reporting.WebForms.ReportViewer.EnsureSessionOrConfig() at Microsoft.Reporting.WebForms.SessionKeepAliveOperation.CreateRequest(ReportViewer viewer) at Microsoft.Reporting.WebForms.ReportViewerClientScript.SetViewerInfo(ReportViewer viewer, String reportAreaId, String promptAreaRowId, String docMapAreaId, String fixedTableId, String promptSplitterId, String docMapSplitterId, String docMapHeaderOverflowId, String directionCacheId, String browserModeCacheId) at Microsoft.Reporting.WebForms.ReportViewer.OnPreRender(EventArgs e) at System.W... 4384d11b-0b4a-4164-ab5e-9643ab891e27

In this particular case, I can see that I am using a control that requires Session State, but it’s not enabled. Wouldn’t it have been nice if instead of having to go through all of that log searching I could have just gotten a message like this:


image


So, the first thing I do in my development environment is configure a few items in the web.config so that I get real error messages on the page. Please make sure that you do NOT use these settings in production, because aside from not wanting end users to see the hideous yellow and red error message and stack trace, these settings cause a good bit of overhead and will slow down your site unnecessarily.



Here are the settings I always set in my development SharePoint box, that will ensure I get the detailed message as shown above.


How to get the “real” error to show on web page:


1. Open the web.config for the appropriate web application. In my case, it’s located at:

c:\inetpub\wwwroot\wss\VirtualDirectories\80\web.config

2. Search for “<customErrors” – I usually just turn them completely off for my web.config:

    <customerrors mode="Off" />
If for you don't have a customErrors entry in your web.config, you can just add it. It is a child of system.web.

3. Search for “<compilation”—change or add the attribute “debug” and set it to true (here’s what my whole line looks like):

    <compilation batch="false" debug="true" optimizeCompilations="true">

4. Search for “<SafeMode” and set “CallStack” to "true (here’s my SafeMode node):

<SafeMode MaxControls="200" CallStack="true" DirectFileDependencies="10" TotalFileDependencies="50" AllowPageLevelTrace="false">


And… That’s it. You should now get “real” error messages right from the web page instead of having to dig through ULS logs!!