Sharepoint: Фильтрация представлений по статусу рабочего процесса

Когда Вы добавляете рабочий процесс (Workflow, далее по тексту — РП) к списку после первого запуска в списке создается поле (столбец), имя которого равно имени РП. В этом поле записывается статус рабочего процесса, а рендерится он в виде имени статуса РП и ссылкой на страницу состояния этого РП.

Крайне полезным бывает создавать представления, в которых список отфильтрован по состоянию РП. Например представление “Завершенные РП”. Но тут могут возникнуть проблемы – если Вы попытаетесь в фильтре выбрать поле РП, а затем указать значение фильтра в “Завершен”, то такой фильтр работать не будет.

Причина тому – тип поля РП. Поле РП имеет тип int (целочисленное), и соответственно хранит в себе цифровое обозначение текущего состояния РП. Стандартные состояния и их значение таковы (см. SPWorkflowStatus Enumeration (Microsoft.SharePoint.Workflow)):

Текстовое значение Числовое значение
Не запущен*  
Ошибка при старте 1
В ходе выполнения 2
Ошибка 3
Отменен 4
Завершен 5
Ошибка при старте. Перезапуск. 6
Ошибка. Перезапуск. 7

*Для не начатых РП значение этого поля – “пусто”, хотя в API используется значение, равное нулю.

Т.е. для того, что отфильтровать данное поле необходимо в фильтре выбрать поле РП, а в значение подставить соответствующее числовое значение.

Эту особенность следует учитывать и при сортировке – не удивляйтесь, что элементы со значением поле равной “Ошибка” идут раньше, чем со значением “Завершен”.

Есть еще одно замечание – при использовании кастомного статуса РП нужно помнить, что новые статусы будут начинаться с 15 (SPWorkflowStatus.Max).

PS Информация актуальна как для WSS3\MOSS2007, так и для Sharepoint Foundation\MOSS2010.

Реклама

Новая версия SCCM Client Check 1.0.0.3

Новая версия тулзы по проверки клиента SCCM
Добавлено:
  • проверка сертификатов компьютера (для Native-режима). Проверяется наличие сертификата на удаленном компьютере, а также его валидность.
  • программу можно использовать из консоли SCCM
Инструкции:
  1. Всё содержимое архива извлечь в одну папку
  2. Поправить в файле SCCMClientCheck.xml путь до SCCMClientCheck.exe (см. тег <FilePath>). Путь может содержать пробелы, кавычки указывать не надо. 
  3. После изменение файл SCCMClientCheck.xml скопировать в папку %PROGRAMFILES%\Microsoft Configuration Manager Console\AdminUI\XmlStorage\Extensions\Actions\7ba8bf44-2344-4035-bdb4-16630291dcf6\ (создать необходимые подпаки при необходимости) на компьютеры, где установлена консоль
  4. Перезапустить консоль, в меню компьютера появится пункт SCCM Client Check

image

Подробнее почитать про внедрение своих команд в меню консоли SCCM можно здесь и здесь

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

Обновление SCCM Client Check

Выложил обновление программы для проверки клиентских компьютеров на предмет работы агента SCCM.

http://cid-9e1589588902dbaa.skydrive.live.com/embedicon.aspx/SCCMClientCheck/SCCMClientCheck_v1.0.0.2.zip

Добавлено:

  • Возможность открыть любой лог с клиента (кнопка open log file)
  • Возможность закрыть вкладку с логом двойным щелчком мыши (аля-Maxthon)

Исправлены баги:

  • время отображалось формате 12h. Теперь отображается в 24h.

Несколько картинок:

image image image

Передача значений из формы InfoPath в задачу рабочего процесса

Я ранее приводил ряд ссылок на описание рабочих процессов с использованием форм InfoPath для задач.
Сегодня я хочу рассказать про одну особенность этих форм.

Все мы знаем, что поменять свойства задачи в РП, который написан в Visual Studio, не так просто, как кажется. Надо вставлять активити UpdateTask, заполнять его свойства и т.д.
При использовании форм InfoPath для редактирования задач РП у нас есть еще одна возможность — передавать значения элемента задачи прямо из формы редактирования задачи. Как Вы уже знаете, мы можем получать значения из элемента задачи, указав дополнительный источник данных в форме InfoPath с именем ItemMetadata, перечислив нем все столбцы с приставкой ows_. Для того, чтобы передать данные обратно в элемент задачи, нам достаточно в основном источнике данных создать поля, которые должны называться точно также, как и поля в элементе задачи.
В момент, когда мы делаем Submit на форме InfoPath, значение полей из формы будет записано в элемент задачи.
Для примера возьмем Срок (DueDate).

  1. Создадим в форме, в основной источнике данных поле DueDate, указав тип DateTime.
  2. Добавим на форму DateTimePicker, ассоциировав его с полем DueDate
  3. Добавим кнопку OK, назначив ей одно правило, которое делает Submit нашей формы.
  4. Создадим простой РП, который создает задачу, укажем созданную нами форму в настройка РП как форму для редактирования задачи.
  5. Запустим РП, откроем задачу для этого РП, введем какую-либо дату в поле и нажмем ОК.
  6. В итоге в свойствах нашей задаче, в поле Срок вы увидите введенное значение из формы.

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

Версии Sharepoint 2007\WSS3

Можно узнать какая версия по номеру какому выпуску Sharepoint\WSS3 соответствует.
Н-р можно узнать, что крайний Октябрьский CU имеет номер версии 12.0.0.6520.

Sharepoint, PowerShell и пара сотен нервных клеток

“Слався Шел, слався Шел” (с)
Перефразированная цитата из фильма MiB

Все мы любим Sharepoint. Он любит нас, но “какой-то своей любовью”. С сегодняшнего дня я еще очень люблю PowerShell. Теперь по порядку.

Как известно, Sharepoint не очень хорошо относится к локализации. А вернее он её ну совсем не любит. Н-р вот такой кусок кода запросто может выдать ошибку:

using (SPSite site = new SPSite("http://localhost"))
{
     using (SPWeb web = site.OpenWeb())
     {
           SPListItem item = web.Lists["Документы"].GetItemById(1);
           object fieldValue = item["МегаПоле"]; //вот тут будет ошибка
     }
}

Всё дело в том, что поля можно получать только по внутреннему имени. А внутреннее имя крайне не любит русские буквы, и заменяет их кодами. Н-р в нашем примере item["МегаПоле"] принимает вид item["_x041c__x0435__x0433__x0430__x04"]. Не очень читаемо. По этой причине все разработчики создают поля с внутренними именами на английском.

Но тут есть еще одна засада. Создали мы столбец, дали ему внутреннее имя “MegaField”, а DisplayName дали ему “МегаПоле”, добавили его в столбцы узла. Но вот нам захотелось добавить это поле в список (или в тип содержимого, не важно). При добавлении из веб-интерфейса в списке создается новый столбец, потомок нашего. А столбцы создаются, используя DisplayName. Т.е. в списке наш столбец опять будет иметь имя "_x041c__x0435__x0433__x0430__x04". Приходится перед добавлением переименовать столбец в его внутреннее имя, добавлять, после чего опять возвращать имя обратно. Но это мелочи. Главное в том, что если вы уже добавили столбец, поменять ему внутреннее имя можно будет только удалив столбец из списка (или из типа содержимого), что означает удаление всех данных этого столбца. Не радостная картина.

Так вот сегодня мне достался худший из таких случаев – в системе документооборота, с несколькими рабочими процессами и EventReceiver-ами, в один из списков было добавлено поле с русским DisplayName. В результате, в части списках поле нужно было получать как item[“StaticFieldName”], а в этом одном – item["_x041c__x0435__x0433__x0430__x04”]. Но весь код, естественно, оперировал только с англоязычными названиями. Хуже всего было то, что это заметили после нескольких месяцев использования, и это поле фигурировало уже в нескольких сотнях записей. Еще одним отягчающим обстоятельством было то, что этот список был библиотекой документов с включенной версионностью и требованием извлечения файлов перед редактирование.

Передо мной была поставлена задача – заменить столбец на англоязычный, при этом не потеряв его содержание. Сервер был боевой, т.е. ни о каких установках дебагеров, а уж тем более VisualStudio, речи просто не велось. И вот тут я вспомнил про PowerShell.

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

  1. Проходим по всему списку, для каждого элемента получаем строку в виде “%ID%|%FieldValue%”, и записываем эти строки в файл.
  2. Удаляем столбец из списка, добавляем его с английским названием
  3. Считываем строку из файла, находим элемент по ID и записываем его свойство
  4. Для каждого элемента вызываем SystemUpdate(false), чтобы сделать обновление без изменения версии (в том числе и в не извлеченных элементах)

В итоге у меня получились вот такие скрипты:

GetValues.ps1

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") | Out-Null

$site = New-Object Microsoft.Sharepoint.SPSite("http://localhost")
$web = $site.OpenWeb("/doccenter")

$web.Lists["Документы"].Items | foreach {
    $val = $_["_x041c_x0435_x0433_x0430_x04"]

    if($val -ne $Null)
    {
    $temp = $_.ID.ToString() + "|" + $_["_x041c_x0435_x0433_x0430_x04"].ToString()
    Write-Output $temp
    }    
}

SetValues.ps1

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") | Out-Null

$site = New-Object Microsoft.Sharepoint.SPSite("http://localhost")
$web = $site.OpenWeb("/doccenter")
$list = $web.Lists["Документы"]

Get-Content dump.txt | foreach {
    $ar = $_.Split("|")
    
    $item = $list.GetItemByID($ar[0])
    $item["StaticFieldNames"] = $ar[1]
    $item.SystemUpdate($False)
}

Порядок работы:

  1. Запускаем скрипт .\GetValues.ps1 | Out-File dump.txt
  2. Проверяем, что значения получены верно
  3. Удаляем столбец
  4. Добавляем его заново, предварительно поменяв DisplayName на английский
  5. Запускаем скрипт .\SetValues.ps1
  6. Проверяем результат (н-р можно заново запустить GetValues, изменив в нем имя столбца – данные на выходе должны совпасть)
  7. Переименовываем столбец обратно

С учетом того, что поле у меня было кастомное, на базе MultiValue, а документов было более 800, я считаю, что отделался легким испугом. За что спасибо PowerShell!

PS Скрипты далеки от идеалов программирования, но с учетом того, что были сделаны за десять минут и, главное, отлично работают, вполне подходят :)