Monday, December 1, 2014

Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information

I have been using the following Powershell to browse around some assemblies
$assembly = [Reflection.Assembly]::Load('myassembly')
$assembly.GetTypes()

Sometimes, I get the following exception:
Exception calling "GetTypes" with "0" argument(s): "Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information."
At line:1 char:19
+ $assembly.GetTypes <<<< ()
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException


To get at the actual error, I use the following:
$x = $Error[0]
$x.Exception.InnerException.LoaderExceptions

Then all I had to do was to load the assemblies that were listed and my initial Load() now works.

Wednesday, November 5, 2014

The query cannot be completed because the number of lists in the query exceeded the allowable limit.

I have recently come across an error where our code is calling GetSiteData with a query and was returning this error:
The query cannot be completed because the number of lists in the query exceeded the allowable limit. For better results, limit the scope of the query to the current site or list or use a custom column index to help reduce the number of lists.
I then built the following powershell to mimic our code in order test it:

$web = Get-SPWeb some-url

$query = New-Object Microsoft.SharePoint.SPSiteDataQuery
$query.Webs = '<Webs Scope="Recursive">'
$query.Query = "<Where><And><Eq><FieldRef Name='_ModerationStatus' /><Value Type='Number'>0</Value></Eq><BeginsWith><FieldRef ID='{03e45e84-1992-4d42-9116-26f756012634}' /><Value Type='Text'>0x0110</Value></BeginsWith></And></Where><OrderBy><FieldRef Name='PublishedDate' Ascending='FALSE' /></OrderBy>"
$query.ViewFields = '<FieldRef Name="_ModerationStatus"/><FieldRef Name="Title"/><FieldRef Name="ID" /><FieldRef Name="Permalink"/><FieldRef Name="PublishedDate"/><FieldRef Name="Body"/><FieldRef Name="NumComments"/><FieldRef Name="Author"/><FieldRef Name="ContentType"/><FieldRef Name="ContentTypeId"/>'
$query.Lists = "<Lists BaseType='0'/>"
$query.RowLimit = [uint32]::MaxValue

$web.GetSiteData($query)


From what I have read about the call to GetSiteData, when SharePoint performs the query, it takes into consideration the lists that match the criteria passed in the query. It then returns a DataTable with a limit of RowLimit rows. However, since we have not set a MaxListLimit the query simply fails at 1000 lists (instead of giving you the first 1000). There is a parameter we can change in the code $query.Lists = "<Lists BaseType='0' MaxListLimit='0'>" which will allow the query to consider over 1000 lists, however, I am not sure about the performance impact.

References:
SPWeb.GetSiteData method
SPSiteDataQuery.Lists property - see description of MaxListLimit


Monday, November 3, 2014

SharePoint picture library not generating thumbnail and websize images

I recently came across a problem in a customer's site where the thumbnail and websize version of an image was not being generated. Typically when you upload an image to a picture library, a thumbnail and a websize version of that image are generated by SharePoint and saved into the /_t/ and /_w/ subfolders. For example, if upload an image to /Shared Pictures/image.jpg, then SharePoint also automatically generates /Shared Pictures/_t/image_jpg.jpg and /Shared Pictures/_w/image_jpg.jpg

For some reason, this was not happening. When you view the picture library with the default view, all the pictures were showing a blank image (since they use the thumbnail version).

Reaching out to Microsoft Support, it turns out that for these libraries, the parent SPWeb had the ParserEnabled property set to false.

The MSDN description of the SPWeb.ParserEnabled Property is quite useless.

Fortunately, I found a blog discussing this: http://neels-indites.blogspot.ca/2012/06/sharepoint-spweb-property-parserenabled.html. According to this blog, having ParserEnabled=false will cause the following:

  • Cannot search in document library using Office document properties
  • When you upload an image file, the thumbnail and websize images will not be generated
  • When you save a list template, you will not see it in the list template gallery.





Thursday, October 2, 2014

Lists.asmx GetListCollections and GetListItems example

I recently had to get all items of a list as well as all lists in a SPWeb. This involved calling Lists.asmx. For the service description of Lists.asmx just go to /_vti_bin/lists.asmx

Get all lists for some SPWeb

$webUrl = 'some-web-url'

$credential = Get-Credential -Message "Enter your login for $($webUrl)"

$uri = [uri]"$($webUrl)/_vti_bin/lists.asmx"

$contentType = 'text/xml'
$bodyString = @"
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<GetListCollection xmlns="http://schemas.microsoft.com/sharepoint/soap/" />
</soap12:Body>
</soap12:Envelope>
"@

$result = Invoke-WebRequest -Credential $credential -Method Post -Uri $uri -Body $bodyString -ContentType $contentType
$xml = [xml]$result.Content
$xml.Envelope.Body.GetListCollectionResponse.GetListCollectionResult.Lists.List

Get all list items for some list

$webUrl = 'some-web-url'
$listName = 'some-list-name'

$credential = Get-Credential -Message "Enter your login for $($webUrl)"

$uri = [uri]"$($webUrl)/_vti_bin/lists.asmx"

$contentType = 'text/xml'
$bodyString = @"
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<GetListItems xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<listName>$($listName)</listName>
<viewName></viewName>
<rowLimit>5000</rowLimit>
<query>
<Query xmlns="">
<OrderBy> <FieldRef Name="ContentType" /> </OrderBy>
</Query>
</query>
<viewFields><ViewFields xmlns="" /></viewFields>
<queryOptions>
<QueryOptions xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns>
<IncludeAttachmentUrls>TRUE</IncludeAttachmentUrls>
<ViewAttributes Scope='RecursiveAll' IncludeRootFolder='True' />
<DateInUtc>TRUE</DateInUtc>
</QueryOptions>
</queryOptions>
</GetListItems>
</soap12:Body>
</soap12:Envelope>
"@

$result = Invoke-WebRequest -Credential $credential -Method Post -Uri $uri -Body $bodyString -ContentType $contentType
$xml = [xml]$result.Content
$xml.Envelope.Body.GetListItemsResponse.GetListItemsResult.listitems.data.ItemCount
$xml.Envelope.Body.GetListItemsResponse.GetListItemsResult.listitems.data.row | Format-Table ows_LinkFilename, ows_Author, ows_Created, ows_Modified -AutoSize

I could probably use New-WebServiceProxy and skip all the SOAP envelope stuff. However, this better mimics the code that I was trying to troubleshoot.


Monday, May 26, 2014

The solution cannot be deployed. The feature 'some-feature-id' uses the directory "some-directory" in the solution

I recently came across this error when trying to deploy a WSP:
The solution cannot be deployed.  The feature 'some-feature-id' uses the directory "some-directory" in the solution. However, it is currently installed in the farm to the directory "some-other-directory". Uninstall the existing feature before you install a new version of the solution.

Simple enough, I tried to do an Uninstall-SPFeature as well as Uninstall-SPFeature -Force both of which did not help. Finally someone tried stsadm -o uninstallfeature and then the subsequent WSP deploy worked. I guess Powershell and stsadm are not quite equivalent


Calling private member using reflection in Powershell

Often I have to put together some Powershell scripts for troubleshooting. These scripts are based on some c# code. Recently, I had to mimic the behaviour of a call to a private member overload of GetTags in the Microsoft.Office.Server.SocialData.SocialTagManager class.

$site = Get-SPSite my-site-url
$context = Get-SPServiceContext($site)
$socialTagManager = New-Object -TypeName Microsoft.Office.server.SocialData.SocialTagManager -ArgumentList $context

# Get the type definition
$type = [type]'Microsoft.Office.Server.SocialData.SocialTagManager'

# List the GetTags members
($socialTagManager | Get-Member GetTags).Definition.Replace("), ", ")`n")

This results in (just the public members):
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(Microsoft.Office.Server.UserProfiles.UserProfile user)
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(Microsoft.Office.Server.UserProfiles.UserProfile user, int maximumItemsToReturn)
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(Microsoft.Office.Server.UserProfiles.UserProfile user, int maximumItemsToReturn, int startIndex)
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(System.Uri url)


Now use Reflection

# Which methods to list
$bindingFlags = [Reflection.BindingFlags] "Default,NonPublic,Instance"

# List the methods
$type.GetMethods($bindingFlags) | Where-Object {$_.Name -eq 'GetTags'} | ForEach-Object {$_.GetParameters() | Select-Object Member -First 1}

This results in (both public and private members);
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(System.DateTime, System.DateTime)
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(System.DateTime, System.DateTime, Int32)
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(System.DateTime, System.DateTime, Int32, Int32)
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(System.Uri, Microsoft.Office.Server.UserProfiles.UserProfile, System.Nullable`1[System.DateTime], System.Nullable`1[System.DateTime])
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(System.Uri, Int32)
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(System.Uri, Int32, Microsoft.Office.Server.SocialData.SocialItemPrivacy)
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(Microsoft.SharePoint.Taxonomy.Term[], Int32, Microsoft.Office.Server.SocialData.SocialItemPrivacy)
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(Microsoft.Office.Server.UserProfiles.UserProfile, Int32, Int32, Boolean, System.Nullable`1[System.DateTime], System.Nullable`1[System.DateTime])
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(Microsoft.Office.Server.UserProfiles.UserProfile, Int32, Int32, Boolean, System.Nullable`1[System.DateTime], System.Nullable`1[System.DateTime], System.Nullable`1[System.Guid])


Now to call a private member. Let's call: Microsoft.Office.Server.SocialData.SocialTag[] GetTags(System.DateTime, System.DateTime, Int32, Int32)


$startTime = [DateTime]'2014-05-01 00:00:00'
$endTime = [DateTime]'2014-05-31 00:00:00'
$maximumItemsToReturn = 1000
$startIndex = 0
$typeList = @([type]'DateTime', [type]'DateTime', [type]'Int32', [type]'Int32')
$method = $socialTagManager.GetType().GetMethod('GetTags', $bindingFlags, $null, $typeList, $null)
$terms = $method.Invoke($socialTagManager, [Object[]] @($startTime, $endTime, $maximumItemsToReturn, $startIndex))
$terms | Format-Table @{l='Term';e={$_.Term.Name}}, Title -AutoSize




Sunday, May 25, 2014

Get all features that define Site Settings links

Recently, I needed to find out where a particular link listed under Site Settings. Doing a bit of research on how to add links to a Site Settings page involves defining a CustomAction in the Elements.xml file with a Location of Microsoft.SharePoint.SiteSettings. Reversing this logic, we can find all Elements.xml files that contains a line Location="Microsoft.SharePoint.SiteSettings" and from there work backwards to get the SharePoint feature.

Here is a Powershell that does this:
Get-ChildItem -Recurse -Filter *.xml | Select-String -Pattern 'Microsoft.SharePoint.SiteSettings' | Group-Object path | ForEach-Object {$x = $_.Name; Get-SPFeature | Where-Object {$x -like "$($_.RootDirectory)*"}} | Format-Table Id, Scope, @{l='Title';e={$_.GetTitle(1033)}} -AutoSize

This script can easily be modified to find other menu items by changing the Select-String -Pattern to something else such as Microsoft.SharePoint.StandardMenu.

Tuesday, April 1, 2014

SharePoint Timezone Settings

I recently had to troubleshoot some SharePoint Timezone issues. There are a bewildering number of places where this may be a factor:

These are nicely summarized at http://www.techgrowingpains.com/2012/05/sharepoint-time-zone-confusion-2/

  • Web Application Level
    • Central Administration->Manage Web Applications
    • Select your web application
    • Select General Settings
    • Default Time Zone: Select time zone
  • Site Collection Level
    • Go to your site collection
    • Site Actions->Site Settings->Regional Settings
    • Select time zone
  • User Level
    • Welcome menu (aka Personal menu, aka the menu with your name on it)->My Settings->My Regional Settings
    • Uncheck Always follow web settings (if checked)
    • Select time zone


There is also
  • Server time zone (across all farm servers)
  • Desktop time zone