Showing posts with label SharePoint 2013. Show all posts
Showing posts with label SharePoint 2013. Show all posts

Wednesday, June 28, 2017

Grabbing EML files from drop folder before job-email-delivery gets them

Often when troubleshooting incoming email problems in SharePoint, we would temporarily disable the Microsoft SharePoint Foundation Incoming E-Mail (job-email-delivery) timer job, then send an email and watch the folder for an EML file to show up.

Alternatively, you can register a FileSystemWatcher to listen on a Created event. Then, this code can copy out the EML file to some safe place before job-email-delivery gets it.

To install the listener:

$destination = 'c:\Windows\Temp\maillogs' # Make sure your powershell user can write here
$dropFolder = 'C:\inetpub\mailroot\Drop' # Drop folder as configured in SharePoint

$filter = '*.eml'

$fsw = New-Object System.IO.FileSystemWatcher($dropFolder, $filter)
$fsw.IncludeSubdirectories = $false
$fsw.NotifyFilter = [System.IO.NotifyFilters]'FileName,LastWrite' # seems to need this to avoid some IOExceptions

$onCreated = Register-ObjectEvent -InputObject $fsw -EventName Created -Action {
  Write-Host "$($Event.TimeGenerated) : Incoming email file - $($Event.SourceEventArgs.Name)"
  Copy-Item $Event.SourceEventArgs.FullPath -Destination $destination -Force -Verbose
}


To remove the listener:

Unregister-Event -SourceIdentifier $onCreated.Name
$onCreated.Dispose()

Unknowns:

  • Does not account for large incoming files that are temporarily locked while being copied
  • Not sure if this causes problems if job-email-delivery tries to access (or even remove) file while Copy-Item is being called.
  • Not sure if this is guaranteed to happen before job-email-delivery
  • Not sure of the performance impact



Thursday, April 27, 2017

SharePoint 2013 - Sign in as a different user

I keep forgetting this, so noting it down here:

_layouts/closeConnection.aspx?loginasanotheruser=true


Tuesday, April 4, 2017

SocialDataManager.SocialDataManager Proxy has no ServiceContext available

Just ran into this issue when trying to instantiate Microsoft.Office.Server.SocialData.SocialTagManager in powershell:

$siteUrl = 'some-site-url'
$site = Get-SPSite $siteUrl
$serviceContext = Get-SPServiceContext($site)
$msstm = New-Object Microsoft.Office.Server.SocialData.SocialTagManager($serviceContext)

New-Object : Exception calling ".ctor" with "1" argument(s): "UserProfileApplicationNotAvailableException_Logging :: SocialDataManager.SocialDataManager Proxy has no ServiceContext available."
At line:1 char:10
+ $msstm = New-Object Microsoft.Office.Server.SocialData.SocialTagManager($service ...
+          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [New-Object], MethodInvocationException
    + FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand


Not much out there, but the UserProfileApplicationNotAvailableException provided a clue. I did not track down the specific cause, but it looks like I was not running powershell with an account that admin permissions in the UPA or MMS. I did not have time to dig further, but instead simply opened up my powershell as the farm account and did not run into the same problem.


Wednesday, March 22, 2017

Finding Alias for SharePoint Email Enabled Lists

As usual, there are several ways to do this that can be readily found via a search

Powershell: Loop through each Web Application, Site Collection (SPSite), Subweb (SPWeb), List. Then look in the EmailAlias property for what you are searching. In large environments, I suspect that this would be very slow and resource intensive. Here is a Foreach-Object pipeline that would do the trick:

Get-SPWebApplication | ForEach-Object {$_.Sites} | ForEach-Object {$_.AllWebs} | ForEach-Object {$_.Lists} | Where-Object {$_.CanReceiveEmail -and $_.EmailAlias} | Format-Table EmailAlias, Title, ParentWebUrl -AutoSize


SQL: One way is to essentially do the above but via the content databases, but this one also seems resource intensive:

USE [Some_Content_DB]
SELECT tp_Title, tp_EmailAlias, FullUrl
  FROM [dbo].[AllLists] lists
  LEFT JOIN [dbo].[AllWebs] webs ON lists.tp_WebId = webs.Id
  WHERE tp_EmailAlias IS NOT NULL

SQL: I decided to see what the Microsoft SharePoint Foundation Incoming E-Mail timer job does (job-email-delivery) since the timer job should be quite fast. Looking at the code, I can see that it calls the proc_getEmailEnabledListByAlias stored procedure. Diving into that, I see that this may be a better query:

SELECT * FROM [SharePoint_Config].[dbo].[EmailEnabledLists] 


However, I did also run across a post mentioning that it is possible the Config database and the Content database can be out of sync. So, it may still be necessary to choose the correct method depending on the problem one is trying to tackle.

Wednesday, December 28, 2016

Faking Microsoft.SharePoint.ServiceContext.Current with Powershell

While debugging some server side code, I tried to mimic it in Powershell. The challenge was that the backend code relied on Microsoft.SharePoint.SPServiceContext.Current. Fortunately, there are many posts on how to do this including:



Frustratingly, none of this was working when I tried. I was running as the Farm Account.

Then, I came across this: http://blog.claudiobrotto.com/2011/sharepoint-management-shell-vs-standard-powershell-console/

I normally use just the Windows Powershell while on my servers and call Add-PSSnapin Microsoft.SharePoint.Powershell. However, I forgot that the SPServiceContext::Current is being lost when a new thread is being used.

I added the following and all is good again:
$Host.RunSpace.ThreadOptions = 'ReuseThread' 


Wednesday, November 23, 2016

SPList.GetItems(SPQuery) appears to miss items if paging info not precise

We have some code that uses SPList.GetItems(SPQuery) with paging info.

The list items we were running against had the following values:

ID   Created
--   -------
51   8/30/2016 8:02:40 AM
49   8/12/2016 2:42:26 PM
48   6/27/2016 3:39:05 AM
46   6/21/2016 4:04:28 PM
45   6/21/2016 3:10:18 PM
44   6/21/2016 2:32:13 PM
43   6/21/2016 3:56:01 AM
42   6/20/2016 6:32:34 AM
41   6/20/2016 4:55:47 AM
39   6/14/2016 1:30:05 PM <-- The last item on page 1
38   6/14/2016 11:34:51 AM <-- Should be the first item on page 2
37   6/14/2016 10:21:22 AM <-- With our bad code, this one is first on page 2
36   6/14/2016 8:48:43 AM
35   6/9/2016 12:56:16 AM
32   5/25/2016 11:38:44 PM
29   5/9/2016 9:43:31 AM
28   5/9/2016 9:35:38 AM
26   4/28/2016 8:19:59 AM

Due to a bug in our code (timezone conversion!), we were providing an SPListItemCollectionPosition containing an incorrect value for the Created property. As a result, SPList.GetItems gets the first row that matches both criteria. This leads to the appearance that the paginated data is missing rows.

For example:

$webUrl = 'some-web-url';
$rowLimit = 10;
$goodPage = 'Paged=TRUE&p_ID=39&p_Created=20160614%2013%3A30%3A05';
$badPage  = 'Paged=TRUE&p_ID=39&p_Created=20160614%2011%3A30%3A05';

$web = Get-SPWeb $webUrl;
$list = $web.Lists['some-list'];
$spquery = New-Object Microsoft.SharePoint.SPQuery;
$spquery.Query = "<OrderBy><FieldRef Name='Created' Ascending='False' /></OrderBy>";
$spquery.RowLimit = $rowLimit;
$spquery.ListItemCollectionPosition = New-Object Microsoft.SharePoint.SPListItemCollectionPosition($goodPage);
$list.GetItems($spquery) | Format-Table ID, Name, @{l='Created'; e={$_['Created']}} -AutoSize;
$spquery.ListItemCollectionPosition = New-Object Microsoft.SharePoint.SPListItemCollectionPosition($badPage);
$list.GetItems($spquery) | Format-Table ID, Name, @{l='Created'; e={$_['Created']}} -AutoSize;
$list.GetItems("Id", "Created", "Name") | Format-Table ID, Name, @{l='Created'; e={$_['Created']}} -AutoSize;


Using the above powershell, the results from $goodPage works as expected. However, with $badPage, the time is off by 2 hours (we provided 11:30:05 instead of 13:30:05). Since we are sorting descending by Created, the wrong page info value causes the entry at 11:34:51 to be skipped as well. Oops!



The field with Id {field-GUID} defined in feature {feature-GUID} was found in the current site collection or in a subsite.

One of my site collection features is failing to activate and throws this exception:

SPException thrown: Message: The field with Id {field-GUID} defined in feature {feature-GUID} was found in the current site collection or in a subsite.. Stack:   
 at Microsoft.SharePoint.Utilities.SPUtility.ThrowSPExceptionWithTraceTag(UInt32 tagId, ULSCat traceCategory, String resourceId, Object[] resourceArgs)    
 at Microsoft.SharePoint.Administration.SPElementDefinitionCollection.ProvisionFieldsAndContentTypes(SPFeaturePropertyCollection props, SPSite site, SPWeb web, SPFeatureActivateFlags activateFlags, Boolean fForce)    
 at Microsoft.SharePoint.Administration.SPElementDefinitionCollection.ProvisionElements(SPFeaturePropertyCollection props, SPWebApplication webapp, SPSite site, SPWeb web, SPFeatureActivateFlags activateFlags, Boolean fForce)    
 at Microsoft.SharePoint.SPFeature.Activate(SPSite siteParent, SPWeb webParent, SPFeaturePropertyCollection props, SPFeatureActivateFlags activateFlags, Boolean fForce)    
 at Microsoft.SharePoint.SPFeatureCollection.AddInternal(SPFeatureDefinition featdef, Version version, SPFeaturePropertyCollection properties, SPFeatureActivateFlags activateFlags, Boolean force, Boolean fMarkOnly)    
 at Microsoft.SharePoint.SPFeatureCollection.AddInternalWithName(Guid featureId, Int32 compatibilityLevel, String featureName, Version version, SPFeaturePropertyCollection properties, SPFeatureActivateFlags activateFlags, Boolean force, Boolean fMarkOnly, SPFeatureDefinitionScope featdefScope)    
 at Microsoft.SharePoint.WebControls.FeatureActivator.ActivateFeature(Guid featid, Int32 compatibilityLevel, SPFeatureDefinitionScope featdefScope)    
 at Microsoft.SharePoint.WebControls.FeatureActivatorItem.ToggleFeatureActivation()    
 at System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument)    
 at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)    
 at System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)    
 at System.Web.UI.Page.ProcessRequest()    
 at System.Web.UI.Page.ProcessRequest(HttpContext context)    
 at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()    
 at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)    
 at System.Web.HttpApplication.PipelineStepManager.ResumeSteps(Exception error)    
 at System.Web.HttpApplication.BeginProcessRequestNotification(HttpContext context, AsyncCallback cb)    
 at System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context)    
 at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)    
 at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)    
 at System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr pHandler, RequestNotificationStatus& notificationStatus)    
 at System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr pHandler, RequestNotificationStatus& notificationStatus)    
 at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)    
 at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)  


I found a lot of references out there saying to redeploy the solution or use Overwrite="TRUE" in the field definition. However, not satisfied with either, I dug deeper.

I put this powershell together to figure out where the fields are coming from:

$siteUrl = 'site-collection-url'
$fieldId = 'field-GUID'
$fieldInternalName = 'field-internal-name'

$site = Get-SPSite $siteUrl
$webFields = @()
foreach ($web in $site.AllWebs) {
  foreach ($field in $web.Fields) {
    $webField = New-Object PSObject -Property ([ordered]@{
      WebUrl = $web.Url
      FieldId = $field.Id
      FieldInternalName = $field.InternalName
      FieldTitle = $field.Title
    })
    $webFields += $webField
  }
}
$webFields | Where-Object {$_.FieldId -eq $fieldId -or $_.FieldInternalName -eq $fieldInternalName} | Format-Table -AutoSize

From the results, I found 2 subwebs that contained this same definition. It looks like these subwebs were migrated into that site collection. Is is possible that this was done before the site collection feature was activated. The migration process must have created the fields at the subweb level.

Going to each of the subwebs listed by the powershell, I was able to go to Site Settings->Site Columns, locate my field, and delete it, Once these were deleted, I was able to activate my site collection feature.






Throttled:Query exceeds lookup column threshold

One of my apps gets its data via lists.asmx. In a particular environment, no data was being returned and I found these entries in ULS:

Throttled:Query exceeds lookup column threshold. List item query elapsed time: 0 milliseconds, Additional data (if available): Query HRESULT: 80070093 List internal name, flags, and URL: {list-guid}, flags=0x0008000000c4108c, URL="web-url/_vti_bin/lists.asmx" Current User: {some-id} Query XML: "<Query><OrderBy><FieldRef Name="ContentType"/></OrderBy></Query>" SQL Query: "N/A"

The query cannot be completed because the number of lookup columns it contains exceeds the lookup column threshold enforced by the administrator.

Query exceeds lookup column threshold. List: {list-guid}, View: , ViewXml: <View Scope="RecursiveAll" IncludeRootFolder="True"><Query><OrderBy><FieldRef Name="ContentType" /></OrderBy></Query><ViewFields>... and a whole ton of <FieldRef> entries.


SOAP exception: Microsoft.SharePoint.SPQueryThrottledException: The query cannot be completed because the number of lookup columns it contains exceeds the lookup column threshold enforced by the administrator. ---> System.Runtime.InteropServices.COMException (0x80070093): The query cannot be completed because the number of lookup columns it contains exceeds the lookup column threshold enforced by the administrator.    


I found a few references to this, but it is not the more common 5000 item List View Threshold throttling. Instead this is the List View Lookup Threshold setting of 8 (12 in SharePoint 2013).

It turns out that my app is using the default view and not specifying which fields to return in the query. In fact, there is a Level=Medium ULS log entry that has my exact query. Putting this into powershell as follows, I was able to confirm the behaviour:

$webUrl = 'some-web-url'
$listName = '{list-guid}' # note: keep the curly braces

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

$uri = [uri]"$($communityRoot)/_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
$result.RawContent


To confirm the view and the number of lookup columns, I used this powershell:

$webUrl = 'some-web-url'

$web = Get-SPWeb $webUrl
$list = $web.Lists['Shared Documents']
$fields = $list.Fields
$defaultViewXml = [xml]$list.DefaultView.GetViewXml()
Write-Output "Default View: $($list.DefaultView.Title)"
$defaultViewXml.View.ViewFields.FieldRef | Format-Table @{l="Type"; e={$fields.GetField($_.Name).TypeDisplayName}}, Name -AutoSize -Wrap


Reference: This is a very well written article on GetListItems - https://msdn.microsoft.com/en-us/library/websvclists.lists.getlistitems(v=office.14).aspx





Wednesday, October 7, 2015

SPBasePermissions enumeration - values in Int64, Hexadecimal, and Name


$t = [type]'Microsoft.SharePoint.SPBasePermissions'
[enum]::GetValues($t) | ForEach-Object {Write-Host "$($_): $([int64]$_) (0x$([Convert]::ToString([int64]$_,16)))"}

Haven't figured out a way to use Format-Table for this, but good enough for now.

Thursday, July 30, 2015

Solutions, features, and CompatibilityLevel

I recently came across an issue where certain feature definitions were not available in 2010 mode sites in one farm, but they were in another. It turned out that the parameters supplied to Install-SPSolution are the reason. Essentially, the difference was specifying -CompatibilityLevel {14,15} vs specifying nothing. I found this article to be very helpful: Planning Deployment of Farm Solutions for SharePoint 2013

Tuesday, May 5, 2015

Hacking SPRoleDefinition SPRoleType in the database

If you are a Site Collection Administrator, SharePoint allows you to go to a Site Collection, Site Actions->Site Permissions->Permission Levels, then edit a permission level and delete it.

Some predefined Permission Levels (SPRoleDefinition) have a Type (SPRoleType) defined. This is not visible via the UI. However you can get this via Powershell as follows:

$web = Get-SPWeb your-web-url
$web.RoleDefinitions | Format-Table Id, Name, Type, Hidden -AutoSize

This gives output like the following:

        Id Name                       Type Hidden
        -- ----                       ---- ------
1073741829 Full Control      Administrator  False
1073741828 Design              WebDesigner  False
1073741827 Contribute          Contributor  False
1073741826 Read                     Reader  False
1073741825 Limited Access            Guest   True

Now, if you delete one of these such as the Contribute and then decide to recreate it, the type is now "None". There is no way to make the Type "Contributor".

This is all fine, but if you have some code that calls Microsoft.SharePoint.SPRoleDefinitionCollection.GetByType then your code is now broken.

To "resolve" (using the term very loosely as I do not know if there are any implications), I was able to restore this by hacking the database directly.

Essentially, I looked into the Roles table in the WSS_Content database, filtered on the WebId and RoleId and set the Type column directly in the database. Is it a good idea? Who knows? It seemed to work for me, but I do not know what I may have broken as a result of this.





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, 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




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

Wednesday, June 5, 2013

0x80070002 when adding web part using Powershell

I was adding a webpart using this powershell:
$webpart = New-Object Microsoft.SharePoint.WebPartPages.SilverlightWebPart
$wpm = $web.GetLimitedWebPartManager($page.Uri.OriginalString, "Shared")
$wpm.AddWebPart($webpart, 'Header', 0)

... and got this error:

Exception calling "AddWebPart" with "3" argument(s): "<nativehr>0x80070002</nativehr><nativestack></nativestack>"
At line:1 char:16
+ $wpm.AddWebPart <<<< ($webpart, 'Header', 0)
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException


It turns out that my $page was the wrong one which was not checked out nor editable at the time.

Listing a page's web part zones

I have been trying to figure out a way to list all of a page's web part zones. There is not much documentation out there on this. Here's what I have been able to figure out. It is for a publishing web, but the procedure should be pretty much the same.

$myweburl
$mylayouttitle
$web = Get-SPWeb $myweburl
$pWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web)
$layout = $pWeb.GetAvailablePageLayouts() | Where-Object {$_.Title -eq $mylayouttitle}
$layout.ListItem.Properties['vti_cachedzones']


And to list the webparts on a page:
$pageurl
$wpm = $web.GetLimitedWebPartManager($pageurl, 'Shared'
$wpm.WebParts | Format-Table -AutoSize WebBrowsableObject, ZoneId, ZoneIndex


There's also a post Determine which webpartzones are on a webpartpage that uses reflection to get at a private member however I have not gotten it to work.



Wednesday, April 17, 2013

Could not load the current My Site settings

I have a new SP2013 installation and going into the Setup My Sites, I get the error:
Could not load the current My Site settings

Doing a quick search, I came across this:


It turned out that my Search Service Application was broken as described here:

Unable to retrieve topology component health states. This may be because the admin component is not up and running

I just installed SP2013 RTM on Win2k8R2 SP1 and SQL2012 Enterprise on a separate Win2k8R2 SP1 server. I used Powershell to provision my Search as follows:


$ssi = Get-SPServiceInstance | Where-Object {$_.TypeName -eq 'SharePoint Server Search'}
Start-SPServiceInstance $ssi
WaitForServiceInstance $ssi.TypeName
$searchAdminAppPool = Get-SPServiceApplicationPool -Identity $AppPoolSearchAdmin
$searchQueryAppPool = Get-SPServiceApplicationPool -Identity $AppPoolSearchQuery
New-SPEnterpriseSearchServiceApplication -Name 'Search Service Application' -ApplicationPool $searchQueryAppPool -AdminApplicationPool $searchAdminAppPool
New-SPEnterpriseSearchServiceApplicationProxy -Name 'Search Service Application' -SearchApplication (Get-SPEnterpriseSearchServiceApplication 'Search Service Application')
Set-SPEnterpriseSearchService -ServiceAccount $searchServiceAccount -ServicePassword (ConvertTo-SecureString -AsPlainText -Force $password)

When I go into manage my Search Service Application, I get the following error:
Unable to retrieve topology component health states. This may be because the admin component is not up and running

Figuring that I may have been missing some steps in my Powershell script, I tried unprovisioning my Search Service Application and reprovisioning using Central Administration. Still the same problem. Time to do some searches. Here is what I found.

http://office.microsoft.com/en-ca/help/sharepoint-server-2013-known-issues-HA102919021.aspx
http://social.technet.microsoft.com/Forums/en-US/sharepointitpropreview/thread/50acc2b8-dd56-4d5a-a660-dffa325ef807/?prof=required
http://leonzandman.com/2012/11/08/return-of-the-search-application-topology-component-health-state-error/
http://www.mavention.nl/blog/sp2013-installation-lessons-learned-part-1

After doing a lot of reading and considering the various CUs, I went back to my servers to try some of the suggested solutions. Lo and behold, search is working now. The only things I can infer from this is:

  1. Central Administration is doing something to provision Search that is missing from my Powershell script
  2. Some process took its time to execute
  3. Possibly some random factors like memory, etc.


As much as I would like to know the real answer, it is working now, time to move onto next problem.