Tuesday, August 11, 2009

Sharepoint or Sharepoint Central Admin Returns Error “The File Exists (Exception from HRESULT: 0x80070050)

One of my clients is a financial institution. As such, they have pretty stringent controls on user accounts for vendors that may need to work on their system. Several months ago, I was brought in to do an install of Business Portal, which requires SharePoint.

I was given a temporary admin level userid to use during the setup, which I used to install and configure SharePoint and Business Portal.

Today I was called back to resolve some issues with Business Portal. When I tried to log back into SharePoint, my access was denied. I tried to get to Central Admin and received the error – The file exists. (Exception from HRESULT: 0x80070050).

Basically, what has happened is that the user account I was given initially was deleted after the initial install was completed and then recreated when I was asked to come back and repair Business Portal. They also never created another Admin login for the Central Admin and SharePoint sites. When the new account was created, AD issued a new SID (Security ID) which is the string of characters that REALLY defines your account. Your username is just a descriptive field. SharePoint provides access based on the SID, not just the username field. So, my username is the same, but the SID is different, preventing me from getting to SharePoint. The problem is that my account is the ONLY one that has rights – not a good situation for the client to be in.

Fixing this problem….well, it’s not a simple procedure. I’ve spent nearly two hours now researching and testing ways of getting the SID updated in the SharePoint database.

Here’s the procedure to go through to get the SID changed for a user in SharePoint. You’ll definitely earn your Geek badge for this one.

ts-geek.lg[1]

WARNING: This is a low-level solution, requiring hackery and other risky behaviors. USE AT YOUR OWN RISK ONLY AFTER YOU HAVE A BACKUP.

Procedure:

  • Get the SID listed in SharePoint
  • Get your current SID from Active Directory
  • Convert your current SID from binary SID to HEX
  • Update the database with the new HEX value

Simple sounding, not so much in real life. After much searching and trial and error, here are the source files you’ll need to accomplish this.

1) Get the SID listed in Sharepoint

Connect to your SQL Server and run the following query on the AdminContent database for your SharePoint install:

SELECT Sites.Id, Webs.FullUrl FROM Sites inner join Webs on Sites.RootWebId = Webs.Id

This will give you a list of the sites and associates URL’s that SharePoint knows about. Copy the Site ID to your clipboard.

You’ll now run this script that will get you the other information you need – including the user’s SID which is in the tp_SystemID field. Paste your Site ID from above into the XXXX space below.

SELECT * FROM UserInfo WHERE tp_SiteID='XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'

If you don’t mind filtering through a long list manually, you can just skip the 1st step and run this query -

SELECT * FROM UserInfo

This will get you a list of the usernames for that site.

2) Get your current SID from AD and convert to HEX

This is the part that took a long time to figure out. Fortunately, I came across a Visual Basic Script that will accomplish the task in one fell swoop.

You’ll want to copy the following text into NotePad and then save it as getSID.vbs. Note the portion in yellow below, you’ll need to replace it with the user’s AD context information. If you don’t know what the context is, use the dsquery command listed below the script to retrieve it.

GETSID.VBS

Option Explicit
Dim objUser, arrSid, strSidHex, objTrans, strUserDN, strSidDec
' Constants for the NameTranslate object.
Const ADS_NAME_INITTYPE_GC = 3
Const ADS_NAME_TYPE_1779 = 1
Const ADS_NAME_TYPE_SID_OR_SID_HISTORY_NAME = 12
' Bind to object. REPLACE WITH YOUR AD INFO 
Set objUser = GetObject("LDAP://cn=Test,ou=Sales,dc=MyDomain,dc=com")
' Retrieve SID and convert to hex string, then to decimal string.
arrSid = objUser.objectSid
strSidHex = OctetToHexStr(arrSid)
Wscript.Echo strSidHex
strSidDec = HexStrToDecStr(strSidHex)
Wscript.Echo strSidDec
' Use the NameTranslate object to convert objectSid to
' Distinguished Name.
Set objTrans = CreateObject("NameTranslate")
' Initialize NameTranslate by locating the Global Catalog.
objTrans.Init ADS_NAME_INITTYPE_GC, ""
' Use the Set method to specify the SID format of the object name.
objTrans.Set ADS_NAME_TYPE_SID_OR_SID_HISTORY_NAME, strSidDec
' Use the Get method to retrieve the Distinguished Name of the user object.
strUserDN = objTrans.Get(ADS_NAME_TYPE_1779)
Wscript.Echo strUserDN
Wscript.Quit
Function OctetToHexStr(arrbytOctet)
' Function to convert OctetString (byte array) to Hex string.
Dim k
OctetToHexStr = ""
For k = 1 To Lenb(arrbytOctet)
OctetToHexStr = OctetToHexStr _
& Right("0" & Hex(Ascb(Midb(arrbytOctet, k, 1))), 2)
Next
End Function
Function HexStrToDecStr(strSid)
' Function to convert hex Sid to decimal (SDDL) Sid.
Dim arrbytSid, lngTemp, j
ReDim arrbytSid(Len(strSid)/2 - 1)
For j = 0 To UBound(arrbytSid)
arrbytSid(j) = CInt("&H" & Mid(strSid, 2*j + 1, 2))
Next
HexStrToDecStr = "S-" & arrbytSid(0) & "-" _
& arrbytSid(1) & "-" & arrbytSid(8)
lngTemp = arrbytSid(15)
lngTemp = lngTemp * 256 + arrbytSid(14)
lngTemp = lngTemp * 256 + arrbytSid(13)
lngTemp = lngTemp * 256 + arrbytSid(12)
HexStrToDecStr = HexStrToDecStr & "-" & CStr(lngTemp)
lngTemp = arrbytSid(19)
lngTemp = lngTemp * 256 + arrbytSid(18)
lngTemp = lngTemp * 256 + arrbytSid(17)
lngTemp = lngTemp * 256 + arrbytSid(16)
HexStrToDecStr = HexStrToDecStr & "-" & CStr(lngTemp)
lngTemp = arrbytSid(23)
lngTemp = lngTemp * 256 + arrbytSid(22)
lngTemp = lngTemp * 256 + arrbytSid(21)
lngTemp = lngTemp * 256 + arrbytSid(20)
HexStrToDecStr = HexStrToDecStr & "-" & CStr(lngTemp)
lngTemp = arrbytSid(25)
lngTemp = lngTemp * 256 + arrbytSid(24)
HexStrToDecStr = HexStrToDecStr & "-" & CStr(lngTemp)
End Function

This script will give you pop-up messages with the HEX value of the userid you’ve searched for. Unfortunately, you can’t copy and paste. So, VERY CAREFULLY transcribe it into notepad and then copy to your clipboard.

Future upgrade: I’ll try and see if I can revise the script to export to a text file instead.

DSQuery:

This command line will have to be run from a server that is AD aware and has the DSQuery utility. Easiest option is to run it from your AD Controller. In this example, we return any userid that starts with the letters JE. So for me, where my userid is RYoder, I’d use RY*

dsquery * domainroot -filter "(&(objectCategory=Person)(objectClass=User)(sAMAccountName=je*))" -attr sAMAccountName distinguishedName ObjectSid -Limit 0

 

3) Update the database with the new HEX value

Run the following script against the Content database. NOTE: You’ll need to append the 0x to the front of the HEX string you found above.

Replace the X with the tp_ID of the user you are trying to update.

UPDATE UserInfo SET tp_SystemID = 0x010500000000000000000986BD9EA976E44036C3F5D3F04040000 WHERE tp_ID = 'X'

You should now have access to the content database. Note,  you’ll also want to run this update against any other content databases that are out there – usually one exists for each web application, otherwise you’ll get an Access Denied error when trying to hit the site.

 

sleep_desk_full[1]

That’s it! Enough for now, my brain hurts just typing this!

3 comments:

DeliriousAmbiguity said...

Wow. I'm speechless and in awe of your geekiness. I tip my hat to you, sir.

-Walter

compute4Christ said...

Hi,
I keep getting this error when running the UPDATE.

"Msg 2601, Level 14, State 1, Line 2
Cannot insert duplicate key row in object 'dbo.UserInfo' with unique index 'UserInfo_SID'.
The statement has been terminated."

Am I missing something? Here is my command:

UPDATE UserInfo SET tp_SystemID = 0x0105000000000005150000006D0DF27D1943052D8F2F4B7E926E0000 WHERE tp_ID = '13'

Guillaume B. said...

http://vspug.com/dustin/2007/04/08/stsadm-in-a-gui-2007-version/


UPDATE UserInfo
SET tp_systemid = suser_sid('DOMAIN\testUser') WHERE tp_login='DOMAIN\testUser'