How it works: MOSS 2007 automatic user profile removal
13 November 09 11:24 PM

I have seen many posts filled with myths and legends how this actually works in MOSS 2007. This post is based on information received from SharePoint product group, my own research, debugging and testing to clarify the internals of this feature.

In MOSS 2007 the inactive user profiles are deleted by a timer job called “My Site Cleanup Job”.

my site cleanup job screenshot

This new job was the product group’s answer for customer feedback about the problems with SPS 2003 user profile removal to make it more robust.

The job runs once every hour which confused many people who thought that 3 full imports will delete users in MOSS 2007 as it was in SPS 2003. It is not the case anymore. You can do as many full imports as you like, if you disable this job, no user will be removed from the inactive user list. Since it runs hourly and full import can be long, 3 runs can take about 1 hour and it seems the full import did the trick, but in fact it did not.

To understand how this new feature works let’s start from the basics.

During the user import process (crawl) if MOSS cannot find a user in AD/LDAP directory it marks the user deleted in the SSP user profile store without removing it.

user deleted during import screenshot

You can check these users in the SSP administration site under user profiles and properties on the View user profiles page selecting the “Profiles Missing From Import” view. You can delete the profiles here manually.

missing profiles view in sssp admin site

This list is the input for the “My Site Cleanup Job”.

Let’s dive into the details.

The job in fact does two things every hour:

  1. Updates all personal sites and sets the mysite host as portal url
  2. Processes pending user profile deletes using the “profiles msissing from import” list

The following steps happen during user profile removal:

  1. Using the account name of the to be deleted user the job fetches the user profile
  2. Checks if the user is active using all defined import connections defined in this SSP
    1. LDAP connection is created to search for the user
      1. using it’s Username (domain\user) for Active directory connections. The filter is samaccountname=domain\user and the filter which was defined in the connection
      2. using the user porting of the AccountName , for eg user is used for an AccountName of “membershipprovider:user”. The filter is uid=user and the filter which was defined in the connection.
    2. After MOSS 2007 Sp2 if the user’s domain cannot be contacted the user is assumed inactive and user profile is removed.
    3. If all connections return zero results then the user is assumed inactive and the profile is removed.
  3. Just before the actual profile delete happens, the profile delete event handler is called. The event handler can cancel the deletion if it returns false in it’s PreProfileDeleted method implementation.
    1. The out-of-the-box event handler takes the manager of the to-be-deleted user and sets that user (if found) as the owner of the user’s my site.
    2. The manager gets an email with a subject of “The My Site of username is scheduled for deletion” and the url of the mysite.
    3. The event handler returns true for all users, there is no filtering.
  4. If the user is found in any of the import connections it’s deleted status is removed and the user is set active in the SSP.

Troubleshooting

To troubleshoot this feature you need to increase the trace level of “User Profiles” ULS category in central administration / operations / diagnostic logging.

Alternatively you can use stsadm to set it:

stsadm -o setlogginglevel -category "User Profiles" -tracelevel Verbose

Then verify all lines with “MySiteCleanup:” to follow what the job is doing.

I have to mention a special case of problem which is difficult to figure out. When an admin defines an import connection which uses a custom account, MOSS stores this setting in two locations. When you save the setting, a crawl rule is created for the Profile import project in the registry – since the user profile import is in fact a crawl, this is somehow expected. Furthermore the regularly called Synchronize method stores/updates this account information in the configuration database as well which is used by the “My Site Cleanup Job”. Sometimes these accounts gets out of sync and the “My Site Cleanup Job” tries to validate a user with invalid connection credentials. In this case usually the user profiles are not deleted automatically. To solve the problem, first of all resolve any exceptions which happen during the Synchronize method which is synchronizing the search settings on all SharePoint machines. Once the errors are gone, you need to delete the recreate the user profile import connections to ensure that the credentials are ready to be created again in the configuration database.

Postedby gyorgyh | (Comments Off)    
Site Directory: Customization of the categories form
29 August 09 03:45 PM

It is possible to add more values to the default categories and even add more categories or properties to fill for your users creating subsites or site collections. The customization method is the same for both.

  1. Create the new custom columns using the supported types:
    1. Choice column - it will be a DropDownList with the choices of the field.
    2. MultiChoice - it will be a checkbox list with the choices of the field.
    3. Lookup field (single or multi valued ) - it will be a DropDownList with the values of the lookup list items.
    4. Boolean field - it will be a checkbox.
    5. All other types (including People, DateTime) - it will be a simple textbox.
  2. Add the new columns to the “Site Creation Categories” view.

Step by step guide can be found on Office online here.

This is how it looks like with the OOB default columns selected on an English MOSS 2007.

Edit view: Sites screenshot

Be aware that adding a lookup field with hundreds of items will negatively affect your rendering performance, not to mention usability and end-user experience.

It is not possible to extend the supported types or register custom controls to handle the display logic. Therefore you cannot use People nd DateTime column types with your custom controls either.

Back to the table of contents.

Postedby gyorgyh | (Comments Off)    
Site Directory: FAQ
29 August 09 03:45 PM

Q: If I add multiple site directories which one will be the default for the “Create site” action?

A: The first site directory site created will be the default. You can change it in the top level site of your site collection in Site Actions / Site settings / Site directory settings. You need to enter the relative url of the new default site directory.

Q: I have multiple site directories in my farm in multiple site collections. Is there an out of the box feature to consolidate all of these site directory entries into a single  true “Master”  site directory. That should contain all site directories and all subsites and external sites added.

A: There is no such feature. You can create a timer job which uses the changetoken on the lists to synchronize all site directories into a single one but you have to be strict about the custom columns and choice values set in the various site directories throughout the farm to be able to consolidate them into a single one.

Q: Will stsadm  export / import affect Site directory operations?

A: Yes, import will create new GUIDs for all subsites and the GUIDs in the rootweb’s property bag will point to non-existing subsite. To fix this after the import you need to open the top level site of your site collection then Site Actions / Site settings / Site directory settings. You need to enter the relative url of the new default site directory after the import. If the relative url did not change ( same relative url in a different web application ) you just need to press OK to save the new GUID. This behavior of skipping updating web GUIDs in property bags during import is by design.

Q: Can I add more categories or other fields to the site directory form? Is it customizable?

A: Yes. Read the my customization post for details.

Q: What kind of column types are supported for the form?

A: Simple choice columns will be rendered as drop down list. Multiple choice column will be rendered as checkbox list. Lookup columns (single or multi valued ) will be rendered as drop down list. Boolean columns will be rendered as a single checkbox. For all other types it will be a simple textbox.

Q: Will the form be rendered for users who has no rights to write to the Site directory and their attempt is set to a failure?

A: Local site directory case : The form will not be displayed for a user with no rights on that web or list. However if the current user has view rights, the form will be displayed. During site creation the user will get an access denied page if he/she selected to add the subsite to the site directory  and an error will be logged to ULS if the Site Directory category trace level is High or above:

CreateSitePanel1: An exception occured in OnFormSave(). Exception: System.UnauthorizedAccessException: Access is denied.

The subsite will be created without a template. User will be presented with the “Select template” page on first access which indicates that subsite provisioning was not complete due to the access denied error in site directory.

If MOSS 2008 December rollup or later is installed (including MOSS SP2) and the default local site directory is used, the current user’s permissions are checked against the Sites list. Expected permissions: AddListItems, EditListItems, ViewListItems

For the master site directory security is checked for the application pool account and not for the current user. If the app pool account has no read rights on the web and the list, the form is not displayed. You can see an exception in ULS:

“CreateSiteCollectionPanel1: An exception occured in Site Categories panel. Setting CreateSiteCollectionPanel1 to not render. Exception: The request failed with HTTP status 401: Unauthorized”

If the app pool id user has read rights on both web and subweb but no write permissions, no error messages will be generated for the user, the new site collection won’t be added to the master site directory, all webservice calls finish with 200 OK but in ULS with Medium or above trace level for Site Directory category you can spot the error:

Adding site directory item with title of "team1" completed: <Results xmlns="http://schemas.microsoft.com/sharepoint/soap/"><Result ID="1,New"><ErrorCode>0x80070005</ErrorCode><ErrorText>The operation failed because an unexpected error occurred. (Result Code: 0x80070005)</ErrorText></Result></Results>

0x80070005 is access denied.

Q: How can I troubleshoot site directory problems?

A. Enable Site Directory ULS log category logging on Verbose trace level. Look for “Site Directory” entries after you reproduced the problem. For master site directory problem look for “CreateSiteCollectionPanel1” and “GetSiteDirectoryListInfo” tokens in your log and read the corresponding post to get more details how it works and at which step you need to start. Verifying IIS logs for the master site directory website is a good place to start to verify authentication and the webservices mentioned in the post.

For local site directory you need to look for “CreateSitePanel1” and check things with powershell, details in the corresponding post.

Back to the table of contents

Postedby gyorgyh | (Comments Off)    
How it works: Site Directory table of contents
14 August 09 12:27 AM

This is post was created to ease the navigation in the series.

Introduction

How it works: Site categories form for subsite creation

How it works: Site categories form for site collection creation

Site Directory: Customization of the categories form

Site Directory: FAQ

How it works: Site categories form for site collection creation
14 August 09 12:05 AM

This post is part of the Site directory troubleshooting series, you can access the other posts here.

So the focus is on the rendering and submit action of this form on the /_layouts/csignup.aspx page or /admin/createsite.aspx.

sitedir6

The major difference in the form rendering is the fact that the master site directory form is prepared to have the site directory even in another other SharePoint farm therefore local object model calls cannot be used to verify the web, list, view existence. Web service calls are used with the identity of the application pool account. In case of the /admin/createsite.aspx by default it will be the system account. On the  /_layouts/csignup.aspx page it will be the configured application pool identity. Single machine installs having network service as the default application pool account might run into permissions problems accessing master site directory on another farm due to machine accounts being used for the web service calls.

However you cannot set remote farm to be the default master site directory in central administration. You can enter a remote farm absolute url and click ok and receive no errors, but this won’t be persisted and next time you open the setting it will be unchanged. This is a side effect how SharePoint stored master site directory in the PortalService. The site id and web id stored instead of the url, and the siteid and webid looked up from the url in the local farm therefore saving a remote farm url cannot succeed. On the other hand the form rendering is fully capable of handling remote farm urls if the remote master site directory url is passed  as query string parameter.

This is the pre-requisite check process for the form rendering:

  1. Get the absolute path of the site directory subsite to be used
    1. Check if there is a query string parameter called sitedirectory passed in containing the url encoded absolute url of the site directory subweb in a site collection.
    2. If this is not specified in the query string or it is empty then SharePoint checks the PortalService instance for master site directory location data. This is stored in the configuration database.
    3. Then the site and subweb is opened using the ids retrieved in the local farm (no webservices are used here).  File not found exception is handled silently and empty string is returned for site directory url. If the site collection and web could be opened successfully, the subweb’s Url is returned. The current website’s Zone is used to retrieve this url so if you’re accessing the site collection creation page with a url from etc the Intranet zone, then the site directory url will be created using the Intranet zone as well, if there is no public url for that zone in AAM settings of the webapp of the master site directory than the default zone url will be returned.
  2. If the returned url is not null the form is displayed.
  3. SharePoint checks if the enforcement was turned on from the query string or the PortalService property and displays the checkbox accordingly.
  4. Same action to retrieve the entry requirements to decide if the user needs to specify value to all controls,only one or none.
  5. SharePoint uses $master_site_directory_url$/_vti_bin/lists.asmx using the application pool’s identity (not the logged on user’s id) to get the lists in the web. Iterates through the result and uses the title of the first list which has the site directory template type (300)
  6. Next step is to fetch the language of the subweb using the /_vti_bin/webs.asmx. Using the web’s language id SharePoint looks up the localized capture view name from a resource file. The view is called “Site Creation Categories” in English, for other languages you can check \12\resources\spscore.*.resx , it’s resource label is called SitesList_CaptureViewName_Text.
  7. If the list title or the capture title is empty, the controls won’t be added to the form.
  8. Otherwise SharePoint calls /_vti_bin/views.asmx webservice to get the view collection for the returned list title. Iterates through the result (if result is null, no control rendering) and locates the view GUID using the capture view’s title gathered in step 6.
  9. Then /_vti_bin/views.asmx webservice  is called again using the capture view GUID to get the view itself and its fields in a single call.
  10. Finally the /_vti_bin/lists.asmx webservice  is called to fetch the Sites list and its fields using the list title gathered  in step 5.
  11. Then SharePoint iterates through the fields of the capture view and looks up the same field in the list fields and renders the control for the corresponding field type:
    1. For Choice column it will be a DropDownList with the choices of the field.
    2. For MultiChoice it will be a checkbox list with the choices of the field.
    3. For Lookup field it will be a DropDownList with the values of the lookup list items. Here the /_vti_bin/lists.asmx webservice is called with the GetListItem operation to fetch the lookup list items.
    4. For Boolean field it will be a checkbox.
    5. For all other types it will be a simple textbox.
  12. If there is any problem encountered during the form field rendering depending on the error type the following line is logged into ULS if the Site Directory trace level is Medium or above:
    "CreateSiteCollectionPanel1: A SOAPServer exception occured in Site Categories panel. Setting CreateSiteCollectionPanel1 to not render. Exception: "
    "CreateSiteCollectionPanel1: An XML exception occured in Site Categories panel. Setting CreateSiteCollectionPanel1 to not render. Exception: "
    "CreateSiteCollectionPanel1: An exception occured in Site Categories panel. Setting CreateSiteCollectionPanel1 to not render. Exception: "

Note: there is a typo in the ULS log entry itself, I pasted as you will see it in the log.

On submit event depending on the entry requirements server side validation runs to check all field values or to ensure that at least one is filled out. Before the save operation all control rendering happens in the same sequence from step 5 to create the update XML with the correct field names and values which will be used in the /_vti_bin/lists.asmx webservice  in the UpdateListItems operation (again the application pool’s identity is used as in all site directory initiated webservice calls).

If there is a problem during the update XML creation , save operation can fail with "Update xml is unexpectedly empty.  No update performed." if the Site Directory category trace level is at least on Unexpected or above.

When the new list item is added in the site directory list in the site directory subweb using the webservice te following is logged in ULS if the Site Directory category trace level is at least on Medium or above (the placeholder between $ signs will be populated with real values) :

“Adding site directory item with title of "$new site collection’s title$" completed”

If there is an error during save the following line is logged into ULS if the Site Directory trace level is High or above
"CreateSiteCollectionPanel1: An exception occured in OnFormSave(). Exception: "

Note: there is a typo in the ULS log entry itself, I pasted as you will see it in the log.

Troubleshooting

If the form is not displayed on the site collection creation page 

  • First of all enable the Site Directory ULS category with Verbose trace level. You can find the cause of your form display issue with the ULS log entries. The CreateSiteCollectionPanel1 will log error messages if any of the web service calls fail.
  • Verify the full url in the sitedirectory  query string parameter if there is any in the browser’s address bar, try to remove the sitedirectory= section with the url value and try again to see if the local master site directory web can be determined automatically.
  • Verify Site directory settings in central administration website under Operations / Master Site directory settings. Enter the absolute url of the site directory subsite in the farm. The settings page does not give an error if the entered url was not created with the Site directory template so you have to open it again to verify if the path is not empty. If it is empty than the subweb you entered is not a valid site directory subsite.
  • You have to ensure that the web’s application pool identity has rights on the master site directory website. You can test it easily by logging on with that user to the SharePoint frontend and open the master site url in IE and try to add a new list entry to the Sites list.
  • You have to ensure that it is possible to access the absolute url of the master site directory from the server itself. This can be tricky since the public url can be returned of an AAM zone if the  site collection page was opened using a non-default internal url. So you have to guarantee that the server itself can resolve and connect to each public url of your web application which holds the master site directory.
    • If the public url is different from the servername, you can run into the LoopbackCheck security limitation, which will result authentication error – the server will not send any credentials to itself for unknown url. Solution: http://support.microsoft.com/kb/971382
      I suggest using the BackConnectionHostNames key if you have small number of public urls.
  • If you use external master site directory, you have to ensure that the server can resolve that url and the application pool identity of the site where you opened the create site collection page has rights on it.
  • Because by default Sharepoint uses automatic proxy server detection, you might run into proxy authentication errors or webservice call failures due to proxy usage for the local server.
    In the web.config file you can find the defaultProxy tag which controls this behavior.
    <system.net>
        <defaultProxy>
          <proxy autoDetect="true" />
        </defaultProxy>
      </system.net>
    You can turn proxy auto-detection off for the affected website to bypass default proxy usage. This will not affect the crawler’s proxy setting although it can cause problems for webparts accessing the internet (like RSS webpart).
  • Check the existence of the Sites list and the Capture.aspx view in it (“Site Creation Categories” in English, for other languages you can check \12\resources\spscore.*.resx , it’s resource label is called SitesList_CaptureViewName_Text). A view with this localized name must exists otherwise the form rendering will fail. You have to check furthermore if this view has any columns selected, since those columns will be rendered in the form.

Form submit fails and site collection is not added to the list.

  • Check ULS for the exception during list item addition.
  • Try to open the site directory list and add an item manually using the app pool identity user to verify if you receive an error. Try to resolve the error received.

Form submit succeeds and site collection is not added to the list.

  • Application pool identity has only read access to the Sites list in the master site directory and list addition webservice call fails with the following message in ULS with Medium or above trace level for Site Directory category you can spot the error:

    Adding site directory item with title of "team1" completed: <Results xmlns="http://schemas.microsoft.com/sharepoint/soap/"><Result ID="1,New"><ErrorCode>0x80070005</ErrorCode><ErrorText>The operation failed because an unexpected error occurred. (Result Code: 0x80070005)</ErrorText></Result></Results>

    0x80070005 is access denied. You might have other error code listed. Try to open the site directory list and add an item manually using the app pool identity user to verify if you receive an error as well. Try to resolve the error received.

  • Another similar error can happen when custom columns used in the Sites list were created by a feature and that feature is removed or gets corrupted on a frontend machine. The error returned in ULS looks like this with clear steps to follow:

    Adding site directory item with title of "test2" completed: <Results xmlns="http://schemas.microsoft.com/sharepoint/soap/"><Result ID="1,New"><ErrorCode>0x81020014</ErrorCode><ErrorText>One or more field types are not installed properly. Go to the list settings page to delete these fields.</ErrorText></Result></Results>

Back to the table of contents

How it works: Site categories form for subsite creation
14 August 09 12:04 AM

This post is part of the Site directory troubleshooting series, you can access the other posts here.

So the focus is on the rendering and submit action of this form on the /_layouts/newsbweb.aspx page.

sitedir6

This is the pre-requisite check process for the form rendering:

  1. Get the relative path of the site directory subsite to be used
    1. Check if there is a query string parameter called sitedirectory passed in containing the url encoded relative url of the site directory subweb in this site collection.
    2. If the query string is specified SharePoint returns with the urldecoded string passed in. If this url not specified in the query string or it is empty then SharePoint checks the rootweb of the site collection otherwise .  It looks for the SiteId and the WebId in the rootweb’s AllProperties bag. The actual keys are these DefaultSiteDirectorySiteId and DefaultSiteDirectoryWebId.
    3. Then the site and subweb is opened using the ids retrieved. Access denied and File not found exceptions are handled silently and empty string is returned for site directory url.
    4. If the web can be opened using the current user’s credentials SharePoint looks up the SiteDirectoryList. The first list with template type == 300 will be returned.
    5. Then SharePoint checks if the current user has the following rights on that list AddListItems, EditListItems, ViewListItems. (This check was introduced in 2008 December MOSS rollup and also included in MOSS Service Pack 2 and this check is not applied when query string contains the url due to step 2)
    6. If all checks succeed the relative url of the site directory subweb is returned otherwise empty string.
  2. If the returned url is not null the form is displayed.
  3. SharePoint checks in the rootweb’s AllProperties bag is the enforcement has been turned on with the EnforceNewListingForSites property and displays the checkbox accordingly.
  4. Same action to retrieve the entry requirements to decide if the user needs to specify value to all controls or only one.
  5. Open the subweb with url retrieved in step 1.
  6. Try to get the list, if the list cannot be retrieved (not exists, or read access denied) the following line is logged into ULS if the Site Directory trace level is High or above:
    ”CreateSitePanel: Site directory list was not found in the web:“
  7. In order to retrieve the View which specifies the fields to be displayed in the form SharePoint looks up the name of the view from core resource using the language of the site directory web.  The name of the view is localized, in English it is called “Site Creation Categories” - “Capture.aspx”.
  8. Then SharePoint enumerates the ViewFields property of the View and renders the control for the corresponding field type
    1. For Choice column it will be a DropDownList with the choices of the field.
    2. For MultiChoice it will be a checkbox list with the choices of the field.
    3. For Lookup field it will be a DropDownList with the values of the lookup list items.
    4. For Boolean field it will be a checkbox.
    5. For all other types it will be a simple textbox.
  9. If there is any problem encountered during the Form field rendering the following line is logged into ULS if the Site Directory trace level is Medium or above:
    ”CreateSitePanel1: An exception occured creating child controls. Setting CreateSitePanel1 to not render. Exception: “

Note: there is a typo in the ULS log entry itself, I pasted as you will see it in the log.

On submit event depending on the entry requirements server side validation runs to check all field values or to ensure that at least one is filled out.

Then a new list item is created in the site directory list in the site directory subweb with the new subweb’s title, description, url and the selected values of the form fields.

If there is an error during save the following line is logged into ULS if the Site Directory trace level is High or above
”CreateSitePanel1: An exception occured in OnFormSave(). Exception:”

Note: there is a typo in the ULS log entry itself, I pasted as you will see it in the log.

Troubleshooting

If the form is not displayed on /_layouts/newsbweb.aspx

  • Verify Site directory settings on the top level website in Site actions / Site settings / Site directory settings. Enter the relative url of the site directory subsite. The settings page does not give an error if the entered subweb was not created with the Site directory template so you have to open it again to verify if the path is not empty. If it is empty than the subweb you entered is not a valid site directory subsite.
  • Verify the subweb in the sitedirectory  query string parameter if there is any in the browser’s address bar, try to remove the sitedirectory= section with the url value and try again to see if the local site directory web can be determined automatically.
  • To easily verify the necessary user rights and possibly missing list or view ensure that you add the sitedirectory  query string parameter with your site directory’s relative web as value and enable the Site Directory ULS category with Verbose trace level. You can find the cause of your form display issue with the ULS log entries.
  • Verify the rootweb’s property bag looking for the site directory properties
  • Check the existence of the Sites list and the Capture.aspx view in it (“Site Creation Categories” in English, for other languages you can check \12\resources\spscore.*.resx , it’s resource label is called SitesList_CaptureViewName_Text). A view with this localized name must exists otherwise the form rendering will fail.

You can use the following powershell script to validate the root web’s property bag:

[Reflection.Assembly]::Load("Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c")

$sitecollurl = "http://bobmoss32:9000";
$site = new-object Microsoft.SharePoint.SPSite($sitecollurl
);

$web = $site.OpenWeb();

# Display all properties in a table

$web.AllProperties | ft

#Fetch the critical properties and check them

$strwebguid= $web.AllProperties["DefaultSiteDirectoryWebId"]
$strsiteguid= $web.AllProperties["DefaultSiteDirectorySiteId"]
if ($site.ID.toString("D") -ne $strsiteguid) {"Error: SiteID does not match current site's ID. Save site directory settings in site actions to fix it."}

# Verify subweb’s existence by its ID

"Checking subweb with ID:" + $strwebguid

$sitedirguid = new-object Guid($strwebguid)
$sdirweb = $site.OpenWeb($sitedirguid);
$sdirweb.Url

# if a valid web can be opened and url is returned then the property bag looks ok.

 

  • There is a specific scenario when a user can receive Access denied for the whole create subweb page – this is connected to a problem how site directory checks the rootweb’s properties. Scenario: a subsite owner whose subsite has unique assigned permissions and this owner has no rights on the root of the site collection wants to create a sub-subsite under his site and site directory is configured for tis site collection. In this case during the rootweb’s property bag check the user gets an access denied. This problem has been corrected in the MOSS 2008 December rollup. The fix for this is also included in MOSS Service Pack 2. After the fix the site directory form will not be displayed for such user due to permission issues but subsite creation will work.

 

Form submit fails and subsite is not added to the list.

  • Check ULS for the exception during list item addition.
  • Try to open the site directory list and add an item manually using the user to verify if you receive an error. Try to resolve the error received.

For the site collection form rendering and troubleshooting read the post here.

Back to the table of contents

How it works: Site Directory
11 August 09 11:38 PM

I’m writing a 5 parts troubleshooting post series about SharePoint 2007 Site Directory troubleshooting and in order to successfully troubleshoot a feature you need to understand how it works under the hood. This quite long post is part one of the series is about the details of Site Directory feature focusing on the site directory form rendering and entry addition to the Site Directory.

First of all Site Directory is a site template in MOSS 2007 enterprise edition under the Enterprise category.

sitedir1

The official documentation about the usage and purpose of Site Directory can be found here.

By default users are creating subsites (SPWeb) under the site directory website when they are using the create site button:

sitedir2

After you enable self-service site creation in Central admin site under Application Management / “Self-service site management” for the web application you can configure Site Directory to create site collections.

sitedir3

sitedir4

The Create site button will open /_layouts/scsignup.aspx in the root of the web application instead of /_layouts/newsbweb.aspx in the site directory subsite to create a site collection (SPSite) instead a subweb (SPWeb).

If you do not have a site collection created in the root you cannot enable Self-service site creation. It will fail with this error message:

sitedir5

It is good to keep in mind when you are designing your managed path / site collection creation strategy.

If you decide to create site directory site as a root site of a site collection (a top level website) you will face a problem with the Create Site button will have an incorrect url. (http://_layouts/newsbweb.aspx). Solution is described in the following KB article:Error message when you click "Create Site" on the tab that is located in the upper-right corner of the Site Directory page of a site collection: "Page cannot be displayed" http://support.microsoft.com/kb/925728

There is no such problem if you enable Self-service site creation though.

In order to successfully troubleshoot a Site Directory form display problem you must be able to verify if the user creates a site collection (/_layouts/scsignup.aspx  or /_admin/createsite.aspx) or a subsite (/_layouts/newsbweb.aspx)

You also have to keep in mind that each site collection  can contain multiple site directory subsites – each configures with different custom categories. However there is only one master site directory per farm. All three forms can receive the site directory url in query string and they can look it up automatically. If your customizations to the categories does not show up, make sure your new form is using the site directory you’ve just modified. For details, read on.

The Site categories form

This is the default form you will see out of the box.

sitedir6 

The form looks the same for both type of creation pages but the logic and the actions done after clicking “Create” are very different.

Since by this time you know if this is a subweb creation or a site collection creation you can read in the next posts how that specific form is rendered.

How it works: Site categories form for subsite creation

How it works: Site categories form for site collection creation

 

Back to the table of contents

Postedby gyorgyh | (Comments Off)    
How to display Web Application Policies with Powershell
28 March 09 02:32 AM

I had to create this script to troubleshoot the anonymous permission setting problem and I though it might come handy for you.

Let’s start with the usual SPSite creation

[Reflection.Assembly]::Load("Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c")
$site = new-object Microsoft.SharePoint.SPSite("http://bobmoss32:9000")

# Get the webapplication

$webapp=$site.WebApplication

# Display the global policies

$webapp.Policies

#Display global policies with RoleBindings

foreach ($zonepol in $webapp.Policies) {$zonepol;$zonepol.PolicyRoleBindings}

# Display the anonymous policy as well

$webapp.Policies.AnonymousPolicy

#Get the IIS zones and get the policies for each zone as well

foreach ($zone in $webapp.IisSettings.Keys) {$zone; $webapp.ZonePolicies($zone)}

#Display the RoleBindings as well with the per zone AnonymousPolicy

foreach ($zone in $webapp.IisSettings.Keys) {$zone; foreach ($zonepol in $webapp.ZonePolicies($zone)) {$zonepol;$zonepol.PolicyRoleBindings;$zonepol.AnonymousPolicy}}

Postedby gyorgyh | 1 Comments    
Trouble saving add or edit list items permissions for anonymous users
28 March 09 02:14 AM

I’ve recently come across an interesting issue regarding anonymous permission setting problem on custom lists.

Symptoms:

  1. Enable anonymous access on the web application’s authentication provider.
  2. Enable anonymous settings on the site collection.
  3. Create a custom list, set unique permissions, enable “add items” and “edit items” for anonymous users. anonymous settings2
  4. Press Ok.
  5. Open the page again, and the setting is not saved (only view items is selected)anonymous settings2result

Troubleshooting:

The list’s anonymous permission mask property shows correct permission mask:

[Reflection.Assembly]::Load("Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c")
$site = new-object Microsoft.SharePoint.SPSite("http://bobmoss32:9000")
$web=$site.OpenWeb();
$list=$web.Lists["anonlist"]
$list.AnonymousPermMask64
ViewListItems, AddListItems, EditListItems, OpenItems, ViewVersions, ViewFormPages, Open, UseClientIntegration, UseRemoteAPIs

This confirms that the settings were saved to the content database.

So what can override this mask? Well, it is called Web Application polices in Central Administration.

policywebapp 

Solution:

If you have any users defined for Deny Write, Deny Full (or any custom policy removing add or edit items permissions) that will also apply for the anonymous user as well. If you scope the policy for a single zone only, the other zones will not be affected. This behavior is by design according to the product group and cannot be changed.

If you think about it, this makes sense, you declared that a user or group of users cannot write to web application. If that user is opening the site as anonymous, how can you guarantee that he/she does not write to it?
Yes, you cannot allow anonymous writes, since you have to be sure that the anonymous user is not the one you forbid.

So if you need to allow for anonymous users to edit list items you need to remove all Deny policies for that zone and for any assigned to “all zones”.

Postedby gyorgyh | 1 Comments    
Troubleshooting Web Part property load errors
04 March 09 01:00 AM

Recently I came across an interesting problem on a SharePoint site which is worth a post.

Issue:

The Content Editor Web Part’s “Rich Test Editor…” button gives “Cannot retrieve properties at this time” error and does not load the content.

webpartprop1

The alert was generated from JavaScript and since we failed to retrieve something it is good idea to use Fiddler2 to see what is going on.

Behind the scenes a web service call is initiated to [siteurl]/_vti_bin/WebPartPages.asmx to get the properties of the Content Editor Web Part. Using Fiddler you can check the actual communication under the Inspectors tab, I prefer the Raw view and it is nice to have the gzip decode feature to see the response in plain text.

In the request we can see that the soap Body contains the GetWebPart2 call with some parameters. More interesting things can be seen in the response: we have interesting namespaces like xmlns:wsse and notice the soap headers like wsa:Action.

If you ever used Web Services Enhancements for Microsoft .NET Framework version 3.0 (WSE 3.0) these soap headers will be familiar. It seems this enhancement causes some trouble for SharePoint JS code which parses the GetWebPart2 result.

webpartprop2

Using the IE 8 Developer tools it wasn’t so difficult to find where we fail on client side. “WebPartPages.asmx” appears in ie55up.js in the GetPropCol function.

Setting a breakpoint and inspecting the parsing results is very easy with this JavaScript debugging tool.

webpartprop3

Now we know what the problem is, the WSE 3.0 section in the web.config of the site overrides the default soapServerProtocolFactory which will be applied for the _vti_bin virtual directory as well resulting unexpected WSE headers in the WebPartPages.asmx results. In the website’s root web.config you will find these which controls the problematic setting:

<webServices>
<soapExtensionImporterTypes>
  <add type="Microsoft.Web.Services3.Description.WseExtensionImporter, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</soapExtensionImporterTypes>
<soapServerProtocolFactory type="Microsoft.Web.Services3.WseProtocolFactory, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</webServices>

Solution:

There is a web.config file in the _vti_bin virtual directory in "c:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\ISAPI\"

Here we can override the soapServerProtocolFactory and set it back to the default.

Locate the </webServices> line and paste this above it in a single line:

<soapServerProtocolFactory type="System.Web.Services.Protocols.SoapServerProtocolFactory, System.Web.Services, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />

Save the file.

Now the web part property can be loaded and WSE 3.0 can be enabled for other custom web services.

Postedby gyorgyh | 1 Comments    
Customized MOSS 2007 discussion board definition
11 February 09 09:36 PM

As I mentioned in my previous post you can override the default behavior of the “Show Quoted Message” link.

You need to create a custom list template, it is very easy with Visual Studio 2008 and Visual Studio Extensions for SharePoint Services (VSEWSS) 1.3.

I will explain all steps from scratch.

  1. Install VS 2008 and VSEWSS 1.3 on your development SharePoint server with MOSS 2007 installed.
  2. Start Visual Studio and create a new project
  3. Select Visual C# / SharePoint in the tree and List definition in the templates. I used the AlwaysQuotedDiscussionBoard as name discussion1
  4. Open listdefinition.xml and replace “List Definiton1” and “Listdefinition1” to “Always Quoted DiscussionBoard” and “AlwaysQuotedDiscussionBoard”. This will ensure that the list template will have a non-default name.
    discussion2
  5. Open schema.xml and modify the list name and title in the second row.
    discussion4 
  6. Locate the definition of the field “CorrectBodyToShow”.
     discussion5
  7. Modify this field definition. There is an <IfEqual> section which controls the value of this computed column, that will be used later to decide if the “Show Quoted Message” link should be rendered. I removed the <IfEqual> with the two expressions, leaving only the internal <Switch> expression, within the outer <Default> tags.
    discussion6
  8. Save both modified files.
  9. Open the project properties (right click in the solution explorer on the project name) and on the debug tab edit the “Start browser with Url” field so it points to your site collection. Build and deploy the solution.

 

 

 

 

 

After a successful deployment open your site collection and in the create page you will see your new customized list.

discussion7Be aware that when you edit your reply, this modified discussion board will show the original reply since you’ve edited the “Quoted Message” while the original short reply is in a hidden column. So the modification will only show up if you click the link. So keep in mind that this implementation has limits.

Postedby gyorgyh | (Comments Off)    
Filed under: ,
How it works: Show Quoted Messages link in MOSS 2007 Discussion boards
11 February 09 09:20 PM

If you ever wondered why would  the “Show Quoted Messages” link disappear once you edited a reply, I have an answer for you.

The explanation can be found in the schema.xml at "c:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\FEATURES\DiscussionsList\Discuss\schema.xml"

at the computed hidden field definition

<Field ID="{b0204f69-2253-43d2-99ad-c0df00031b66}" Name="CorrectBodyToShow"

<IfEqual>

<Expr1>

<Column Name="Created"/>

</Expr1>

<Expr2>

<Column Name="Modified"/>

</Expr2>

<Then>

<Switch>

<Expr>

<Field Name="IsRootPost"/>

</Expr>

<Case Value="TRUE"><HTML>Body</HTML>

</Case>

<Default>

<Switch>

<Expr>

<Column Name="TrimmedBody"/>

</Expr>

<Case Value=""><HTML>Body</HTML>

</Case>

<Default><HTML>TrimmedBody</HTML>

</Default>

</Switch>

</Default>

</Switch>

</Then>

<Else><HTML>Body</HTML>

</Else>

</IfEqual>

This means if the created and modified time was not equal then TrimmedBody returned for this value which will eventually cause the rendering to use that field value to be displayed with the link. Otherwise the field value Body is returned and the link is not displayed.

This means that if you have content approval required set on a discussion board and someone approves an item, the link will disappear.

This behavior was implemented with the following mindset, if you edit your reply, only the Body field will be updated, the TrimmedBody field will not be changed. That is only populated on reply creation. This means that the edited reply will only show up if the full Body field is displayed.

It is possible to override this behavior using a custom discussion board list definition, implementation details can be found here.

Postedby gyorgyh | 1 Comments    
How it works: MOSS 2007 User Profile Import
07 February 09 10:15 PM

I often face the problem of missing documentation of MOSS 2007 operations at high level, it is documented how to configure it and the very low level details in protocol specification.

Profile import is using the crawler component of MOSS search. A user profile import is actually a crawl of special content - people.

It is using the same pipeline mechanism with mssearch.exe and mssdmn.exe , the difference is that during profile import the crawler uses a protocol handler written for AD,  LDAP connections to handle AD users, groups and AD/LDAP properties.

LDAP and AD connections are called primary connections because these can import new user profiles. BDC connections are called secondary since they can only add supplementary properties to already imported user profiles from custom data source like SQL or other enterprise applications.

The integration can also be noticed when you check the import log which is the same as the crawl log.user profile import log

Profile import is using two special content sources PEOPLE_IMPORT and PEOPLE_DL_IMPORT and uses with a special start url using spsimport:// prefix.

dlimportlog 

User profile import process has 5 main steps:

  1. Enumerating and caching DC connections based on the import settings.
  2. Enumerating users from AD or LDAP repository using the specified filter. This step will add each detected user to the crawl queue.
    enumerating 
  3. Getting profile properties according to the mappings and default columns user by user using the crawl queue and update the temporary tables and commit changes in batches.
    importing
  4. Importing group information (PEOPLE_DL_IMPORT using start address suffixed by $$$dl$$$) based on the memberof properties of the imported users. (so only those groups get into the SSP database where the group contains a member imported and the DC/LDAP server returns valid memberof field for that user – this due to performance reasons)
  5. Computing recursive membership information in SQL SSP database: flattening hierarchical group membership tree  to be able to resolve users quickly. This time the application servers seem to be idle, SQL server is doing this part of the import.

Incremental profile imports are supported when the AD connection account has rights to query the replication changes from the DC.

More information:

User Profiles and Audience Targeting Overview

http://msdn.microsoft.com/en-us/library/ms573802.aspx

Managing User Profile

http://technet.microsoft.com/en-us/library/cc263325.aspx

Postedby gyorgyh | 1 Comments    
MOSS 2007 interesting authentication behavior
26 January 09 11:59 PM

I have an interesting problem to share with you; I came across a site collection where any authenticated users can log in with their account without giving them explicit permissions in any groups. It is interesting since usually this is the other way around - users gets denied. These users had no write permissions but could see all document libraries and lists. You might think that it’s easy, authenticated users were added with Full read in web application policies, but it wasn’t. The solution is more elegant in fact, anonymous access was enabled on the site collection and then it was turned off in the web application authentication provider page. This resulted in an interesting situation, the web still had it’s anonymous access enabled, however since it is unchecked on the authentication providers, you cannot see the setting in advanced permissions in the site settings page.

Enable anonymous access is disabled

Anonymous setting is missing

After the anonymous access is enabled in the authentication providers page an application pool recycle happens and after refresh in IE the setting appears in advanced permissions / settings.

anonyous setting can be seen

Now it is possible to turn off anonymous access to fix the behavior.

anonymous settings page1

Setting it to nothing and turning off the checkbox the anonymous access solved the problem.

If you cannot allow an application pool recycle or enabling anonymous access, you can access the page directly and set anonymous access option to nothing on the web.

Open http://server/sites/testsite/_layouts/setanon.aspx and you will see this, showing the previous setting disabled.

anonysettingspage

If you need to check this from powershell, you can use this script sample to check the setting and the details of the assigned permission.

[Reflection.Assembly]::Load("Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c")
$site = new-object Microsoft.SharePoint.SPSite("http://bobmoss32:8000")
$web = $site.OpenWeb()
$web.AllowAnonymousAccess
True
$web.AnonymousPermMask64
ViewListItems, ViewVersions, ViewFormPages, Open, ViewPages

The AllowAnonymousAccess property is read-only, however you can use the AnonymousPermMask64 to turn anonymous access off if you have permissions and on Windows 2008 you have started the powershell with “run as administrator”

$web.AnonymousPermMask64 = [Microsoft.SharePoint.SPBasePermissions]::EmptyMask
$web.Update();

To set “Lists and Libraries” use

$web.AnonymousPermMask64 = [Microsoft.SharePoint.SPBasePermissions]::Open
$web.Update();

To set to Entire Web site

$web.AnonymousPermMask64 = [Microsoft.SharePoint.SPBasePermissions]::ViewListItems -bor[Microsoft.SharePoint.SPBasePermissions]::ViewVersions -bor[Microsoft.SharePoint.SPBasePermissions]::ViewFormPages -bor[Microsoft.SharePoint.SPBasePermissions]::Open -bor[Microsoft.SharePoint.SPBasePermissions]::ViewPages
$web.Update();
Postedby gyorgyh | (Comments Off)    
MCMS 2002 and ASP.Net Framework 3.0
21 January 09 09:49 PM

There are several problems with MCMS 2002 server when you have ASP.Net Framework 3.0 installed on the server. According to official Microsoft documentation .Net 3.0 is not supported with MCMS 2002.

Microsoft Content Management Server 2002 with Service Pack 2 (SP2) supports the following features of Microsoft ASP.NET 2.0:

  • Authorization Providers
  • Navigation Providers
  • Master Pages

Other features of ASP.NET 2.0 are not supported.

More information on Sp2 can be found here

Solution for the installation problem with Site Manager

This problem is caused by the missing separate J# for .Net Framework 3.0. The Visual J# 2.0 Second Edition supports .Net 3.0 but the detection mechanism of the MCMS setup utility was developed with .Net Framework 1.0 and 1.1 in mind. If you try to install Site Manager you get the message of missing pre-requisite of the non-existing Visual J# 3.0.

mcms install screen clipping 1 showing missing pre-requisite

Follow these steps to install MCMS 2002 on a server with .Net Framework 2.0 and 3.0 installed.

The detection code checks the existence of vjslib.dll in directory of the highest installed .Net version but does not check if the file is a valid J# dll.

Postedby gyorgyh | (Comments Off)    
Filed under:
More Posts Next page »

This Blog

Syndication

Page view tracker