Sue Hernandez's SharePoint Blog

SharePoint and Related Stuff

Category Archives: SharePoint 2013

SharePoint 2013 – Recover deleted Default authentication Zone

Yes, yes, by the title you’re saying how in the world did you delete your default zone.  Well on my test platform I had installed a CU and it went horribly wrong, and in an effort to fix it, I mistakenly blew away the default zone.

Here's what I did to recover it:

$wa = Get-SPWebApplication "https://YourWebApplicationUrl.com"
$def = [Microsoft.SharePoint.Administration.SPIisSettings]::CreateFromExistingWebSite("IIS Displ Name")
$wa.IisSettings["Default"] = $def
$wa.Update()

So just go in to IIS Manager to make sure you have the right display name for the IIS web site related to that web application.

Advertisements

SharePoint 2010 Error nativehr 0x80131904

We came across a strange error the other day, reported by a user in SharePoint 2010.   When the user attempted to add a new item to a Contacts list, the page threw an error.  When we debugged it on the server and showed the server error, it was basically as follows:

<nativehr>0x80131904<nativehr>
System.Runtime.InteropServices.COMException

with stack trace containing:

SPRequestInternalClass.AddOrUpdateItem
SPRequest.AddOrUpdateItem
SPListItem.AddOrUpdateItem
SPListItem.UpdateInternal

We looked in the ULS logs and found the following 2 errors:

  • No XsltListViewWebPart was found on this page[/path/siteColl/site/Lists/ListName/NewForm.aspx?IsDlg=1].  Hiding key filters and downgrading tree functionality
  • Cannot insert the value NULL into column ‘tp_DocId’, table ‘ContentDBName.dbo.AllUserData’; column does not allow nulls. INSERT fails.

From reading the blog that led me to the answer (below) there may also be an event log error, number 5586 (Unknown SQL Exception 515 occurred).

So I found a blog by Allen Wang about a similar problem he had with a survey.  SP2010 Survey List Error and Event ID 5586.  He explained in his post that when SharePoint owners add a certain number of columns to their List/Library, all of the same data type, that the SQL storage starts implementing what is called row wrapping.  So internally in the database, one of the columns is tp_RowOrdinal (NEVER EVER EVER EVER modify the DB directly), and this number gets increased once you go past the row wrapping limits (see below for PowerShell commands to see this).  Here’s a summary of the data types:

Single Line of Text:  Wraps after 64 columns
Mult Lines of Text:  Wraps after 32 columns
Choice:  Wraps after 64 columns
Number:  Wraps after 12 columns
Currency:  Wraps after 12 columns
Date/Time:  Wraps after 8 columns
Lookup:  Wraps after 16 columns
Boolean (Yes/No):  Wraps after 16 columns
Person/Group:  Wraps after 16 columns
Hyperlink/Picture:  Wraps after 32 columns
Calculated:  Wraps after 8 columns
GUID:  Wraps after each and every column
Int:  Wraps after 16 columns
Managed Metadata:  not sure, seems to be 4 or 6

Please reference this post from Microsoft (I know it’s 2013, but 2010 doesn’t seem to be around any more):  Software boundaries and limits.

So what had happened in our case was that there were over 78 columns in the list.  When the list Owner modified the column order to move the newly added columns to the top of the Edit/New form, that’s when it broke.  That was because RowOrdinal=1 was placed above RowOrdinal=0.

To see what I’m talking about without digging in the database, use PowerShell:

$web = Get-SPWeb https://yourURL.com/path/siteCollection/site
$list = $web.Lists["Name Of Your List"]
$field = $list.Fields.GetField("Field Display Name")
Write-Host $field.SchemaXml

This will output something like this

<Field Type="Number" DisplayName="Field Display Name" 
   ID="{89d9e81e-e31a-402d-a8e4-05935dbb29ac}" 
   SourceID="{9007df08-a644-461b-9af5-b39252f5bb93}" 
   StaticName="_x004e_um10" 
   Name="_x004e_um10" 
   ColName="float10" RowOrdinal="0" Version="1"/>

If you get the SchemaXml of the last few columns, you might see RowOrdinal=”1″ inside the SchemaXml.  If you see that, you cannot place that column above another column of the same type which has a 0 ordinal.  So for example this would be OK:

       NumberColumn10
       NumberColumn13

but this would break:

       NumberColumn13
       NumberColumn10

 

DISCLAIMER:

I just tried to replicate this in my VM of SP 2013 and I added over 500 number columns and over 100 user columns and was unable to get RowOrdinal to be anything but 0.  Not sure why.

Thanks to Allen Wang for providing solution.

Repost – Get an SPUser Object From a List or Library in SharePoint Using PowerShell (Brandon Atkinson)

This blog was written by someone else but appears to not be available right now.  I got this on cache.  I am re-posting it cause I had the hardest time tracking this down.  On reflection, it makes sense that you’d have to do it very similar to C# code, but I was stuck for a while.

THIS POST WAS WRITTEN BY BRANDON ATKINSON not me.  Following is the link, however it appears to not be working right now.  sharepointbrandon.com/category/powershell

I was looking this up for SharePoint 2010, however it most likely works the same in 2013.

Get an SPUser Object From a List or Library in SharePoint Using PowerShell

At some point in your journeys with PowerShell and SharePoint you’ll need to pull a user from a list/library column and get an email address or login name, etc.  If you’ve never done this before it can be a little frustrating as you have to jump through a couple of hoops.  Let’s take a look at simply querying the list.

Let’s assume we have a library with a Name column and a user column called “Owner”.  Now we can easily query the library and pull out the “Name” with something like this:

# $docLib is a reference to a library and $spQuery is an SPQuery object with a CAML query
$spListItems = $docLib.GetItems($spQuery)

# Loop through items and write out info
foreach ($item in $spListItems) {

    Write-Host $item.Name
}

In this example we simply query the library and loop through the results, writing out the ”Name”.  But what if we needed to also write out the email address of the user column.  Here is where the hoops come in, fortunately they are small.

You have to perform some casts in order to get the actual SPUser object.  So taking the previous example, we can re-write it like this:

# $docLib is a reference to a library and $spQuery is an SPQuery object with a CAML query
$spListItems = $docLib.GetItems($spQuery)

# Loop through items and write out info
foreach ($item in $spListItems) {

     Write-Host $item.Name

    # Get the SPUser object from the column
$spFieldUser = [Microsoft.SharePoint.SPFieldUser]$item.Fields.GetField(“Owner”);


$spFieldUserValue = [Microsoft.SharePoint.SPFieldUserValue]$spFieldUser.GetFieldValue($item[“Owner”].ToString());

$user = $spFieldUserValue.User;

   # Pull out the user email
Write-Host = $user.Email
}

In this example we first have to create an SPFieldUser object using $item.Fields.GetField(“Owner”).  Once we have that reference we can use the GetFieldValue method to return an SPFieldUserValue object, which will contain the actual SPUser object.  Now we have access to all the properties on the user like Email, DisplayName, LoginName, etc.

As you can see, its pretty easy to get to the user object in SharePoint via PowerShell.

Enjoy!

SharePoint 2013 Sorry this site has not been shared with you

Recently I ran into an issue with a site that had been migrated from SharePoint 2007 through to SharePoint 2013.  The home page was a Publishing page in the Pages library, and the Pages library inherited permissions from the site, and none of the pages had unique permissions.  I had a couple of users who were in groups that had full control.  Those users were able to browse to the home page just fine, but when putting the page in Edit mode, received the message “Sorry, this site has not been shared with you.”

I went to the page in question and did a “Check Permissions” and sure enough they DID have rights – full control – to the page.

So I went into the SharePoint ULS logs and there was an Access Denied error logged, sure enough, but right around that error it was referencing something about the Publishing infrastructure.

 

So on a hunch, I checked permissions on the library at the root – Master Pages and Page Layouts.  Someone way back when had broken permissions on this library and removed EVERYONE’s permissions on this library except the system account and one administrator.  So I added the users to Full Control for the library (probably read would have sufficed, but they needed full control anyway) and the problem was resolved.

In general, you also want to be careful of permissions around the Style Library and/or Site Assets, depending on where your css files and images are stored.  We always have lots of people who think they are locking down their site remove the “Style Resource Readers” group (which by default has NT Authority\Authenticated Users in it) but the end result is no users can browse to anything because they don’t have rights to view the stylesheets.

SPSecurity.RunWithElevatedPrivileges and Console Applications

Wow – I should have recognized this a LONG time ago.  But hey, I’m human.

When you use code such as the following:

SPSecurity.RunWithElevatedPrivileges(delegate()
{

     using (SPSite site = newSPSite(urlToSite))
{

         using (SPWeb web = site.OpenWeb())
{

             // Do something
         }
}
});

if you use that code in a Web Part, Application Page, or I think Event Handler – i.e. any code that has Context inside SharePoint – the code runs as expected and will elevate your permissions to the Application Pool account.

However, if you try to use that same code in your Console application, and let’s say you update a list item, and you run it either in debug mode or just “regularly” by double-clicking the exe file, you will notice that last modified by is YOU – NOT your Application Pool account.

This is because there’s no SharePoint context.

Instead, you can create a batch file (like if you have input parameters) and use the “RunAs” method that Windows gives you (example, in Windows Server 2008 R2 you have to hold down Shift and Right-click the batch file, in order to get the Run As option).  If you’re setting up the job as a scheduled task through Windows, you simply have to set the account to the Application Pool account and specify that it should run whether or not the account is logged in.

SPD 2013 Workflows – Wait for Change booleans

The Scenario:

I have an approval process in my InfoPath form.  When the user presses a button called Approve or a button called Reject, it fills in 3 read-only fields:  ApprovalName (with currently logged in user name); ApprovalDate (with today); and Approval (Boolean with blank default – true means approved, false means rejected).

In SharePoint Designer 2010 what I would do is to use an action called “Wait for field change” (not sure if that’s the exact action name).  I would give it the ApprovalName field and say Wait until Field ApprovalName is not empty.

The reason I choose that field is because I do not wait to wait until Approval is true – because true means approved; what if it’s rejected?  I can’t wait for it to be false either for that same reason.  In 2010, it wouldn’t give you the choice for Boolean fields to say “is not empty” so I chose the text field instead, the person’s name, that gets auto-populated when the button is pressed.

The Problem:

I ran across 2 problems.  The first of which is that in SharePoint Designer 2013, with the 2013-compatible workflow, you can no longer choose things like “Contains”, “Is NOT Equal to”, “Is greater than”, “Is not Empty”, etc.  You can ONLY choose Is Equal To.  As a matter of fact, it’s not even a choice – it’s hard-coded right in there – you can’t even click “is Equal To”.

So what I figured I’d do, is to create another field in InfoPath called ApprovalCompleted as a Boolean, with false as the default.  When you press EITHER the Approve or Reject buttons, it turns the ApprovalCompleted field to true.

So I went in to SharePoint Designer and changed my Wait for Field Change to ApprovalCompleted.  For the value it wouldn’t allow me to fill anything in – it only gave me a Yes or No.  So I chose Yes.

No matter how many times I chose “True” in that blasted InfoPath Form, the Workflow would never get past that Wait for Field Change action – it never equaled.

The Solution:

I Googled around a bit and found that others had the same problem – Boolean fields just never match in a Wait for Field Change action.  I think it’s because it’s storing it as a 1 or 0 and the action expects “Yes” or “No”.

So there’s 2 ways of handling this.  One way is to go back into your InfoPath form and change ApprovalCompleted into a text field and have a textual representation of completion when they click the Approval or Rejection buttons.  That way you can set the Wait for Field Change action to equal a particular string that you’ve set in the InfoPath form.

The other way to do it is to set up a Calculated Field on the Form Library.  So to be clear, you need to promote ApprovalCompleted as a Boolean field (in this particular way of handling it) to the Form Library.  Then you go into the Form Library and create a new field, and call it something like ApprovalCompletedCalc.  Set its formula as just outputting the ApprovalCompleted field, and set its output format as a Number (doesn’t really matter if you use number or string here).  Now in your workflow, you need to Wait for Field Change to be the field ApprovalCompletedCalc and it needs to equal the value 1 – 1 for true, and 0 for false.  No quotes, just the number 1.

Extras:

Couple of interesting things to note.  First is, is that if you have that Calculated Field in your view, and you’ve TOLD it that it’s supposed to be a number, it’s still going to read as “Yes” and “No” EVEN THOUGH it’s really storing 0 and 1.  To be clear, do NOT set your SPD workflow to look for “Yes” or “No” – it needs to be 1 or 0.  But yes, the view is confusing and shows you the text.

Also, in SPD, in a condition, the Yes/No value seems to WORK right.  So if you say “If Approval Is Equal To Yes” it works right.  It captures the “true” or the 1.   So it’s just that other action, the wait for field change action, that is messed up.

 

SharePoint 2013, InfoPath and Claims – GetUserProfileByName

You would not believe the hoops you have to go through to get data auto-populated in an InfoPath Form if you’re using Claims-based authentication, which I believe is the default in SharePoint 2013.

The Scenario:

You have an on-premise SharePoint 2013 Server installation with InfoPath Forms Services (so you have enterprise) and you want to create an InfoPath form that auto-populates a logged in user’s ID, email, and phone number.  You are using Claims-based authentication in the web application in question.

In this scenario, I’m using InfoPath Designer 2010 – I haven’t upgraded to 2013 yet, but I don’t think it makes a difference.

The Problem:

When you use Claims-based authentication, your user name is prefaced by “0#.w|”.  So for example, if your user name is SuesDomain\jdoe then your Claims-based user token will be, without the quotes:     “0#.w|SuesDomain\jdoe”

InfoPath can’t handle that, or more specifically, the UserProfile.asmx method GetUserProfileByName method can’t handle that.  InfoPath tries to pass in your Claims-based user token instead of your domain\User Name.

You get 2 problems – you have an authentication problem where the currently logged in user is not allowed to hit the web service, so you get an Access Denied 401 authentication error.  The second problem is getting the right user from the web service.

The Solution:

The steps you have to take are listed here.  See the reference posts for more details and pictures.

  • Have your Active Directory team create you a User Name and Password for a “generic” InfoPath Account.  The one I created was called Domain\SP2013_IPRdr for “InfoPath Reader”.
  • Have the Central Administration team create a Secure Store service application, if they don’t already have one.
    • Generate the Secure Store key if you haven’t already.
    • Create a new application in the Secure Store called something like InfoPathGUPBN (“GetUserProfileByName” is what the acronym stands for); target application type is Group, and User Field Types are the Windows User Name and Password.
    • Set the credentials:  Whomever you want to administer the application should be set as the Target Application Administrators and for the Members, select All Users.
    • Set the Credentials to the Application and use the User Name and Password that you received from the A/D team, example Domain\SP2013_IPRdr.
  • In SharePoint 2013 – in the site you wish to publish your form to, create a Data Connection library.
  • Go Into InfoPath and go to your GetUserProfileByName secondary data connection.  If you don’t already have one, you can create one the “normal” way, making sure you do not choose a user name (just like you would normally do).  For an example of how to set one up, see the first reference in the section at the bottom of this post.
  • Modify the GetUserProfileByName secondary data connection so that it does NOT automatically load the data upon form load.  This is not required, but saves performance.
  • Convert the GetUserProfileByName secondary data connection into a UDCX file (“Convert to Connection File”) – store it in the Data Connection Library that you created a few steps ago.
  • Download the UDCX file that you just created from your SharePoint 2013 Data Connection library and put it on your desktop.  Edit it in Notepad.
  • Change the commented out line to read something like this (depending on what you called your Secure Store Application):
    <udc:Authentication><udc:SSO AppId='InfoPathGUPBN' CredentialType='NTLM' /></udc:Authentication>
  • Upload the UDCX file back in to the Data Connection Library.
  • Publish your newly changed InfoPath form into your SharePoint 2013 InfoPath Form Library
  • Make sure to give your special A/D account, for example the Domain\SP2013_IPRdr account, full read access to that site, so that they have permissions to hit the web service.

All of the above was just to get you to Authenticate properly with the Web Service.  If you were to stop now, and try to get the information from the web service you would get the information for the user Domain\SP2013_IPRdr.  Not the logged in user.  Now you have to take the following steps to get the real logged in user:

  • Go into InfoPath and go to create a Form Load rule
  • For the first rule, call it “Set User Profile” or something similar
    • Create an action to Set a Field’s Value
    • Choose the field – it’s the GetUserProfileByName secondary data connection, in the queryFields node, all the way in:  AccountName.
    • Set it to the following formula value:
      substring-after(userName(), "0#.w|")
    • Add another action, Query for Data, and choose your GetUserProfileByName secondary data connection
  • For the second rule, call it something like “Set Fields”
    • This is where you fill in your fields from the data source.  To find a good example of how to do this, see the first reference in the section at the bottom of this post.

Bottom line:  Pain in the rear.

References: