<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Marat Bakirov</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/mbakirov/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/mbakirov/feed.xml</link>
    <description>Блог Марат Бакирова.(Marat Bakirov blog)</description>
    <lastBuildDate>Wed, 17 Apr 2019 03:10:43 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Changing SharePoint 2013 farm passwords</title>
      <link>https://docs.microsoft.com/archive/blogs/mbakirov/changing-sharepoint-farm-passwords</link>
      <pubDate>Fri, 29 Jul 2016 09:09:31 GMT</pubDate>
      <dc:creator><![CDATA[Marat F Bakirov]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mbakirov/?p=1335</guid>
      <description><![CDATA[Another recent case from the customer.

What they had is a farm which was deployed with...]]></description>
      <content:encoded><![CDATA[Another recent case from the customer.

What they had is a farm which was deployed with autospinstaller. <a href="https://autospinstaller.codeplex.com/">https://autospinstaller.codeplex.com/</a> So they have quite a number of accounts for various SharePoint services , windows services and application pools.

&nbsp;

So how should we change the accounts?

The easiest way (that was implemented at the customer) is to have account to be registered as managed accounts.

This way you or SharePoint can automatically change passwords for the accounts, and update all relevant records.

The managed account can change the passwords in AD or just update the SharePoint records. In our case there were some errors we have not resolved, so we have let the AD admins change the password and then we have changed the things in SharePoint.

&nbsp;

So what happens after you change the AD account password?

If you do nothing, there will be problems. Most likely though you will only notice the problems after you restart the server.

&nbsp;

The reason is that there are

Windows Service registrations on farm computers containing copies of the passwords

IIS Pools registrations containing copies of the passwords

In some cases (like search or workflow) other entities contain the reference to the password.

<b>Managed accounts</b>

The benefit of managed account is that SharePoint can automate some of these actions across the farm. Namely - changing the windows service registrations and iis pools registrations.

If you choose to change the passwords (and not let them be changed automatically), there are basically 2 ways to do it.

Option one - Central Admin

<img class="alignnone size-full wp-image-204" src="https://mbakirov.files.wordpress.com/2016/07/two.png" alt="two" width="1250" height="768" />

&nbsp;

Press the edit button

Enter new password and press ok below

<img class="alignnone size-full wp-image-204" src="https://mbakirov.files.wordpress.com/2016/07/two.png" alt="two" width="1250" height="768" />

&nbsp;

Note that option one - Set account password to a new value will try to change the password in AD first. Option two will just update the relevant services and IIS pools.

In some cases you would prefer to use PowerShell. If the account you are changing is also used to run the Central Administration application pool, then your command will kinda fail in the middle cause it will run under the pool that is going to be reset!

In this case you can use the <b>Set-SPManagedAccount </b>command

<a href="https://technet.microsoft.com/en-us/library/ff607617(v=office.16).aspx">https://technet.microsoft.com/en-us/library/ff607617(v=office.16).aspx</a>

If you want this command to change the AD password use this format
<code>
Set-SPManagedAccount -Identity $username -NewPassword $newpassword -ConfirmPassword $newpassword
</code>
If you want to use an existing password - use this one.

<code>
Set-SPManagedAccount -Identity $username -ExistingPassword $newpassword  -UseExistingPassword:$true
</code>

I have made a script that reads accounts and new passwords from the csv files and updates them in a bulk.

<code>
&lt;#
.SYNOPSIS
Changes managed account passwords at the farm.
.DESCRIPTION
Changes accounts using the provided CSV file.
.EXAMPLE
.\changepasswords.ps1    -inputFile "yourfile.csv" -newPasswords:$false
.NOTES
Author: Marat Bakirov
Date: 05 July 2016
#&gt;
[cmdletbinding()]
param(
[string] $InputFile = "accountsandpasswords.csv",
[switch] $newPasswords = $true
)</code>

####################################################
# Configurables
####################################################

Add-PSSnapin Microsoft.Sharepoint.Powershell

####################################################
# Main
####################################################

function Main
{

$passwords = Import-Csv $InputFile
$passwords | foreach {
$username = $_.Username
$newpwd1 = $_.NewPassword
$newpassword =  ConvertTo-SecureString -String $newpwd1 -AsPlainText -Force
$newpwd1
if ($newpasswords)
{
Write-Host "changing password for  {$username} to a new one"
Set-SPManagedAccount -Identity $username -NewPassword $newpassword -ConfirmPassword $newpassword -Confirm:$false
}
else
{
Write-Host "changing password for  {$username} to an existing one"
Set-SPManagedAccount -Identity $username -ExistingPassword $newpassword -Confirm:$false -UseExistingPassword:$true
}
}
}
Main

<b>How to change other passwords</b>

If the account participates in the user profile sync, search or workflow farm, you  might need to run additional scripts.

<b>User profile sync</b>

These accounts are managed and are changed within SharePoint but are also used for the User Profile Sync. So an additional configuration might be required.

Good reference can be found here

<a href="https://blog.zubairalexander.com/managing-passwords-for-service-accounts-in-sharepoint-sql-server/">https://blog.zubairalexander.com/managing-passwords-for-service-accounts-in-sharepoint-sql-server/</a> - section 5 5. User Profile Synchronization Connection Account

or <a href="https://blogs.msdn.microsoft.com/charliechirapuntu/2013/01/16/sharepoint-2010-service-accounts-passwords-change-guide/">https://blogs.msdn.microsoft.com/charliechirapuntu/2013/01/16/sharepoint-2010-service-accounts-passwords-change-guide/</a>

&nbsp;

<b>Search crawler account</b>

This has an additional impact – the search content account has to be updated in the active directory first and then updated in the search center.

<a href="https://technet.microsoft.com/en-au/library/dn178512.aspx">https://technet.microsoft.com/en-au/library/dn178512.aspx</a>

&nbsp;

<b>Workflow and service bus farm accounts</b>

&nbsp;

&nbsp;

On each server in the farm that has workflow installed run the <b>Service Bus PowerShell</b> in the elevated mode. (Note: if the service buspower shell is missing, then skip the procedure for this server).

Run the <b>changewfpassword.ps1</b> script.

The script will prompt for the new Password for the <b>svcInsiteWfProd/ svcInsiteWfTest </b> account.

&nbsp;

<code>
Write-Host "Please enter a new password"
$passwordText = Read-Host
$AccountPassword = ConvertTo-SecureString -String $passwordText -AsPlainText -Force</code>

Stop-WFHost -Verbose
Update-WFHost -RunAsPassword $AccountPassword –Verbose
Start-WFHost -Verbose

Stop-SBHost -Verbose
Update-SBHost -RunAsPassword $AccountPassword –Verbose
Start-SBHost -Verbose

&nbsp;

<b>Source code</b>

The scripts could be found here

&nbsp;

<a href="https://1drv.ms/f/s!AguWtH15ywzQhI5kUYLXI1Jcmv4Y6Q">https://1drv.ms/f/s!AguWtH15ywzQhI5kUYLXI1Jcmv4Y6Q</a>

&nbsp;]]></content:encoded>
    </item>
    <item>
      <title>Случай - перестала работать команда export-spweb. (А также некоторые размышления о том, почему важна настройка package version и настройка DeploymentServerType)</title>
      <link>https://docs.microsoft.com/archive/blogs/mbakirov/%D1%81%D0%BB%D1%83%D1%87%D0%B0%D0%B9-%D0%BF%D0%B5%D1%80%D0%B5%D1%81%D1%82%D0%B0%D0%BB%D0%B0-%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D1%82%D1%8C-%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D0%B0-export-spweb</link>
      <pubDate>Tue, 19 Jul 2016 09:13:40 GMT</pubDate>
      <dc:creator><![CDATA[Marat F Bakirov]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mbakirov/?p=1325</guid>
      <description><![CDATA[Еще один случай,  который произошел у последнего клиента.

У клиента есть стороннее приложение, в...]]></description>
      <content:encoded><![CDATA[Еще один случай,  который произошел у последнего клиента.

У клиента есть стороннее приложение, в котором создана веб часть и шаблон списка (list template). Судя по всему созданы для Sharepoint 2010 (14) и просто перекомпированы под SharePoint 2013. А может даже и не перекомпилированы. Исходный текст есть но я не имею права ничего менять в решении.

У клиента ферма на 4 сервера, 2 - Application Role (APP1 и APP2), 2 - Web Front End (WEB1 и WEB2)

APP1 содержит центр администрирования.

Еще одно стороннее решение выполняет гранулярный бекап, в котором внутри используется команда Export-SPWeb.

Export-SPWeb не работает.

Ошибка примерно такая

<a href="https://social.technet.microsoft.com/Forums/en-US/6b50d0f2-b323-4156-a11a-d3f6ea1492c7/sharepoint-2010-site-collection-export?forum=sharepointgeneralprevious">https://social.technet.microsoft.com/Forums/en-US/6b50d0f2-b323-4156-a11a-d3f6ea1492c7/sharepoint-2010-site-collection-export?forum=sharepointgeneralprevious</a>

Error: Feature 'blalba-guid' for list template '100' is not installed in this farm.  The operation could not be completed.

Feature blalba-guid - находится в стороннем решении и развернута!

В ходе исследования выяснилось несколько моментов.

&nbsp;

Первый - стороне решение ставится в 14 Hive.

Что - Что? Hive?

Файлы из решения были развернуты сюда "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\<b>14</b>\TEMPLATE\FEATURES\"  но НЕ БЫЛИ развернуты сюда  "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\<b>15</b>\TEMPLATE\FEATURES\"

Кажется, что решение просто было скомпилировано с неверной опцией Compatibility (14, а должно быть 15).

<img class="alignnone size-full wp-image-181" src="https://mbakirov.files.wordpress.com/2016/07/2016-07-19_14-42-55.png" alt="2016-07-19_14-42-55" width="1280" height="733" />

Думается, что ходить и копировать файлы вручную все-таки не очень хорошая идея, так что нужно как то сказать Sharepointу, чтобы решение поставилось в <b>15 hive. </b>Проще всего было бы перекомпилировать, но раз такое возможности нет, то можно установить решение вот такое командой.

<img class="alignnone size-full wp-image-182" src="https://mbakirov.files.wordpress.com/2016/07/2016-07-19_15-07-18.png" alt="2016-07-19_15-07-18" width="1280" height="303" />

Install-SPSolution -Identity &lt;yoursolution.wsp&gt; -AllWebApplications -GacDeployment <b>-CompatibilityLevel {14,15}</b>

&nbsp;

Итак, файлы появляются в <b>15 Hive</b>.

Остается одна проблема - файлы появились только на  WEB1 и WEB2. Команда Export-SPWeb на них начала работать, но по-прежнему не работает на APP1/2.

Клиент запускать экспорт на фронт ендах не хочет. Там сотни гигабайт,  дополнительную нагрузку на фронт енды никто не хочет.

Чтобы понять, почему же файлы не появились на веб фронтендах, давайте взглянем еще на одну настройку.

<img class="alignnone size-full wp-image-183" src="https://mbakirov.files.wordpress.com/2016/07/2016-07-19_15-11-07.png" alt="2016-07-19_15-11-07" width="1280" height="733" />

Настройка говорит нам, устанавливать ли решение на сервера с ролью Web Front End или ApplicationServer, но как Sharepoint определяет кто есть who?

&nbsp;

Можно было бы подумать, что это server role.

<a href="https://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spserverrole.aspx">https://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spserverrole.aspx</a>

<img class="alignnone size-full wp-image-184" src="https://mbakirov.files.wordpress.com/2016/07/2016-07-19_15-18-44.png" alt="2016-07-19_15-18-44" width="994" height="690" />

&nbsp;

Но кажется,что для For SP2013 это не важно. В моем случае самое логичное объяснение в том, что Sharepoint определяет фронт енд как сервер, на котором запущена служба "Microsoft Sharepoint Foundation Web Application" service.

<img class="alignnone size-full wp-image-185" src="https://mbakirov.files.wordpress.com/2016/07/2016-07-19_15-22-50.png" alt="2016-07-19_15-22-50" width="1280" height="733" />

&nbsp;

То есть если решение развёртывается как "WebFrontEnd"  - его файлы развертываются на сервера, на  которых служба "Microsoft Sharepoint Foundation Web Application" <b>запущена</b>.

Итого все просто - запустить службу Microsoft Sharepoint Foundation Web Application ?

Еще один тонкий момент - запуск или остановка этой службы вызывает перезапуск IIS. При этом перезапускается Центр Администрирования. Если запустить перезапуск из центра Администрирования то это может вызывать ошибку.

В этом случае запустите команду

Get-SPServiceInstance | where {$_.TypeName.Contains('Web Application')} | ft -Property Id,TypeName,Server,Status -Autosize

Найдите нужные вам экземпляры службы и запустите их командой

Start-SPServiceInstance -Identity &lt;guid&gt; command

<img class="alignnone size-full wp-image-186" src="https://mbakirov.files.wordpress.com/2016/07/2016-07-19_15-48-44.png" alt="2016-07-19_15-48-44" width="993" height="665" />

Итак, кейс разрешен. Клиент доволен. То есть мы исправили версию при развертывании и добавили веб роль на серверах приложений.

Стоп! Что?

Что??

Добавили веб роль на серверах приложений.???

Верно, но при этом мы не нарушили логическую топологию. Служба "Microsoft Sharepoint Foundation Web Application" действительно запущена на серверах APP1 и APP2 но мы из не используем как Web Front Ends. Наш балансировщик просто не в курсе, что на них можно перенаправлять запросы.

&nbsp;

Просто мы решили проблему заказчика.]]></content:encoded>
    </item>
    <item>
      <title>Case - broken export-spweb. (Understanding the solution package version and DeploymentServerType)</title>
      <link>https://docs.microsoft.com/archive/blogs/mbakirov/case-broken-export-spweb-understanding-the-solution-package-version-and-deploymentservertype</link>
      <pubDate>Tue, 19 Jul 2016 08:12:51 GMT</pubDate>
      <dc:creator><![CDATA[Marat F Bakirov]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mbakirov/?p=1305</guid>
      <description><![CDATA[Another case from the recent customer support work. The customer had a 3rd party solution with a...]]></description>
      <content:encoded><![CDATA[Another case from the recent customer support work. The customer had a 3rd party solution with a list template, list and a web part which seemed to be created for SharePoint 14 (2010) originally and simply recompiled. (And I cannot change or recompile the sources).

&nbsp;

The customer has SharePoint 2013 farm, made of 2 App servers (let us call them APP1 and APP2) and 2 web front ends (WEB1 and WEB2).

APP1 also runs central admin.

&nbsp;

Another 3rd party backup solutions the customer is using is doing a granular SharePoint backup (up to document) and internally uses the Export-SPWEB command.

&nbsp;

The Export command breaks.

Errors are similar to the ones described here:

<a href="https://social.technet.microsoft.com/Forums/en-US/6b50d0f2-b323-4156-a11a-d3f6ea1492c7/sharepoint-2010-site-collection-export?forum=sharepointgeneralprevious">https://social.technet.microsoft.com/Forums/en-US/6b50d0f2-b323-4156-a11a-d3f6ea1492c7/sharepoint-2010-site-collection-export?forum=sharepointgeneralprevious</a>

&nbsp;

Error: Feature 'blalba-guid' for list template '100' is not installed in this farm.  The operation could not be completed.

Feature blalba-guid is from the 3rd party solution and it is installed!

&nbsp;

During investigation I have found out the few reasons.

&nbsp;

First - the 3rd party solution was installing in the 14 Hive.

What?

&nbsp;

The solution files and features were added to the "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\<b>14</b>\TEMPLATE\FEATURES\"  but NOT added to the "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\<b>15</b>\TEMPLATE\FEATURES\"

&nbsp;

Apparently the solution was compiled with the 14 compatibility option.

<img class="alignnone size-full wp-image-181" src="https://mbakirov.files.wordpress.com/2016/07/2016-07-19_14-42-55.png" alt="2016-07-19_14-42-55" width="1280" height="733" />

&nbsp;

&nbsp;

Probably it is not a good idea to go through all servers and copy the files, so to achieve the result we need to tell SharePoint to deploy the solution to both 14 and 15 hives.

Would be simpler if the solution would recompiled with 15 compatibility option, but I could not do it, so I had to run the following command to deploy the solution

&nbsp;

<img class="alignnone size-full wp-image-182" src="https://mbakirov.files.wordpress.com/2016/07/2016-07-19_15-07-18.png" alt="2016-07-19_15-07-18" width="1280" height="303" />

<code>
Install-SPSolution -Identity &lt;yoursolution.wsp&gt; -AllWebApplications -GacDeployment <b>-CompatibilityLevel {14,15}</b>
</code>

&nbsp;

This made the files to appear at the 15 hive.

However, the files were only deployed to the WEB1 and WEB2, and the export command were still not working at the APP1 and APP2, despite the fact that it started to work fine at the WEB1 and WEB2.

&nbsp;

The customer was really reluctant to run the Export jobs at the Web frontend and thus increasing the load.

&nbsp;

To understand why the files did not appear at the APP1 and APP2, let us look at another setting:

<img class="alignnone size-full wp-image-183" src="https://mbakirov.files.wordpress.com/2016/07/2016-07-19_15-11-07.png" alt="2016-07-19_15-11-07" width="1280" height="733" />

&nbsp;

So this setting is telling us if the solution will be deployed to web front end or an application server.

But how does SharePoint define which server is the application server?

&nbsp;

Well you might assume that it is server role.

<a href="https://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spserverrole.aspx">https://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spserverrole.aspx</a>

<img class="alignnone size-full wp-image-184" src="https://mbakirov.files.wordpress.com/2016/07/2016-07-19_15-18-44.png" alt="2016-07-19_15-18-44" width="994" height="690" />

&nbsp;

For SP2013 it seems that this does not matter.

It seems that the  Sharepoint defines the web front end as a server that runs a "Microsoft Sharepoint Foundation Web Application" service.

&nbsp;

<img class="alignnone size-full wp-image-185" src="https://mbakirov.files.wordpress.com/2016/07/2016-07-19_15-22-50.png" alt="2016-07-19_15-22-50" width="1280" height="733" />
<ul>
	<li>If the solution package deployment type is "WebFrontEnd"  - it's assets are deployed  to the servers that have the "Microsoft Sharepoint Foundation Web Application" <b>on</b>.</li>
</ul>
So the solution was simple - start the Microsoft Sharepoint Foundation Web Application service on the server? Simple?

&nbsp;

One more tricky thing. Starting the service on the server that has a Central Admin - causes IIS to restart, and thus central admin to restart. So we may encounter the problem. In this case run the command

&nbsp;

&nbsp;

<code>
Get-SPServiceInstance | where {$_.TypeName.Contains('Web Application')} | ft -Property Id,TypeName,Server,Status -Autosize
</code>

&nbsp;

Find the service instance on the server you want it to run on, and then run the

<code>
Start-SPServiceInstance -Identity &lt;guid&gt; command
</code>

&nbsp;

<img class="alignnone size-full wp-image-186" src="https://mbakirov.files.wordpress.com/2016/07/2016-07-19_15-48-44.png" alt="2016-07-19_15-48-44" width="993" height="665" />

&nbsp;

That is all! the case is solved. So we have fixed the version by installing the solution with the correct compatibility levels and also added a Web Role to the application servers.

&nbsp;

Woah woah woah wait a second.

What?

Added a Web Role to the application servers???

Yes, however we did not break the farm topology. These servers APP1 and APP2 HAD the "Microsoft Sharepoint Foundation Web Application" service but were NOT used as Web  Front ends. Simply the load balancer had no idea they do have the IIS and so the requests were not redirected here.

We just solved the problem.

&nbsp;

&nbsp;

&nbsp;

&nbsp;]]></content:encoded>
    </item>
    <item>
      <title>Как более правильно отобразить файловые результаты поиска</title>
      <link>https://docs.microsoft.com/archive/blogs/mbakirov/%D0%BA%D0%B0%D0%BA-%D0%B1%D0%BE%D0%BB%D0%B5%D0%B5-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D1%8C%D0%BD%D0%BE-%D0%BE%D1%82%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%B8%D1%82%D1%8C-%D1%84%D0%B0%D0%B9%D0%BB%D0%BE</link>
      <pubDate>Mon, 18 Jul 2016 09:32:30 GMT</pubDate>
      <dc:creator><![CDATA[Marat F Bakirov]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mbakirov/?p=1295</guid>
      <description><![CDATA[Еще один кусочек знаний с последнего проекта.
У клиента была веб часть, которая выглядела точно так...]]></description>
      <content:encoded><![CDATA[Еще один кусочек знаний с последнего проекта.
У клиента была веб часть, которая выглядела точно так же, как и список файлов, но это была веб часть Content Search и она отображала файлы, найденные по определенному критерию на подсайтах.

Клиента не устраивало, что ссылки не предлагают открыть Word/Excel, а вместо этого просто предлагают скачать файл. Хочу, говорит, чтобы работало так же, как и просто в библиотеке документов.

Начал разбираться.
Было несколько причин.

Первая - в результатах поиска использовалось управляемой свойство (managed property) Path.
Это очень простое свойство, которое выдает путь до объекта.

Примерно так
https://sp131:82/Documents/excel1.xlsx

Но нам нужно было, чтобы ссылки учитывали OWA или Excel Services.

Я нашел вот этот пост.

<a href="https://www.eliostruyf.com/three-useful-managed-properties-for-working-with-office-web-apps/">https://www.eliostruyf.com/three-useful-managed-properties-for-working-with-office-web-apps/</a>
Кажется это единственный пост, в котором можно найти описание вот этих свойств:

• ServerRedirectedURL
• ServerRedirectedPreviewURL
• ServerRedirectedEmbedURL

Итого я использовал ServerRedirectedURL. На полноценной ферме у клиента результат выглядел примерно так :
<code>
https://server/_layouts/WopiFrame.aspx?sourcedoc={E526E4B1-6759-448F-B6C6-0C67E942173B}&amp;file=Documents/excel1.xlsx&amp;action=default&amp;DefaultItemOpen=1
</code>

А на моей локальной так :
<code>
https://sp131:82/_layouts/15/xlviewer.aspx?id=/Documents/excel1.xlsx&amp;DefaultItemOpen=1
</code>

Другой важный момент - как работают ссылки. В самой библиотеке документов ссылки пытаются открыть Word/Excel. В результатах поиска этого не происходило.

Вообще говоря, есть настройка, которая описывает данное поведение.
<a href="https://technet.microsoft.com/en-us/library/ee837425.aspx">https://technet.microsoft.com/en-us/library/ee837425.aspx</a>

<img class="alignnone size-full wp-image-162" src="https://mbakirov.files.wordpress.com/2016/07/2016-07-18_16-27-06.png" alt="2016-07-18_16-27-06" width="775" height="374" />

Можно найти в разделе "advanced settings" библиотеки документов.

Ссылки в библиотеке документов выглядели так:

При настройке "open in the client application".
<code>
<code>&lt;a class="ms-listlink ms-draggable" href="/Documents/doc1.docx" onmousedown="return VerifyHref(this,event,'0','SharePoint.OpenDocuments','')" onclick="return DispEx(this,event,'TRUE','FALSE','FALSE','SharePoint.OpenDocuments.3','0','SharePoint.OpenDocuments','','','','1','1','0','0x7fffffffffffffff')" dragid="1" draggable="true"&gt;doc1&lt;/a&gt;</code>
</code>

При настройке "open in the browser".
<code>
&lt;a class="ms-listlink ms-draggable" href="/Documents/doc1.docx" onmousedown="return VerifyHref(this,event,'1','SharePoint.OpenDocuments','')" onclick="return DispEx(this,event,'TRUE','FALSE','FALSE','SharePoint.OpenDocuments.3','1','SharePoint.OpenDocuments','','','','1','1','0','0x7fffffffffffffff')" dragid="1" draggable="true"&gt;doc1&lt;/a&gt;</code>

В моем случае клиента устроило, что мы всегда выбираем первый вариант.
Итоговый код:
<code>
<!--#_ var linkURL = $getItemValue(ctx, "Path"); linkURL.overrideValueRenderer($urlHtmlEncode); var ServerRedirectedURLValue = ''; var ServerRedirectedURL = $getItemValue(ctx, "ServerRedirectedURL"); ServerRedirectedURL.overrideValueRenderer($urlHtmlEncode); ServerRedirectedURLValue = ServerRedirectedURL.defaultValueRenderer(ServerRedirectedURL); if ( (ServerRedirectedURLValue == null) || (ServerRedirectedURLValue == undefined) || (ServerRedirectedURLValue == '')) ServerRedirectedURLValue = linkURL.defaultValueRenderer(linkURL); var onmousedown = "return VerifyHref(this,event,'0','SharePoint.OpenDocuments','1" +ServerRedirectedURLValue +"')"; var onclick = "return DispEx(this,event,'TRUE','FALSE','FALSE','SharePoint.OpenDocuments.3','0','SharePoint.OpenDocuments','','1"+ServerRedirectedURLValue+"','','2','0','0','0x7fffffffffffffff')"; _#-->
&lt;!--#_
var linkURL = $getItemValue(ctx, "Path");
linkURL.overrideValueRenderer($urlHtmlEncode);
var ServerRedirectedURLValue = '';
var ServerRedirectedURL = $getItemValue(ctx, "ServerRedirectedURL");
ServerRedirectedURL.overrideValueRenderer($urlHtmlEncode);
ServerRedirectedURLValue = ServerRedirectedURL.defaultValueRenderer(ServerRedirectedURL);
if ( (ServerRedirectedURLValue == null) || (ServerRedirectedURLValue == undefined) || (ServerRedirectedURLValue == ''))
ServerRedirectedURLValue = linkURL.defaultValueRenderer(linkURL);
var onmousedown = "return VerifyHref(this,event,'0','SharePoint.OpenDocuments','1" +ServerRedirectedURLValue +"')";
var onclick = "return DispEx(this,event,'TRUE','FALSE','FALSE','SharePoint.OpenDocuments.3','0','SharePoint.OpenDocuments','','1"+ServerRedirectedURLValue+"','','2','0','0','0x7fffffffffffffff')";
_#--&gt;
&lt;a class="cbs-Line1Link ms-noWrap ms-displayBlock"
onmousedown="_#= onmousedown =#_"
onclick="_#= onclick =#_"
href="_#= linkURL =#_" title="_#= $htmlEncode(line1.defaultValueRenderer(line1)) =#_" id="_#= line1LinkId =#_"&gt;_#= line1 =#_&lt;/a&gt;
</code>]]></content:encoded>
    </item>
    <item>
      <title>How to display correct document links in the search results.</title>
      <link>https://docs.microsoft.com/archive/blogs/mbakirov/how-to-display-correct-document-links-in-the-search-results</link>
      <pubDate>Mon, 18 Jul 2016 08:52:18 GMT</pubDate>
      <dc:creator><![CDATA[Marat F Bakirov]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mbakirov/?p=1285</guid>
      <description><![CDATA[At the recent client project there were an interesting situation. They had a web part that was...]]></description>
      <content:encoded><![CDATA[At the recent client project there were an interesting situation. They had a web part that was looking pretty much like a list with the only difference - it was a Content Search webpart and it was supposed to show certain the documents from all subsites. Pretty usual request.

However, the client pointed out, that the links are not the same as if they would use the "normal" documents view. The client was not happy that the links suggest to download the file instead of opening in Word/Excel/etc.

I have started to look.

There were a number of reasons why the links were different.
First reason is that they use  <b>Path </b> managed property.
Path managed property gives what it gives. The path.
Like this

<a href="https://sp131:82/Documents/excel1.xlsx">https://sp131:82/Documents/excel1.xlsx</a>

But it does not respect existence of the Excel services or the OWA.
So I found this blog post

<a href="https://www.eliostruyf.com/three-useful-managed-properties-for-working-with-office-web-apps/">https://www.eliostruyf.com/three-useful-managed-properties-for-working-with-office-web-apps/</a>

That was probably the only one explaining other important managed properties
<ul>
	<li>ServerRedirectedURL</li>
	<li>ServerRedirectedPreviewURL</li>
	<li>ServerRedirectedEmbedURL</li>
</ul>
&nbsp;

So I have used the ServerRedirectedURL. At the customer environment it returns a link to OWA, like this:

<code>
<a href="https://server/_layouts/WopiFrame.aspx?sourcedoc=%7bE526E4B1-6759-448F-B6C6-0C67E942173B%7d&amp;file=Documents/excel1.xlsx&amp;action=default&amp;DefaultItemOpen=1">https://server/_layouts/WopiFrame.aspx?sourcedoc={E526E4B1-6759-448F-B6C6-0C67E942173B}&amp;file=Documents/excel1.xlsx&amp;action=default&amp;DefaultItemOpen=1</a>
</code>

&nbsp;

At my local SharePoint dev single server machine it looked like this

<code>
<a href="https://sp131:82/_layouts/15/xlviewer.aspx?id=/Documents/excel1.xlsx&amp;DefaultItemOpen=1">https://sp131:82/_layouts/15/xlviewer.aspx?id=/Documents/excel1.xlsx&amp;DefaultItemOpen=1</a>
</code>

&nbsp;

Another difference was the way the links work. In the library itself the links tried to open the corresponding app - word or excel or the OWA. In the search results there were no prompt for opening the App.

&nbsp;

There is a setting that affects this behaviour It is well described in this article

<a href="https://technet.microsoft.com/en-us/library/ee837425.aspx">https://technet.microsoft.com/en-us/library/ee837425.aspx</a>

<img class="alignnone size-full wp-image-162" src="https://mbakirov.files.wordpress.com/2016/07/2016-07-18_16-27-06.png" alt="2016-07-18_16-27-06" width="775" height="374" />

&nbsp;

You can find it under "advanced" settings in the document library, and there are some other system wide settings that affect it.

&nbsp;

I have looked at the links in the list and found out that the links look like this

&nbsp;

When the library setting is like "open in the client application".

<code>
&lt;a class="ms-listlink ms-draggable" href="/Documents/doc1.docx" onmousedown="return VerifyHref(this,event,'0','SharePoint.OpenDocuments','')" onclick="return DispEx(this,event,'TRUE','FALSE','FALSE','SharePoint.OpenDocuments.3','0','SharePoint.OpenDocuments','','','','1','1','0','0x7fffffffffffffff')" dragid="1" draggable="true"&gt;doc1&lt;/a&gt;</code>

When the library setting is like "open in the browser".

<code>
&lt;a class="ms-listlink ms-draggable" href="/Documents/doc1.docx" onmousedown="return VerifyHref(this,event,'1','SharePoint.OpenDocuments','')" onclick="return DispEx(this,event,'TRUE','FALSE','FALSE','SharePoint.OpenDocuments.3','1','SharePoint.OpenDocuments','','','','1','1','0','0x7fffffffffffffff')" dragid="1" draggable="true"&gt;doc1&lt;/a&gt;</code>

In my case the customer was ok with hardcoding the option one. So the final resulting code was like this

<code>
<!--#_ var linkURL = $getItemValue(ctx, "Path"); linkURL.overrideValueRenderer($urlHtmlEncode); var ServerRedirectedURLValue = ''; var ServerRedirectedURL = $getItemValue(ctx, "ServerRedirectedURL"); ServerRedirectedURL.overrideValueRenderer($urlHtmlEncode); ServerRedirectedURLValue = ServerRedirectedURL.defaultValueRenderer(ServerRedirectedURL); if ( (ServerRedirectedURLValue == null) || (ServerRedirectedURLValue == undefined) || (ServerRedirectedURLValue == '')) ServerRedirectedURLValue = linkURL.defaultValueRenderer(linkURL); var onmousedown = "return VerifyHref(this,event,'0','SharePoint.OpenDocuments','1" +ServerRedirectedURLValue +"')"; var onclick = "return DispEx(this,event,'TRUE','FALSE','FALSE','SharePoint.OpenDocuments.3','0','SharePoint.OpenDocuments','','1"+ServerRedirectedURLValue+"','','2','0','0','0x7fffffffffffffff')"; _#-->
&lt;!--#_
var linkURL = $getItemValue(ctx, "Path");
linkURL.overrideValueRenderer($urlHtmlEncode);
var ServerRedirectedURLValue = '';
var ServerRedirectedURL = $getItemValue(ctx, "ServerRedirectedURL");
ServerRedirectedURL.overrideValueRenderer($urlHtmlEncode);
ServerRedirectedURLValue = ServerRedirectedURL.defaultValueRenderer(ServerRedirectedURL);
if ( (ServerRedirectedURLValue == null) || (ServerRedirectedURLValue == undefined) || (ServerRedirectedURLValue == ''))
ServerRedirectedURLValue = linkURL.defaultValueRenderer(linkURL);
var onmousedown = "return VerifyHref(this,event,'0','SharePoint.OpenDocuments','1" +ServerRedirectedURLValue +"')";
var onclick = "return DispEx(this,event,'TRUE','FALSE','FALSE','SharePoint.OpenDocuments.3','0','SharePoint.OpenDocuments','','1"+ServerRedirectedURLValue+"','','2','0','0','0x7fffffffffffffff')";
_#--&gt;
&lt;a class="cbs-Line1Link ms-noWrap ms-displayBlock"
onmousedown="_#= onmousedown =#_"
onclick="_#= onclick =#_"
href="_#= linkURL =#_" title="_#= $htmlEncode(line1.defaultValueRenderer(line1)) =#_" id="_#= line1LinkId =#_"&gt;_#= line1 =#_&lt;/a&gt;
</code>

&nbsp;]]></content:encoded>
    </item>
    <item>
      <title>Как добавить ссылку “Просмотреть библиотеку" к результатам поиска SharePoint Search из файлового источника (File Share)</title>
      <link>https://docs.microsoft.com/archive/blogs/mbakirov/%D0%BA%D0%B0%D0%BA-%D0%B4%D0%BE%D0%B1%D0%B0%D0%B2%D0%B8%D1%82%D1%8C-%D1%81%D1%81%D1%8B%D0%BB%D0%BA%D1%83-view-library-%D0%BA-%D1%80%D0%B5%D0%B7%D1%83%D0%BB%D1%8C%D1%82%D0%B0%D1%82</link>
      <pubDate>Fri, 15 Jul 2016 09:01:52 GMT</pubDate>
      <dc:creator><![CDATA[Marat F Bakirov]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mbakirov/?p=1265</guid>
      <description><![CDATA[На последнем проекте наткнулся на вопрос от заказчика, на который не нашел ответа в интернете.
Я...]]></description>
      <content:encoded><![CDATA[На последнем проекте наткнулся на вопрос от заказчика, на который не нашел ответа в интернете.
Я думаю, вы знаете ссылку "view library” - она появляется при поиске файлов?

<img src="https://msdnshared.blob.core.windows.net/media/2016/07/VirtualBox_SP2013SP1N_15_07_2016_17_29_38.png" alt="" />

У заказчика был настроен поиск по файловому ресуру, и ссылка не появлялась никак.
Решение казалось простым, но в интернете я ничего не нашел. Клиент - тоже не нашел.
Я думаю, Вы знаете механизм Display Templates, с помощью которых можно переопределить внешний вид результатов поиска.
Ссылки определяются в файле <strong>Item_CommonHoverPanel_Actions.html</strong>

Вот эта часть:

<code>
if(!Srch.U.e(ctx.CurrentItem.ParentLink) &amp;&amp; ctx.CurrentItem.csr_ShowViewLibrary) {
_#--&gt;</code>
<div class="ms-srch-hover-action"><a id="_#= $htmlEncode(id + HP.ids.parentLink) =#_" class="ms-calloutLink ms-uppercase" title="_#= $htmlEncode(Srch.Res.hp_Tooltip_ViewLibrary) =#_" href="_#= $urlHtmlEncode(ctx.CurrentItem.ParentLink) =#_">_#= $htmlEncode(Srch.Res.hp_ViewLibrary) =#_</a></div>
&lt;!--#_
}

Отлаживая данную часть, я обнаружил, что CurrentItem.ParentLink не заполняется при поиске через файловые ресуры.
Я, к сожалению, не могу пока точно сказать почему, но я могу сказать, как это подправить.

<code>
//ignia custom code
var url = ctx.CurrentItem.csr_Path;
if (url.indexOf('file://') &gt;=0)
{
var lastIndexOfSlash = url.lastIndexOf('/');
if (lastIndexOfSlash &gt; 0)
{
ctx.CurrentItem.ParentLink = url.substring(0,lastIndexOfSlash);
}
}
</code>

Вот и все!]]></content:encoded>
    </item>
    <item>
      <title>How to add "View Library" link to the SharePoint Search results from file share</title>
      <link>https://docs.microsoft.com/archive/blogs/mbakirov/how-to-add-view-library-link-to-the-sharepoint-search-results-from-file-share</link>
      <pubDate>Fri, 15 Jul 2016 08:28:24 GMT</pubDate>
      <dc:creator><![CDATA[Marat F Bakirov]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mbakirov/?p=1255</guid>
      <description><![CDATA[Recently a customer asked me to improve one little thing.
You know the “view library” link that...]]></description>
      <content:encoded><![CDATA[Recently a customer asked me to improve one little thing.
You know the “view library” link that appears once you search for the files in SharePoint?

<img src="https://mbakirov.files.wordpress.com/2016/07/virtualbox_sp2013sp1n_15_07_2016_17_15_58_1.png" alt="" />

These guys had setup a search over a file share, but the library link did not appear there.
Apparently the solution appeared to be rather simple. However, I did not find anything in the internet and the customer did not as well.
I assume you are familiar with the display templates concept in the SharePoint 2013. There templates are used to display search results and actually they are JavaScript files (or, in the case of SharePoint Standard, HTML files that generate the JS files).

So the links are rendered by the <strong>Item_CommonHoverPanel_Actions.html</strong>
This part renders the “View Library” link.

<code>
if(!Srch.U.e(ctx.CurrentItem.ParentLink) &amp;&amp; ctx.CurrentItem.csr_ShowViewLibrary) {
_#--&gt;</code>
<div class="ms-srch-hover-action"><a id="_#= $htmlEncode(id + HP.ids.parentLink) =#_" class="ms-calloutLink ms-uppercase" title="_#= $htmlEncode(Srch.Res.hp_Tooltip_ViewLibrary) =#_" href="_#= $urlHtmlEncode(ctx.CurrentItem.ParentLink) =#_">_#= $htmlEncode(Srch.Res.hp_ViewLibrary) =#_</a></div>
&lt;!--#_
}
<code></code>

While debugging I have found out that the CurrentItem.ParentLink is not filled.
I could not find out why it happens that way for the file shares, however, once I found this, the fix became very simple. I have added this simple piece of code before the block.
<code>
//ignia custom code
var url = ctx.CurrentItem.csr_Path;
if (url.indexOf('file://') &gt;=0)
{
var lastIndexOfSlash = url.lastIndexOf('/');
if (lastIndexOfSlash &gt; 0)
{
ctx.CurrentItem.ParentLink = url.substring(0,lastIndexOfSlash);
}
}
</code>

Simple!]]></content:encoded>
    </item>
    <item>
      <title>Работаем с ошибкой "Отсутствуют зависимости на стороне сервера" (Missing server side dependencies)</title>
      <link>https://docs.microsoft.com/archive/blogs/mbakirov/%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D0%B5%D0%BC-%D1%81-%D0%BE%D1%88%D0%B8%D0%B1%D0%BA%D0%BE%D0%B9-%D0%BE%D1%82%D1%81%D1%83%D1%82%D1%81%D1%82%D0%B2%D1%83%D1%8E%D1%82-%D0%B7%D0%B0%D0%B2%D0%B8%D1%81</link>
      <pubDate>Sun, 26 Jun 2016 12:56:35 GMT</pubDate>
      <dc:creator><![CDATA[Marat F Bakirov]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mbakirov/?p=1245</guid>
      <description><![CDATA[В данном посте я привожу свою методологию решения проблемы "Отсутствуют зависимости на стороне...]]></description>
      <content:encoded><![CDATA[В данном посте я привожу свою методологию решения проблемы "Отсутствуют зависимости на стороне сервера" (Missing server side dependencies).
В данном примере используется SharePoint 2010, но принцип остается тем же самым и в новых версиях (хотя честно говоря, на SP2016 я не проверял). Важно отметить, что в данном решении нам необходим доступ непосредственно в базу. 

В анализаторе SharePoint 

<img src="https://mbakirov.files.wordpress.com/2016/06/062616_1118_howtodealwi1.png" alt="" />

ошибка выглядит так:

<img src="https://mbakirov.files.wordpress.com/2016/06/062616_1118_howtodealwi2.png" alt="" />

На секунду задумаемся о том, что же это за ошибка и откуда она берется?

Допустим, у нас имеется серверное решение. В решении есть артефакт - ghosted file, или может быть веб часть. Веб часть могла быть установлена в галерею веб частей, или может быть добавлена на страницу. После чего по разным причинам веб часть удалили (обычно ее переименовывает кто нибудь). Но в базе SharePoint  остается запись о старой веб части. 

Что же делать?
Сначала нужно найти, где же на нашем сайте ссылка на "отсутствующий" компонент. 

Обычно я делаю это с помощью SQL. 
Возьмем скрипт, который пройдет по всем таблицам базы данных контента , и найдет там указанную строчку (в нашем случае ИМЯФАЙЛАВЕБЧАСТИ.webpart)
(В своей практике я несколько раз создавал и терял данный скрипт, так что пора его указать в блоге).

Скрипт взят отсюда и слегка модифицирован. 

<a href="https://stackoverflow.com/questions/591853/search-for-a-string-in-all-tables-rows-and-columns-of-a-db"><span style="color: blue;text-decoration: underline">https://stackoverflow.com/questions/591853/search-for-a-string-in-all-tables-rows-and-columns-of-a-db</span></a>


--

<strong>use WSS_Content -- could be your database name here</strong>

<strong>DECLARE</strong>

<strong> @search_string VARCHAR(100),</strong>

<strong> @table_name SYSNAME,</strong>

<strong> @table_schema SYSNAME,</strong>

<strong> @column_name SYSNAME,</strong>

<strong> @sql_string VARCHAR(2000)</strong>

<strong>SET @search_string = 'yourwebpart.webpart'</strong>

<strong>DECLARE tables_cur CURSOR FOR SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'</strong>

<strong>OPEN tables_cur</strong>

<strong>FETCH NEXT FROM tables_cur INTO @table_schema, @table_name</strong>

<strong>WHILE (@@FETCH_STATUS = 0)</strong>

<strong>BEGIN</strong>

<strong> DECLARE columns_cur CURSOR FOR SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @table_schema AND TABLE_NAME = @table_name AND COLLATION_NAME IS NOT NULL -- Only strings have this and they always have it</strong>

<strong> OPEN columns_cur</strong>

<strong> FETCH NEXT FROM columns_cur INTO @column_name</strong>

<strong> WHILE (@@FETCH_STATUS = 0)</strong>

<strong> BEGIN</strong>

<strong>-- SET @sql_string = 'IF EXISTS (SELECT * FROM ' + QUOTENAME(@table_schema) + '.' + QUOTENAME(@table_name) + ' WHERE ' + QUOTENAME(@column_name) + ' LIKE ''%' + @search_string + '%'') PRINT ''' + QUOTENAME(@table_schema) + '.' + QUOTENAME(@table_name) + ', ' + QUOTENAME(@column_name) + ''''</strong>

<strong> SET @sql_string = 'IF EXISTS (SELECT * FROM ' + QUOTENAME(@table_schema) + '.' + QUOTENAME(@table_name) + ' WHERE ' + QUOTENAME(@column_name) + ' LIKE ''%' + @search_string + '%'') SELECT * FROM ' + QUOTENAME(@table_schema) + '.' + QUOTENAME(@table_name) + ' WHERE ' + QUOTENAME(@column_name) + ' LIKE ''%' + @search_string + '%'''</strong>

<strong> EXECUTE(@sql_string)</strong>

<strong> FETCH NEXT FROM columns_cur INTO @column_name</strong>

<strong> END</strong>

<strong> CLOSE columns_cur</strong>

<strong> DEALLOCATE columns_cur</strong>

<strong> FETCH NEXT FROM tables_cur INTO @table_schema, @table_name</strong>

<strong>END</strong>

<strong>CLOSE tables_cur</strong>

<strong>DEALLOCATE tables_cur</strong>

--

Вот что получилось после запуска скрипта :

<img src="https://mbakirov.files.wordpress.com/2016/06/062616_1118_howtodealwi3.png" alt="" />

Итак, мы знаем, что сайт с идентификатором <strong>089D94D0-7BF4-4A51-9E29-2BACABC30DF4 </strong> содержит запись об отсутствующей веб части в галерее, и мы можем решить данную проблему с помощью <strong>PowerShell</strong> или вручную .

Вот пример другой веб части. В данном случае у нас некорректная веб часть находится в двух местах - на основном сайте и на личном сайте администратора.

<img src="https://mbakirov.files.wordpress.com/2016/06/062616_1118_howtodealwi4.png" alt="" />

К сожалению,  нам понадобится еще один скрипт. Скрипт выше отлично решает проблему веб части в галерее или отсутствующего файла, но не решает проблему веб части , расположенной на странице.
Вот еще один скрипт, который находит все веб части на всех страницах. Если раскоментировать последнюю строчку, то найдется нужная  веб часть.


<strong>SELECT Webs.FullUrl, Webs.Title, AllDocs.DirName, AllDocs.LeafName, AllWebParts.tp_DisplayName, AllWebParts.tp_ID

FROM AllDocs, Sites, AllWebParts, Webs

WHERE Webs.Id = Sites.RootWebId AND AllDocs.Id = AllWebParts.tp_PageUrlID

AND Sites.Id = AllDocs.SiteId AND tp_WebPartTypeId IN (

SELECT DISTINCT tp_WebPartTypeId FROM AllWebParts (NOLOCK)

WHERE tp_WebPartTypeId IS NOT NULL AND tp_Assembly IS NULL AND tp_Class IS NULL)

-- if you add this line, the script will find your specific web part instead of giving you all web parts on all pages

--AND (AllWebParts.tp_DisplayName = 'yourwebpartname')
</strong>

Вот что я получил при запуске скрипта:

Pic4.

<img src="https://mbakirov.files.wordpress.com/2016/06/062616_1118_howtodealwi5.png" alt="" />

Теперь, в зависимости от количества проблем, можно вручную или с помощью скрипта пройтись по указанным страницам и убрать Вашу веб часть. 

Правда, однажды, я столкнулся с ситуацией, которую долго не смог разрешить.
Дело в том, что несколько пользователей добавили веб часть в свою личную копию страницы.  Найти того, кто конкретно добавил, было невозможно (несколько тысяч пользователей).

К счастью, я вспомнил про еще один хороший прием. Дело в том, что если к любой странице <strong>?contents=1 </strong>

Вот таким образом можно сбросить все "личные" копии страницы.

<img src="https://mbakirov.files.wordpress.com/2016/06/062616_1118_howtodealwi6.png" alt="" />

А вот так - удалить "некорректную" веб часть. 

<img src="https://mbakirov.files.wordpress.com/2016/06/062616_1118_howtodealwi7.png" alt="" />
]]></content:encoded>
    </item>
    <item>
      <title>How to deal with “Missing server side dependencies” error</title>
      <link>https://docs.microsoft.com/archive/blogs/mbakirov/how-to-deal-with-missing-server-side-dependencies-error</link>
      <pubDate>Sun, 26 Jun 2016 12:02:13 GMT</pubDate>
      <dc:creator><![CDATA[Marat F Bakirov]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mbakirov/?p=1235</guid>
      <description><![CDATA[In this post I am going to show my methodology for dealing with the "Missing server side...]]></description>
      <content:encoded><![CDATA[In this post I am going to show my methodology for dealing with the "Missing server side dependencies" error. I do not have a good way to deal with it online but one good way to deal with it on-premises.

For this example I am using the SharePoint 2010, but the problem is the same in the newest versions (though honestly I did not check it on the SharePoint 2016).

This error appears in the SharePoint Health Analyzer

<img src="https://mbakirov.files.wordpress.com/2016/06/062616_1118_howtodealwi1.png" alt="" />

and looks like this:

<img src="https://mbakirov.files.wordpress.com/2016/06/062616_1118_howtodealwi2.png" alt="" />

Let us think for a second - why does this error happen and what is the inner reason for it?

Let us say your server side solution has some artefact. In this case it is the web part. Once upon a time the web part was a part of the solution and was deployed somewhere. Then you have decided you do not need the web part or simply has renamed it. However the content database already contains an information like "page xxx has a web part yyy in this zone with this settings".

And if the webpart does not exist the database is inconsistent.

It is not necessary a web part. You can add a ghosted module file and then decided to rename it. So the SharePoint will keep the information about the file in the database but the file will not be there.

Could be also that the web part gallery (_catalogs/wp contains information about your webpart and the webpart is also part of farm solution and do not exist anymore)

So the first step is to find where the web part is.

The way I was always doing it is via SQL. With the SQL you can search through the content database and find that specific string.

I have been making and losing the script the number of times, most recent time I have found a script in here

<a href="https://stackoverflow.com/questions/591853/search-for-a-string-in-all-tables-rows-and-columns-of-a-db"><span style="color: blue;text-decoration: underline">https://stackoverflow.com/questions/591853/search-for-a-string-in-all-tables-rows-and-columns-of-a-db</span></a>

And I have slightly modified it so it not only shows the table where the string is stored, but also specific lines.

--

<strong>use WSS_Content -- could be your database name here</strong>

<strong>DECLARE</strong>

<strong> @search_string VARCHAR(100),</strong>

<strong> @table_name SYSNAME,</strong>

<strong> @table_schema SYSNAME,</strong>

<strong> @column_name SYSNAME,</strong>

<strong> @sql_string VARCHAR(2000)</strong>

<strong>SET @search_string = 'yourwebpart.webpart'</strong>

<strong>DECLARE tables_cur CURSOR FOR SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'</strong>

<strong>OPEN tables_cur</strong>

<strong>FETCH NEXT FROM tables_cur INTO @table_schema, @table_name</strong>

<strong>WHILE (@@FETCH_STATUS = 0)</strong>

<strong>BEGIN</strong>

<strong> DECLARE columns_cur CURSOR FOR SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @table_schema AND TABLE_NAME = @table_name AND COLLATION_NAME IS NOT NULL -- Only strings have this and they always have it</strong>

<strong> OPEN columns_cur</strong>

<strong> FETCH NEXT FROM columns_cur INTO @column_name</strong>

<strong> WHILE (@@FETCH_STATUS = 0)</strong>

<strong> BEGIN</strong>

<strong>-- SET @sql_string = 'IF EXISTS (SELECT * FROM ' + QUOTENAME(@table_schema) + '.' + QUOTENAME(@table_name) + ' WHERE ' + QUOTENAME(@column_name) + ' LIKE ''%' + @search_string + '%'') PRINT ''' + QUOTENAME(@table_schema) + '.' + QUOTENAME(@table_name) + ', ' + QUOTENAME(@column_name) + ''''</strong>

<strong> SET @sql_string = 'IF EXISTS (SELECT * FROM ' + QUOTENAME(@table_schema) + '.' + QUOTENAME(@table_name) + ' WHERE ' + QUOTENAME(@column_name) + ' LIKE ''%' + @search_string + '%'') SELECT * FROM ' + QUOTENAME(@table_schema) + '.' + QUOTENAME(@table_name) + ' WHERE ' + QUOTENAME(@column_name) + ' LIKE ''%' + @search_string + '%'''</strong>

<strong> EXECUTE(@sql_string)</strong>

<strong> FETCH NEXT FROM columns_cur INTO @column_name</strong>

<strong> END</strong>

<strong> CLOSE columns_cur</strong>

<strong> DEALLOCATE columns_cur</strong>

<strong> FETCH NEXT FROM tables_cur INTO @table_schema, @table_name</strong>

<strong>END</strong>

<strong>CLOSE tables_cur</strong>

<strong>DEALLOCATE tables_cur</strong>

--

Once I have run the script I have seen this:

<img src="https://mbakirov.files.wordpress.com/2016/06/062616_1118_howtodealwi3.png" alt="" />

So now I know that the site with ID <strong>089D94D0-7BF4-4A51-9E29-2BACABC30DF4 </strong> contains a missing web part in the gallery, I guess I could just delete it? A simple <strong>get-spsite </strong>PowerShell command could find me the site and the gallery.

Here is another example of another webpart. This time we can see it happens on 2 different web sites - a default site and a personal site of the administrator.

<img src="https://mbakirov.files.wordpress.com/2016/06/062616_1118_howtodealwi4.png" alt="" />

However, running this script is not enough. This is another good script that will find your webpart on all pages.

SELECT Webs.FullUrl, Webs.Title, AllDocs.DirName, AllDocs.LeafName, AllWebParts.tp_DisplayName, AllWebParts.tp_ID

FROM AllDocs, Sites, AllWebParts, Webs

WHERE Webs.Id = Sites.RootWebId AND AllDocs.Id = AllWebParts.tp_PageUrlID

AND Sites.Id = AllDocs.SiteId AND tp_WebPartTypeId IN (

SELECT DISTINCT tp_WebPartTypeId FROM AllWebParts (NOLOCK)

WHERE tp_WebPartTypeId IS NOT NULL AND tp_Assembly IS NULL AND tp_Class IS NULL)

-- if you add this line, the script will find your specific web part instead of giving you all web parts on all pages

--AND (AllWebParts.tp_DisplayName = 'yourwebpartname')

Results of the script when run with my webpart:

Pic4.

<img src="https://mbakirov.files.wordpress.com/2016/06/062616_1118_howtodealwi5.png" alt="" />

Now depending on the number of pages and problems you could either clean the pages manually or make a script that will go through the pages and delete the webpart from it.

One more hint to finish this. Recently I met a problem I could not solve easily. Some users had added the obsolete Web Part to the Personal View of the page. So the script that would clean the web part could not delete this or even find the users! The content database did not help in this case.

So the simplest way to remove all personalized settings and the faulty/missing webpart from the page is to add the ?contents=1 to the page URL. This will bring the page into maintenance mode.

Here is how you remove all personal users settings

<img src="https://mbakirov.files.wordpress.com/2016/06/062616_1118_howtodealwi6.png" alt="" />

And here is how you delete the problematic web part from the page

<img src="https://mbakirov.files.wordpress.com/2016/06/062616_1118_howtodealwi7.png" alt="" />]]></content:encoded>
    </item>
    <item>
      <title>Sharepoint dev machine - не даем базам SQL  разрастись</title>
      <link>https://docs.microsoft.com/archive/blogs/mbakirov/sharepoint-dev-machine-%D0%BD%D0%B5-%D0%B4%D0%B0%D0%B5%D0%BC-%D0%B1%D0%B0%D0%B7%D0%B0%D0%BC-sql-%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D1%81%D1%82%D0%B8%D1%81%D1%8C</link>
      <pubDate>Tue, 31 May 2016 03:52:14 GMT</pubDate>
      <dc:creator><![CDATA[Marat F Bakirov]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mbakirov/?p=1206</guid>
      <description><![CDATA[Пора вернуться к написанию блога.

У меня был данный пост в старом блоге на gotdotnet, (RIP) и я с...]]></description>
      <content:encoded><![CDATA[Пора вернуться к написанию блога.

У меня был данный пост в старом блоге на gotdotnet, (RIP) и я с тех пор сожалею что никак не мог найти в интернете подходящий скрипт. Пришлось восстановить заново.

&nbsp;

Я периодически создаю себе одноверверные фермы для разработки. Свеже установленный SharePoint конфигурирует кучу баз, и каждая со временем разрастается.Хуже того, я сейчас использую  SSD в Azure (а там места совсем мало если брать за разумные деньги).

&nbsp;

То есть, если машина исползуется для РАЗРАБОТКИ, то можно переключить модель восстановления в режим simple (recovery mode = simple).До 2012 SQL была специальная опция "truncate log on checkpoint", но начиная с SQL 2012 ее больше нет (см. <a href="https://technet.microsoft.com/en-us/library/ms187310(v=sql.105).aspx">https://technet.microsoft.com/en-us/library/ms187310(v=sql.105).aspx</a> ).

&nbsp;

Я нашел хороший блог пост тут <a href="https://microtechpoint.com/index.php?route=blog/article&amp;article_id=10">https://microtechpoint.com/index.php?route=blog/article&amp;article_id=10</a> с хорошим наборои команд (реально радует заголовок "Shrinking Ginormous SharePoint Database Transaction Log Files" :)), , но эти команды работают только с одной базой.

&nbsp;

Я также нашел недокументированную хранимую процедуру sp_MSForEachDB (см. <a href="https://www.c-sharpcorner.com/UploadFile/63f5c2/sp_msforeachtable-stored-procedure-in-sql-server-2012/">https://www.c-sharpcorner.com/UploadFile/63f5c2/sp_msforeachtable-stored-procedure-in-sql-server-2012/</a> или  <a href="https://weblogs.sqlteam.com/joew/archive/2008/08/27/60700.aspx">https://weblogs.sqlteam.com/joew/archive/2008/08/27/60700.aspx</a> ), данная процедура может запустить некоторую команду для каждой базы.

&nbsp;

Итого я использовал следующую команду.(Можно обсуждать, нужен ли тут shrinkdataase или нужно ли добавить autoshrink).

EXEC sp_MSforeachdb 'USE [?]; print ''?'';  ALTER DATABASE [?] SET RECOVERY SIMPLE; CHECKPOINT; DBCC SHRINKDATABASE ([?],10); '

&nbsp;

Disclaimer: Я нигде не сказал, что я рекомендую модель simple  в production.

&nbsp;

&nbsp;

&nbsp;]]></content:encoded>
    </item>
  </channel>
</rss>