Adventure in SPWonderland

Take apart and put back together

NAVIGATION - SEARCH

List Windows Groups in a SharePoint site and convert to DirectoryEntry

 

On a Claims enabled site I needed to get a Windows DirectoryEntry object for each group and list its members

Using the LDAP Sid syntax and the ADSI operator allows for a quick lookup to AD

$ClaimMan=Get-SPClaimProviderManager

$web=get-spweb http://flxdev2010:25555/sitecol1/sub6/Test3

# Get User List

$Users=$web.RoleAssignments  | % { $_.Member.Users }

# Filter to get only windows groups – return Sid’s

$WindowsGroups= $Users | ? { $_.IsDomainGroup -eq $true
        -and $ClaimMan.DecodeClaim($_.UserLogin).OriginalIssuer -eq "Windows"}  | % { $ClaimMan.DecodeClaim($_.UserLogin).Value }

# RAW Sids here
$WindowsGroups

# DirectoryEntry list here
$GroupEntries=$WindowsGroups | % { [ADSI]"LDAP://<SID=$($_)>"  }

# List members of group
$GroupEntries | % { $_.Properties["member"] }

SPClaimsUtility.AuthenticateFormsUser Invalid XML Error

 

Hit a strange error that Google turned up blank on.

I had a password reset page that took some encrypted parameters and used SPClaimsUtility.AuthenticateFormsUser to log the user in and set the session token.

This code

Uri appliesTo = new Uri(Page.Request.Url.AbsoluteUri);

// Set the session token
SPClaimsUtility.AuthenticateFormsUser(appliesTo,user.UserName, txtNewPassword.Text);
would fail with a an invalid XML Error

System.Xml.XmlUtf8RawTextWriter.InvalidXmlChar(Int32 ch, Byte* pDst, Boolean entitize) +2670818
   System.Xml.XmlUtf8RawTextWriter.WriteElementTextBlock(Char* pSrc, Char* pSrcEnd) +5042301
   System.Xml.XmlUtf8RawTextWriter.WriteString(String text) +85
   System.Xml.XmlWellFormedWriter.WriteValue(String value) +1959831
   System.Xml.XmlWrappedWriter.WriteValue(String value) +17
   Microsoft.SharePoint.IdentityModel.SPTokenCache.GetBytesForSessionToken(String cookieContents) +123
   Microsoft.SharePoint.IdentityModel.SPTokenCache.WriteToken(SessionSecurityToken sessionToken) +304
   Microsoft.IdentityModel.Web.SessionAuthenticationModule.WriteSessionTokenToCookie(SessionSecurityToken sessionToken) +136
   Microsoft.SharePoint.IdentityModel.SPSessionAuthenticationModule.AuthenticateSessionSecurityToken(SessionSecurityToken sessionToken, Boolean writeCookie) +40
   Microsoft.SharePoint.IdentityModel.SPFederationAuthenticationModule.SetPrincipalAndWriteSessionToken(SecurityToken securityToken, SPSessionTokenWriteType writeOperationType) +485

 

The problem happens because the SPTokenCache is writing the tokenreference claim into an custom XML format.

The tokenreference contains, among other things, the AppliesTo Url.

XML has issues with characters outside a strict range including lower or higher Ascii characters.

The mistake i made was using Page.Request.Url.AbsoluteUri which includes the parameters passed to the page,  this included lower Ascii characters as part of the encrypted string (now this could be BASE64 encoded to avoid that).

The fix is to pass in only the current Web Url

 Uri appliesTo = new Uri(SPContext.Current.Web.Url);             
 // Set the session token
SPClaimsUtility.AuthenticateFormsUser(appliesTo,user.UserName, txtNewPassword.Text);

Turn on tracing in SharePoint Diagnostics Studio

 

If you are getting a problem in SharePoint Diagnostics studio (part of the SharePoint Administration toolkit ) it can be useful to turn on tracing for the app.

Create a file called spdiag.exe.config in the same directory as spdiag.exe and put this in it

<configuration>
    <system.diagnostics>
        <trace autoflush="true" indentsize="4">
            <listeners>
                <add name="TextListener"
                    type="System.Diagnostics.TextWriterTraceListener"
                    initializeData="trace.log" />
            <remove name="Default" />
            </listeners>
        </trace>
    </system.diagnostics>
</configuration>

 

When you run SPDiag you will get a pretty detailed trace file generated.  For some reason this app tends to log exceptions rather than display them in the UI.

This helped me track down a blank report that was actually throwing an error behind the scenes.

System.Data.SqlClient.SqlException: Invalid object name 'TVF_RequestUsageAggregate_LogTime'.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
   at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
   at System.Data.SqlClient.SqlDataReader.ConsumeMetaData()
   at System.Data.SqlClient.SqlDataReader.get_MetaData()
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)

Update User Emails in SharePoint from Active Directory

 

With SharePoint once a user is added to a SharePoint site the users email is saved at that point in time and only updated if you have the User Profile Service setup and running in which case a timer job updates user information in all site collections in the Farm.

Sometimes farms are created that stand alone and do not have the User Profile service setup or it might be a foundation Farm which has no User Profile Service. In that case this script might be useful.

It gets the Email address from AD for every user in all site collections within a Web Application and updates it if needed.

From a Powershell prompt

To Report on out of date  user emails
  .\FixUserEmails.ps1 http://sharepointurl

To update emails 
  .\FixUserEmails.ps1 http://sharepointurl $true

 

Should work for 2007 and 2010.

Its not guaranteed to work across multiple domains as the sAMAccountName attribute does not contain the domain, otherwise let me know of any issues.

FixUserEmails.zip (2.82 KB)

SharePoint 2010 EU Cookie Law Notification Control

 

I’ve just released a SharePoint 2010 solution for external SharePoint sites that need to comply with EU notification rules.

The control is activated on each Web Application and displays a message at the top of every page for each user until they click the confirm button. The confirm button stores a cookie which is detected on further page views and does not display if its detected.

This control allows active consent rather than implied consent.

Tested in SharePoint 2010 Foundation, 2010 Server, IE8/9, Chrome, Firefox.

Download from CodePlex: SharePoint 2010 Cookie Approval

TeamSiteTopPage

Case Sensitive MindF**k Part 1 SharePoint not indexing TWiki

So we’re setting up a crawl of a TWiki site as one source in a suite of content sources.

So far so good, once the authentication was sorted we noticed a problem, only the root Url of the site was getting crawled.

Various ideas were thrown around about nofollow and noindex attributes but we couldn’t find anything wrong with our configuration and nothing seemed to fit the problem.

I noticed that this particular TWiki installation was case sensitive to Urls by accident (thought those days were gone, configurable apparently) and that got me thinking.

By kicking a crawl off i noticed that SharePoint was requesting lower case urls from the Site for every link on the home page getting a 404 and stopping.

Ok penny drops but why is SharePoint sending a lower case url, well… this is by design as part of the crawler’s normalization of urls (http://blogs.msdn.com/b/enterprisesearch/archive/2010/07/09/crawling-case-sensitive-repositories-using-sharepoint-server-2010.aspx)

In 2010 if you’re setting up a crawl rule that checkbox you’ve ignored called Match Case (badly named surely Preserve Url Casing would get the point across better) just needs to be set and viola the crawler will preserve the case of Urls it requests.

SPEndpointAddressNotFoundException error in Dashboard Designer

 

When using PerformancePoint Designer in SharePoint 2010 and trying to add a new item say a SQL Server connection you might get the error 'An Unexpected Error Occured. An error has been logged for the Administrator'

If you check the Event log on your client machine you should find a more detailed but equally cryptic error.

An unexpected error occurred. Error 15568.

Exception details:

Microsoft.SharePoint.SPEndpointAddressNotFoundException: There are no addresses available for this application.

at Microsoft.SharePoint.SPRoundRobinServiceLoadBalancer.BeginOperation()

at Microsoft.PerformancePoint.Scorecards.BIMonitoringServiceApplicationProxy.GetBalancerContext()

at Microsoft.PerformancePoint.Scorecards.BIMonitoringServiceApplicationProxy.ExecuteOnChannel(CodeBlock codeBlock)

 

First check in Central Administration check you have a PerformancePoint Services application created.

My problem was that although the services application was created the service instance itself was not running. Goto Central Admin - System Settings - Manage Services on Server and make sure the PerformancePoint service is started or start it youself.

Why you are not given the option in the Services App to do this automatically is a mystery to me.

 

 

 

SPMetal doesn't like spaces

 

Currently when generating a class with SPMetal from a site that has spaces in it

SPMetal.exe  /web:"http://flxdev2010:19000/PWA/Test Plan" /namespace:ProjectSite /code:ProjectSite.cs

It will give

Error the web at 'http://flxdev2010:19000/PWA/Test Plan' could not be found

Oh dear, a schoolboy error.

Now you could use stsadm to dump out the site, delete and reimport, yikes. Or you can just rename the Url as ServerRelativeUrl is read/write (any outside links point to the Url will not be fixed up!)

Using a quick console app


            using (SPSite site = new SPSite("http://flxdev2010:19000/PWA/Test Plan"))

            using( SPWeb web = site.OpenWeb())

            {
               string s = web.ServerRelativeUrl;
               web.ServerRelativeUrl = "/PWA/TestPlan";
               web.Update();

            }

or that new fangled 4 year old PowerShell thingy

Start-SPAssignment -Global

$web.Title = "/PWA/TestPlan"
$web.Update()
Stop-SPAssignment -Global

SPMetal.exe  /web:"http://flxdev2010:19000/PWA/TestPlan" /namespace:ProjectSite /code:ProjectSite.cs

now works.

you can change it back once you have the definition.