понедельник, 14 декабря 2015 г.

Заполнение свойств сотрудника при выборе его в People picker.

В этой статье я расскажу, как можно добавлять карточку сотрудника и при этом его свойства будут автоматически заполнены при выборе его в people picker.

воскресенье, 15 ноября 2015 г.

Удаление промежуточных версий файлов через PowerShell

Согласно документации MS количество промежуточных версий у списка/библиотеки должно быть не более 511, но я заметил что когда работаешь с файлом через WebDav, то не учитывается лимит который установлен в списке/библиотеки.

Т.е. к примеру когда я редактирую файл через Блокнот, то у меня плодятся промежуточные версии без ограничений.
То же с редактированием  файлов в локальных приложения офиса к примеру Word.

среда, 21 октября 2015 г.

среда, 9 сентября 2015 г.

представления в списке Доска обсуждений

При создании списка «Доска обсуждений» мы получаем представление AllItems.aspx которое не доступно для редактирования. Если присмотрится внимательно, то можно заметить, что переключение между отображением информации происходит через JS .
Немного углубившись я заметил следующее:
Изменение отображения происходит при вызове функции

SP.UI.Discussions.SortFilterItem.onPivotControlMenuOptionClick('SortItem1')



При изменении параметра меняется отображение данных.Использование SortItem1 равносильно нажатию на «Последние»

Так же при использовании разных параметров меняет способ визуализация представления.

понедельник, 7 сентября 2015 г.

Форматирование календаря с помощью JS + REST

Сегодня я расскажу, как можно произвести форматирование в представлении Календарь стандартного списка. В интернете можно найти решения, когда создается вычисляемое поле, в него подается значение из нескольких полей элемента. В представлении выводится вычисляемое поле, а дальше с помощью JS происходит форматирование и скрытие лишней информации. В целом решение не плохое, но мне не особо понравилось, и я решил пойти по другому пути…

Берем представление списка «Календарь» пробегаем по всем ссылкам на в календаре и формируем массив ссылок.


Далее из ссылок получаем Id элементов и делаем запрос к списку. В итоге получаем любые поля из списка и можем с ними работать.
К примеру, можно применить форматирование.


function  getColor(login)
{
 var color;
 login = login.replace("i:0#.w|domain\\","");
 switch(login){
  case "Kaplin Vladimir" : color = "red"; break;
  case "P Michael" : color = "green"; break;
  case "F Pavel" : color = "rgba(254, 164, 0, 1)"; break;

  default: color = "rgb(78, 142, 227)"
  
 }
 return color;
}

function postRender()
{
 data = jQuery("a[href*='.aspx?ID=']");
 //обработка ссылок на элементы
 var arrayID = [] 
 for (var i=0; i <  data.length; i++)
 { 
  var str = data[i].toString();
  var start = str.indexOf('?ID=');
  var end = str.indexOf('"',start);
  if (end == -1){
   var id = str.slice(start+4);
  }
  else{
   var id = str.slice(start+4, end+1);
  }
 
  arrayID.push("Id eq " + id);
 } 
 //работа с объектами элементов
 if (arrayID.length > 0)
 {
  var getItems = getListItem(arrayID.join(" or "));
  getItems.done(function (data, status, xhr) {   
   var items = data.d.results; 
   for(var i=0; i < items.length; i++ )
   {   
    var url = String.format("a[href*='.aspx?ID={0}']", items[i].ID)
    if(items[i].Editor.Title)
    {
     console.log(items[i].Editor.Title)
     var color = getColor(items[i].Editor.Title)
     jQuery(url).closest(".ms-acal-item").css("background-color", color)      
    };    
   }
  })
  getItems.fail(onError)
 }
}
function onError(error) {
    console.log(error.responseText);
}


function getListItem(itemId) { 
 var listTitle = "Заявки"  // название списка
 var webUrl = _spPageContextInfo.webAbsoluteUrl;
 var selectFields = ["Id","Title","Editor/Id","Editor/Title"]; // получаемые поля
 var expandFields = ["Editor/Id","Editor/Title"]; // поля подстановки 
 var listItemUri = webUrl + "/_api/web/lists/GetByTitle('"+ listTitle + "')/Items?$filter=" + itemId+ "&$select="+selectFields.join()+"&$expand="+expandFields.join();
 request = jQuery.ajax({
      url: listItemUri,
      type: "GET",
      headers: { "accept": "application/json;odata=verbose" }
     }); 
 request.done(function (data){console.log('данные REST полученны, объектов - ' + data.d.results.length );});  
 request.fail(function (){console.log('Ошибка при вылнении запроса REST')}); 
 return request;       
}


/* =======================================================================
блок для вызова функции обработки при изменении представления месяц - день 
======================================================================*/ 
 function onCalendarGridsRendered(){
    setTimeout(function () { 
        postRender()
    }, 100);
}

function onCalendarResized(){
    setTimeout(function () { 
        //Add your functionality here
  postRender()
    }, 100);
}

SP.SOD.executeOrDelayUntilScriptLoaded(function () {

    //Week or Day Calendar View
    SP.UI.ApplicationPages.DetailCalendarView.prototype.renderGrids_Old = 
        SP.UI.ApplicationPages.DetailCalendarView.prototype.renderGrids;
    SP.UI.ApplicationPages.DetailCalendarView.prototype.renderGrids = 
        function SP_UI_ApplicationPages_DetailCalendarView$renderGrids($p0) {
        this.renderGrids_Old($p0);

        onCalendarGridsRendered();
    };
    
    //Month Calendar View
    SP.UI.ApplicationPages.SummaryCalendarView.prototype.renderGrids_Old = 
        SP.UI.ApplicationPages.SummaryCalendarView.prototype.renderGrids;
    SP.UI.ApplicationPages.SummaryCalendarView.prototype.renderGrids = 
        function SP_UI_ApplicationPages_SummaryCalendarView$renderGrids($p0) {
        this.renderGrids_Old($p0);

        onCalendarGridsRendered();
    };

    //Resize Calendar
    SP.UI.ApplicationPages.CalendarStateHandler.prototype.parentResized_Old = 
        SP.UI.ApplicationPages.CalendarStateHandler.prototype.parentResized;
    SP.UI.ApplicationPages.CalendarStateHandler.prototype.parentResized = 
        function SP_UI_ApplicationPages_CalendarStateHandler$parentResized() {
        this.parentResized_Old();

        onCalendarResized();
    };
}, "SP.UI.ApplicationPages.Calendar.js"); 

Можно пойти дальше, т.к. мы можем получить любые данные из элемента, то и можем с ними работать. вот пример фильтрации элементов в календаре.
Да, решение не столь красивое, но можно реализовать используя штатные вещи.

понедельник, 10 августа 2015 г.

Создание элемента списка в папке используя REST

Все больше в своих решениях я использую REST запросы и для одной из задач необходимо было создавать элементы в папках.

Для начала нужно проверить есть ли папка или папку нужно ее создать:
Пример :
 checkingExistenceFolder("Билеты", "Folder 10")

function checkingExistenceFolder(listTitle, folderTitle)
{
 filter = "ContentTypeId eq '0x0120001EE026E991F8644A85A5F2888FADB06D' and Title eq '" + folderTitle +"'"; 
 query =  getRest(listTitle,"",filter,"","")
 query.done(function (data, status, xhr) {
  if(data.d.results.length > 0)
  {
   console.log(data.d.results.length);
   console.log("папка '" + folderTitle + "' найдена ")
  }
  else{
   console.log("папка '" + folderTitle + "' не найдена");  
   createFolder(listTitle,folderTitle)
  }
  
  
 });
 query.fail(function (){
  console.log("папка '" + folderTitle + "' не найдена");  
 }); 
 
}
function createFolder(listTitle,folderName)
{ 
 var webUrl = _spPageContextInfo.webAbsoluteUrl;
 var uri = webUrl + "/_api/web/lists/GetByTitle('"+listTitle+"')/Items/";
 console.log(uri);
 var getlistType = getListEntityTypeName(listTitle);
 getlistType.done(function (data, status, xhr) {
  console.log(data.d.EntityTypeName)
  var listType = data.d.EntityTypeName
 
  var body = "{ '__metadata': { 'type': 'SP.Data." + listType + "Item' },  'Title': '" + folderName + "', 'FileLeafRef': '" + folderName + "', 'ContentTypeId': '0x0120001EE026E991F8644A85A5F2888FADB06D'}"
  var newItem = addListItem(listTitle, body);
  newItem.done (function (data, status, xhr) {
   console.log(data)
   var newItemId = data.d.Id;
   var body = "{ '__metadata': { 'type': 'SP.Data." + listType + "Item' },  'FileLeafRef': '" + folderName + "' }";
   updateListItem(listTitle, newItemId, body);
   
   
  });
  
 });  
} 


function addListItem(listTitle,body)
{
 var webUrl = _spPageContextInfo.webAbsoluteUrl;
 var uri = webUrl + "/_api/web/lists/GetByTitle('"+listTitle+"')/Items/"; 
 var query = jQuery.ajax({
     url: uri,
     type: "POST",
     data: body,
     contentLength: body.length,
     headers: {  "accept": "application/json; odata=verbose", 
        "content-type" : "application/json; odata=verbose",
        "X-RequestDigest" : jQuery("#__REQUESTDIGEST").val() }
    }); 
 query.done(function (data){ console.log('элемент создан'); console.log(data)
 
  });  
 query.fail(function (error){console.log('Ошибка при создании элемента'); console.log(error)}); 
 return query;
}

Хорошо, теперь нужно создать элемент в требуемой папке, но вот не задача, у элемента нет свойства заполнив которое получим требуемое.
Для решения этой проблемы нашел обходной путь.
Для начала создаём элемент в корне списка, а потом переносим в требуемую папку.


перемещение 
moveListItem( "Билеты", "Folder 10", 26)


function moveListItem( listTitle, folderTitle, itemId)
{
 var getlistType = getListEntityTypeName(listTitle);
 getlistType.done(function (data, status, xhr) {
  console.log(data.d.EntityTypeName)  
  var listType = data.d.EntityTypeName;
  var listInternalName = listType.substring(0, listType.length - 4 )
  console.log(listInternalName)
    var webUrl = _spPageContextInfo.webAbsoluteUrl;
  var uri = webUrl+ "/_api/web/getfilebyserverrelativeurl('/Lists/"+ listInternalName + "/" + itemId+ "_.000')/moveto(newurl='/Lists/"+ listInternalName + "/" + folderTitle + "/" + itemId+ "_.000',flags=1)";
  var query = jQuery.ajax({
   url: uri,
   type: "POST",
   headers: {  "accept": "application/json; odata=verbose", 
      "content-type" : "application/json; odata=verbose",
   "X-RequestDigest" : jQuery("#__REQUESTDIGEST").val()} 
   });
   query.done(function (data){ console.log('элемент создан'); console.log(data) });  
   query.fail(function (error){console.log('Ошибка при создании элемента'); console.log(error)}); 
  

 });
}
function getListEntityTypeName(listTitle)
{
 var webUrl = _spPageContextInfo.webAbsoluteUrl;
 var uri = webUrl + "/_api/web/lists/GetByTitle('"+listTitle+"')/EntityTypeName";
 var queryAjax = jQuery.ajax({
      url: uri,
      type: "GET",
      headers: {  "accept": "application/json; odata=verbose", 
         "content-type" : "application/json; odata=verbose",
         "X-RequestDigest" : jQuery("#__REQUESTDIGEST").val() }
     }); 
 queryAjax.done(function (data){ console.log('EntityTypeName полученны'); console.log(data)});  
 queryAjax.fail(function (){console.log('Ошибка при вылнении запроса EntityTypeName')}); 
 return queryAjax; 
} 
Если заметили, то мне пришлось еще использовать доп функцию которая возвращает  EntityTypeName. в первом случае я его использую для создания папки, а второй раз при перемещении элемента, т.к. нужно указывать путь (Url)

Еще пришлось обновлять элемент при создании папки, т.к. при ее создании путь и Title верный, но вот Name имеет вид "12_.000"

По этому у созданной папки указываем 'FileLeafRef', т.к. при создании заполнить его не получается.

скрипт целиком

function checkingExistenceFolder(listTitle, folderTitle)
{
 filter = "ContentTypeId eq '0x0120001EE026E991F8644A85A5F2888FADB06D' and Title eq '" + folderTitle +"'"; 
 query =  getRest(listTitle,"",filter,"","")
 query.done(function (data, status, xhr) {
  if(data.d.results.length > 0)
  {
   console.log(data.d.results.length);
   console.log("папка '" + folderTitle + "' найдена ")
  }
  else{
   console.log("папка '" + folderTitle + "' не найдена");  
   createFolder(listTitle,folderTitle)
  }
  
  
 });
 query.fail(function (){
  console.log("папка '" + folderTitle + "' не найдена");  
 }); 
 
}
function createFolder(listTitle,folderName)
{ 
 var webUrl = _spPageContextInfo.webAbsoluteUrl;
 var uri = webUrl + "/_api/web/lists/GetByTitle('"+listTitle+"')/Items/";
 console.log(uri);
 var getlistType = getListEntityTypeName(listTitle);
 getlistType.done(function (data, status, xhr) {
  console.log(data.d.EntityTypeName)
  var listType = data.d.EntityTypeName
 
  var body = "{ '__metadata': { 'type': 'SP.Data." + listType + "Item' },  'Title': '" + folderName + "', 'FileLeafRef': '" + folderName + "', 'ContentTypeId': '0x0120001EE026E991F8644A85A5F2888FADB06D'}"
  var newItem = addListItem(listTitle, body);
  newItem.done (function (data, status, xhr) {
   console.log(data)
   var newItemId = data.d.Id;
   var body = "{ '__metadata': { 'type': 'SP.Data." + listType + "Item' },  'FileLeafRef': '" + folderName + "' }";
   updateListItem(listTitle, newItemId, body);
   
   
  });
  
 });  
} 


function addListItem(listTitle,body)
{
 var webUrl = _spPageContextInfo.webAbsoluteUrl;
 var uri = webUrl + "/_api/web/lists/GetByTitle('"+listTitle+"')/Items/"; 
 var query = jQuery.ajax({
     url: uri,
     type: "POST",
     data: body,
     contentLength: body.length,
     headers: {  "accept": "application/json; odata=verbose", 
        "content-type" : "application/json; odata=verbose",
        "X-RequestDigest" : jQuery("#__REQUESTDIGEST").val() }
    }); 
 query.done(function (data){ console.log('элемент создан'); console.log(data)
 
  });  
 query.fail(function (error){console.log('Ошибка при создании элемента'); console.log(error)}); 
 return query;
}
function moveListItem( listTitle, folderTitle, itemId)
{
 var getlistType = getListEntityTypeName(listTitle);
 getlistType.done(function (data, status, xhr) {
  console.log(data.d.EntityTypeName)  
  var listType = data.d.EntityTypeName;
  var listInternalName = listType.substring(0, listType.length - 4 )
  console.log(listInternalName)
    var webUrl = _spPageContextInfo.webAbsoluteUrl;
  var uri = webUrl+ "/_api/web/getfilebyserverrelativeurl('/Lists/"+ listInternalName + "/" + itemId+ "_.000')/moveto(newurl='/Lists/"+ listInternalName + "/" + folderTitle + "/" + itemId+ "_.000',flags=1)";
  var query = jQuery.ajax({
   url: uri,
   type: "POST",
   headers: {  "accept": "application/json; odata=verbose", 
      "content-type" : "application/json; odata=verbose",
   "X-RequestDigest" : jQuery("#__REQUESTDIGEST").val()} 
   });
   query.done(function (data){ console.log('элемент создан'); console.log(data) });  
   query.fail(function (error){console.log('Ошибка при создании элемента'); console.log(error)}); 
  

 });
}


function updateListItem(listTitle, itemId, body)
{
 var webUrl = _spPageContextInfo.webAbsoluteUrl;
 var uri = webUrl + "/_api/web/lists/GetByTitle('"+listTitle+"')/Items("+ itemId +")"; 
 var query = jQuery.ajax({
     url: uri,
     type: "POST",
     data: body,
     contentLength: body.length,
     headers: {  "accept": "application/json; odata=verbose", 
        "content-type" : "application/json; odata=verbose",
        "X-HTTP-Method":"MERGE",
        "IF-MATCH": "*",
        "X-RequestDigest" : jQuery("#__REQUESTDIGEST").val() }
    }); 
 query.done(function (data){ console.log('элемент обновлен'); console.log(data)
 
  });  
 query.fail(function (error){console.log('Ошибка при обновлении элемента'); console.log(error)}); 
 return query;
}
function getListEntityTypeName(listTitle)
{
 var webUrl = _spPageContextInfo.webAbsoluteUrl;
 var uri = webUrl + "/_api/web/lists/GetByTitle('"+listTitle+"')/EntityTypeName";
 var queryAjax = jQuery.ajax({
      url: uri,
      type: "GET",
      headers: {  "accept": "application/json; odata=verbose", 
         "content-type" : "application/json; odata=verbose",
         "X-RequestDigest" : jQuery("#__REQUESTDIGEST").val() }
     }); 
 queryAjax.done(function (data){ console.log('EntityTypeName полученны'); console.log(data)});  
 queryAjax.fail(function (){console.log('Ошибка при вылнении запроса EntityTypeName')}); 
 return queryAjax; 
} 

среда, 15 июля 2015 г.

Удаление привилегированных прав у пользователя во всем веб-приложении

После изменения должностных обязанностей одного сотрудника появилась необходимость удалить у него  повышенные права (полный доступ).
Руками решать эту задачу было бы очень долго...
прибегнул к PowerSell
данный скрип пробегает по всем сайтам в веб-приложении и удаляет от туда пользователя. После этого у пользователя остались права выданные через группы AD  и  через группу "ВСЕ"

cls
$login = 'i:0#.w|doman\user'
$app = Get-SPWebApplication http://url-app

foreach ($sites in $app.Sites)
{ 
    $collSite = $sites.AllWebs
    foreach ($web in $sites.AllWebs)
    {    


        # удаляем из всех групп            
        foreach($group in $web.Groups)
        {
            foreach($user in $group.Users )
            {
                if($user.UserLogin -eq $login)
                {
                    $web.Url
                    $userRemove = $web.AllUsers.Item($login)            
                    $group.RemoveUser( $userRemove)
                    Write-Host "Сайт -" $web.Title " / удален из группы -"  $group.Name -foregroundcolor Yellow
                }
            }
        }

        # удаляем из администраторов сайта
        $admins = $web.SiteAdministrators
        for ($i = 0 ; $i -le $admins.Count; $i++)
        {
            if( $admins[$i].UserLogin -eq $login)
            {
                $web.Url
                $userRemove = $web.AllUsers.Item($login)            
                $admins.RemoveByID( $userRemove.ID)
                Write-Host "Сайт -" $web.Title " / удален из администраторов сайта" -foregroundcolor blue
            }

        }
        $web.Dispose();
    }
}

понедельник, 29 июня 2015 г.

Применение фильтров к полям в представлении с помощью кнопок

Захотел облегчить работу пользователей в SharePoint, и добавить кнопки фильтрации по полю.
Т.к. значений там не много, то я создал кнопки при клике, на которую переходили по адресу http://текущий_адрес.aspx?FilterField1=Vendor&FilterValue1=VMware
В FilterField1 указываем интернал нейм поля, в FilterValue1 значение.
Представлений стало много (активные заявки, выполненные и т.п.) и для каждого представления прописывать руками жестко адрес было лень сделал более универсальный код, который сам берет текущий адрес и работает с ним.
Для красоты добавил Bootstrap.





воскресенье, 28 июня 2015 г.

Ошибка поиска по дате или как менять языковые параметры.

После установки весенних обновлений веб-часть отображений дней рождения (о которой написал статьи) стала выдавать ошибку.


Замечено, что проблема бывает только в Internet Explorer.
После более глубокого изучения стало понятно, что дело в языковых параметрах.
Путь первый:
Если в расладке клавиатуры по умолчанию использовать En, то в Internet Explorer вываливается ошибка и язык интерфейса SharePoint становится En. (экспериментировал с Win 8.1)

Если поменять раскладку по умолчанию, то все нормально.
Согласитесь, ведь не всем удобно использовать в раскладке по умолчанию русский язык.
Путь второй:
Поменять в свойствах пользователя языки, точнее добавить «Русский язык»

В этом случае не учитывается параметры раскладки локальной машины и сайт отображается на русском и с веб-частью проблем не заметил.
Но как сделать это у всех?

На помощь может прейти знакомый PowerShell

$mySiteUrl = "http://my.sites.com" 

#Connect to User Profile Manager service 
$site = Get-SPSite $mySiteUrl 
$context = Get-SPServiceContext $site 
$profileManager = New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($context) 

for($i=1; $i -le $profileManager.Count; $i++ )
{

    $user = $profileManager.GetUserProfile($i)
    write-host $user.AccountName - $user['SPS-MUILanguages']
    $user['SPS-MUILanguages'].Value = "ru-RU"
    $user.Commit()
}


пятница, 5 июня 2015 г.

работа с Flexi Task Nintex с помощью javascript

В компании, для автоматизации бизнес процессов применяется Nintex и вот появилась задача, вывести на форме элемента кнопки согласования. В интернете много решений с использованием InfoPaht, но так как я его не люблю, то использовал javascript.


вторник, 26 мая 2015 г.

Crawl Rules Search People SharePoint 2013

Возникла потребность, что бы некоторые пользователи не отображались в результатах поиска, ранее, в SharePoint 2010 у меня с этим проблем не возникало. Но вот с SharePoint 2013 возникли проблемы.
Как выглядит адрес профиля пользователя:
согласно Regular Expressions Support in SharePoint 2010 Crawling  все тоже должно быть хорошо.
Для проверки выражения для правила, чтобы после каждого изменения правла не ждать полного обхода, пошел по другому пути. Зашел в Crawl Log > URL View   и в строке экспериментировал.
Если пустая строка, то показывает весь индексированный контент
Если ввести адрес
то результатов у меня не выводило

если так:
то результат уже выводился.

Но вот с обратным слешем «\» возникли проблемы

Я пробовал и [\\] и [\] и %5C

Решение.

Как обходной путь использовать в место «\» использовать «*»
Выглядит примерно так http://my.site:80*person.aspx?accountname=domain*user1

Для пользователей forms-based authentication у них путь выглядит
для того что бы исключить из результатов поиска все таких пользователей я использовал правило

после добавления правил индекса нужно запустить Full Crawl



вторник, 12 мая 2015 г.

REST запросы /_vti_bin/ и /_api/web/ в SahrePoint

Решил по лучше узнать REST (т.к. от CSOM рекомендуют уходить постепенно), но возникли некоторые сложности, т.к. присутствует локализация SharePoint (установлен языковой пакет) и выглядит вот так:
При обращении к элементу списка Employees

получаем отображаемые названия полей
через JavaScript (предварительно подключив jQuery)


_spBodyOnLoadFunctionNames.push("getEmployees");
function getEmployees()
{
  $.getJSON(_spPageContextInfo.webAbsoluteUrl + "/_vti_bin/listdata.svc/Employees?$select=Создано,Название",
  function (data) {  
    console.log(data)
  });
} 
получаем

согласитесь, что это не удобно
как решение использовать не /_vti_bin/, а /_api/web/

http://site/_api/web/lists/GetByTitle('Employees')/items(1)?$select=Title
получаем

через JavaScript (предварительно подключив jQuery)
_spBodyOnLoadFunctionNames.push("getEmployees");
function getEmployees()
{
  var request = $.ajax({
    url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('Employees')/items?$select=Title",
    type: "GET",
    headers: {"Accept": "application/json;odata=verbose"},
    cache:false,                
    success: function(data){  
      console.log("моя функция")
      }
   });
      
  request.done(function (data){ console.log('данные REST получены, объектов - ' + data.d.results.length); 
          console.log(data)
         });  
  request.fail(function (){console.log('Ошибка при выполнении запроса REST')}); 
} 

на выходе


как уже могли заметить данные получаем не через $.getJSON(), а через $.ajax(), т.к. на нужено передать свойство headers: {"Accept": "application/json;odata=verbose"}, что бы нам вернулся JSON
так же я добавил обработчики .done() и fail(), что бы выводить информацию по результатам выполнения запроса REST

воскресенье, 3 мая 2015 г.

UserProfileApplication.SynchronizeMIIS: Failed to configure MIIS post database, will attempt during next rerun. Exception: System.Configuration.ConfigurationErrorsException: ERR_CONFIG_DB

Спустя время после переезда баз данных в другой кластер было замечено, что служба User Profiles Service не запущена, при старте службы ничего не происходило. В Event Viewer было чисто.
  В начале были предположения относительно прав и политик, которые менялись в последнее время, но все без успешно.
Посмотрел ULS я увидел ошибку «UserProfileApplication.SynchronizeMIIS: Failed to configure MIIS post database, will attempt during next rerun. Exception: System.Configuration.ConfigurationErrorsException: ERR_CONFIG_DB»
В начале наткнулся  на “Stuck on Starting”: Common Issues with SharePoint Server 2010 User Profile Synchronization, но права были в порядке.
Так же были у людей проблемы из-за SQL Server 2014, но у меня был SQL Server 2012.

Решение

Оказалось нужно было поставить SQL Server 2008 R2 SP1 Native Client
Скачать можно тут https://www.microsoft.com/en-us/download/details.aspx?id=26728
Нужен 1033\x64\sqlncli.msi  - 7.7 MB



понедельник, 27 апреля 2015 г.

Get-SPWeb : Cannot find an SPWeb object with Id or Url : http://site

Некоторое время назад проводили работы по переносу баз в другой кластер и после этого заметил, что при обращении к сайту через PowerShell от имени SP_Admin, возникает ошибка:

Get-SPWeb : Cannot find an SPWeb object with Id or Url : http://site/ and site Url http://site. At line:1 char:1+ Get-SPWeb http://site/+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~    + CategoryInfo          : InvalidData: (Microsoft.Share....SPCmdletGetWeb:SPCmdletGetWeb) [Get-SPWeb], SPCmdletPipeBindException    + FullyQualifiedErrorId : Microsoft.SharePoint.PowerShell.SPCmdletGetWeb

После добавления учетки как SPShellAdmin ситуация не менялась. Хотя с другими сайтами (находящихся в других базах) все было хорошо.
После добавления учетке прав sysadmin на инстанс SQL, ошибка проходила. 
Видимо проблема была связана с миграцией с SharePoint 2010  в 2013.

РЕШЕНИЕ

Проблема решилась созданием новой базы и перемещение в нее семейства сайтов.


пятница, 17 апреля 2015 г.

Ошибка: Не удалось завершить эту операцию. Повторите попытку.

При создании одного сайта, все списки и библиотеки выдавали следующее сообщение:

Не удалось завершить эту операцию.  Повторите попытку. 



Посмотрев внимательно логи, я заметил: Microsoft.SharePoint.SPTimeZone.EnsureTZData()   

перешел в параметры сайта (/_layouts/15/regionalsetng.aspx) и поменял тайм зону на «Москва» и все стало отлично.
так же, пошел в ЦА > веб-приложение > параметры веб-приложения и поменял там значение тайм зоны для вновь создаваемых сайтов.

надеюсь будет Вам полезно


  

четверг, 26 марта 2015 г.

Кнопки "Утвердить" и "Отклонить" в ItemForm с помощью jQuery

Сегодня я расскажу, как добавить кнопки «Утвердить» и «Отклонить» в место стандартной кнопки «Save» и заполнять поле типа Choice требуемым значением.
выглядеть будет в итоге так

пятница, 20 февраля 2015 г.

Работа с полями элемента с помощью jQuery в EditForm (jQuery + SharePoint 2013 Fields Part 4)

Ранее я рассказывал, как можно работать с полями элемента, те примеры хорошо применять в NewForm создания элемента. Сегодня я хочу рассказать, как можно работать с полями в форме EditForm.
В этой статье:
1. Режим "только чтение" для полей 
2. Скрытие комментариев к полю
3. Скрытие полей в зависимости от значений

понедельник, 2 февраля 2015 г.

Поиск давно не используемых списков и библиотек с помощью PowerShell

Сегодня я расскажу как найти все старые списки, элементы которых давно не меняли.


 
$arraySite =
"http://site/",
"http://site/hr/" # перечень семейства сайтов, через запятую

$modifieDate = "09/24/2014 00:00:00"  #дата последнего изменения

$ListsInfo = @{}
$TotalItems = 0
Foreach ($currentSite in $arraySite)
{
   $SiteCollection = Get-SPSite $currentSite
   ForEach ($Site in $SiteCollection.AllWebs)
   {
                 ForEach ($List in $Site.Lists)
                 {
                                 if ($List.LastItemModifiedDate -lt $modifieDate) 
                                {
                                   $ListsInfo.Add($Site.Url + " - " + $List.Title, $List.LastItemModifiedDate)
                                   $TotalItems += $List.ItemCount
                                }
                 }
   $SiteCollection.Dispose()
   }
}
$ListsInfo.GetEnumerator() | sort name | Format-Table -Autosize
Write-Host "Количество списков: " $ListsInfo.Count
Write-Host "Общее количество элементов: " $TotalItems
получаем такой результат
Обновление!!!
на форуме меня попросили написать аналогичный код для поиска страниц, которые находятся в библиотеках с названием "Страницы сайта" 

$arraySite =
"http://site"

$modifieDate = "01.12.2014 00:00:00"  #дата изменения mm.dd.yyyy
$listTitle = "Страницы сайта"

$ListsInfo = @{}
$TotalItems = 0

Foreach ($currentSite in $arraySite)
{
   $SiteCollection = Get-SPSite $currentSite
   ForEach ($Site in $SiteCollection.AllWebs)
   {
                 ForEach ($List in $Site.Lists)
                 {
                                 if ($List.Title    -eq $listTitle) 
                                {
                                    $items = $List.Items
                                    foreach($item in $items)
                                        {                                           
                                            
                                            if ($item['Modified']  -le $modifieDate) 
                                            {
                                            
                                               $ListsInfo.Add($Site.Url + " - " + $item.Name , $item['Modified'])
                                               $TotalItems += $List.ItemCount
                                            }
                                        }

                                }

                 }
   $SiteCollection.Dispose()
   }
}
$ListsInfo.GetEnumerator() | sort name | Format-Table -Autosize
Write-Host "Количество страниц: " $TotalItems


Надеюсь статья будет Вам полезна.

пятница, 23 января 2015 г.

Forefront Identity Manager Synchronization Service is not starting

Недавно произвел обновление и на двух серверах разработчиков перестала работать служба Forefront Identity Manager Synchronization Service
В Event было:
Evetn 1000
Faulting application name: miiserver.exe, version: 4.0.2450.51, time stamp: 0x52b234fe
Faulting module name: MSVCR90.dll, version: 9.0.30729.6871, time stamp: 0x4fee5fd5
Exception code: 0x40000015
Fault offset: 0x0000000000042686
Faulting process id: 0x8bc
Faulting application start time: 0x01d03708d749fd18
Faulting application path: C:\Program Files\Microsoft Office Servers\15.0\Synchronization Service\Bin\miiserver.exe
Faulting module path: C:\Windows\WinSxS\amd64_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.6871_none_08e717a5a83adddf\MSVCR90.dll

Посмотрев ULS нашел следующее:
UserProfileApplication.SynchronizeMIIS: Failed to configure MIIS post database, will attempt during next rerun. Exception: System.Runtime.InteropServices.SEHException (0x80004005): External component has thrown an exception.
at Microsoft.Office.Server.UserProfiles.Synchronization.ILMPostSetupConfiguration.ConfigureMiisStage2()
at Microsoft.Office.Server.Administration.UserProfileApplication.SetupSynchronizationService(ProfileSynchronizationServiceInstance profileSyncInstance)

Запустив PowerShell я увидел текст:
Microsoft.SharePoint.WorkflowServices.WorkflowServiceApplicationProxy' from assembly 'Microsoft.SharePoint.WorkflowServices, Version=.....

Поблема возникала при запуске службы Forefront Identity Manager Synchronization Service через Central Administration, в этот момент происходит настройка конфигурации и обращение в SQL базам средствами PowerShell в этот момент происходила ошибка.

Решение:



После установки обновления не было проблем при запуске службы Forefront Identity Manager Synchronization Service и при запуске PowerShell не было лишнего текста.





четверг, 15 января 2015 г.

Дни рождения пользователей - SharePoint 2013 (Part 3)

В продолжение статей про выведение дней рождение пользователей с помощью веб-части поиска людей сегодня я расскажу, как сортировать результаты и как заменить текст при отсутствии результатов.
предыдущие статьи:

Дни рождения пользователей - SharePoint 2013 (Part 2)

В продолжении статьи Дни рождения пользователей - SharePoint 2013 (Part 1) я сегодня расскажу, как вывести дату рождения в веб-часть.