Сложные сценарии оповещения пользователей в SCSM

Из консоли SCSM мы можем настраивать рабочие процессы, которые будут реагировать на изменение свойств объекта. Такие рабочие процессы могут быть использованы для рассылки уведомлений при смене статуса, при изменении описания и так далее. У этого подхода есть один недостаток – мы не можем подписываться на изменение type projection, т.е. когда один объект связывается с другим. Примером таких свойств могут служить поля “Назначено на”, “Затронутый пользователь” (и вообще все поля типа “Пользователь или Группа”), а также “Затронутые услуги”, “Затронутые элементы” и т.д. При этом SCSM имеет встроенные механизм реагирования на такие события. Также мы не можем настраивать сложные условия для рассылки. О том, как задействовать оба этих механизма и пойдет речь в этой статье.

Продолжить чтение этой записи

Использование Type Projection

Я уже писал ранее о Type Projection, но то была больше теоритическая статья, сегодня я постарасюь привести примеры использования Type Projection. Напомню, что Type Projection позволяет манипулировать одновременно с базовым объектом, и объектами которые с ним связаны каким-либо отношением. Например, инцидент и затронутый пользователь, пользователь и настройки его почты, компьютер и его программное обеспечение.

Продолжить чтение этой записи

Type Projection в SCSM

Если вы захотите создавать объекты в SCSM с помощью кода или скриптов, рано или поздно (скорее всего рано) вы столкнетесь с таким понятием как Type Projection. В данной статье я попытаюсь разъяcнить, что же это такое, для чего нужно и как его можно использовать, но я не буду рассматривать создание собственных Type Projection.

Продолжить чтение этой записи

Stsadm vs Sharepoint Powershell cmdlet

Как известно, Microsoft активно продвигает Powershell, и старается использовать его в каждом своем продукте. Не исключением стала и очередная версия Sharepoint 2010. В данной статье я хотел бы поделиться своими соображениями на счет того, почему Powershell это наше всё, и почему следует активно отказывать от stsadm при работе с Sharepoint 2010.

С каждой последующей версией любой серьезный программный продукт обрастает функциональностью, и, как следствие, требует всё больше и больше системных ресурсов. В Sharepoint количество таких изменений и нововведений просто огромно. Поэтому требования к аппаратному обеспечению (особенно к памяти) выросли. Но этот вопрос должен больше волновать администраторов. Что же до разработчиков, то для них это вылилось в заметное удлинение процесса деплоя и отладки. stsadm – это .NET приложение, и ему свойственны все “болячки” таких приложений, связанные с производительностью. Только усугубляет ситуацию “модульность” stsadm.

Перейдем сразу к примеру. Думаю многим разработчикам, да и администраторам, знакома вот такая последовательность:

spsadm -o deactivatefeature -id 3bd1ede7-cfa3-45a7-b19e-70ae69a50db6 -url %TargetWebUrl% –force 
spsadm -o uninstallfeature -id 3bd1ede7-cfa3-45a7-b19e-70ae69a50db6 -force
echo Deactivating feature ...
spsadm -o deactivatefeature -id e240c347-7fd4-4ef8-9f57-424664e53e01 -url %TargetWebUrl% -force
echo Uninstalling feature ...
spsadm -o uninstallfeature -id e240c347-7fd4-4ef8-9f57-424664e53e01 -force
echo Retracting solution %PackageName% ...
spsadm -o retractsolution -name "%PackageName%" -local -url %TargetWebUrl%
echo Deleting solution %PackageName% from SharePoint ...
spsadm -o deletesolution -name "%PackageName%"

echo Adding solution %PackageName% to SharePoint ...
spsadm -o addsolution -filename "%PackageFile%"
echo Deploying solution %PackageName% ...
spsadm -o deploysolution -name "%PackageName%" -local -allowGacDeployment -url %TargetWebUrl%
echo Activating feature ...
spsadm -o activatefeature -id 3bd1ede7-cfa3-45a7-b19e-70ae69a50db6 -url %TargetWebUrl%
echo Activating feature ...
spsadm -o activatefeature -id e240c347-7fd4-4ef8-9f57-424664e53e01 -url %TargetWebUrl%

Стандартный скрипт для установки решения в Sharepoint, часто применяется для установки решений в продуктовой среде. Когда я запустил подобный скрипт для установки решения из нескольких рабочих процессов и пары-тройки фич на сервере под управлением Sharepoint 2010, то выполнение этого скрипта заняло у меня… 15 минут. Скрипт и сервер были те же самые, которые использовались для Sharepoint 2007, и на нем выполнение занимало 6-7 минут. Даже после добавления памяти на сервер время удалось уменьшить всего на 2-3 минуты.
 
Ждать столько времени желания не было никакого, особенно если учесть, что из Visual Studio такой же деплой идет за минуту-две. И тогда появилась идея попробовать переписать эту же последовательность на Powershell с применением командлет от Sharepoint 2010. Когда работа была закончена, результат превзошел все ожидания – вместо 12-15 минут те же самые действия в Powershell выполнялись за пару минут!!!! Кроме этого, благодаря Powershell, в скрипт были добавлены действия по открытию сайта (т.к. первое открытие занимает довольно ощутимое время), а также включение рабочих процессов в списках.
 
Для примера привожу тот же самый кусок скрипта, что и выше, но уже на Powershell:
Disable-SPFeature -Identity "3bd1ede7-cfa3-45a7-b19e-70ae69a50db6" -url $TargetWebUrl -Confirm:$false 
Uninstall-SPFeature -Identity "3bd1ede7-cfa3-45a7-b19e-70ae69a50db6" -Confirm:$false
write-host Deactivating feature ...
Disable-SPFeature -Identity "e240c347-7fd4-4ef8-9f57-424664e53e01" -url $TargetWebUrl -Confirm:$false 
write-host Uninstalling feature ...
Uninstall-SPFeature -Identity "e240c347-7fd4-4ef8-9f57-424664e53e01" -Confirm:$false 
write-host Retracting solution $PackageName ...
Uninstall-SPSolution -Identity $PackageName -local -Confirm:$false 
write-host Deleting solution $PackageName from SharePoint ...
Remove-SPSolution -Identity $PackageName  -Confirm:$false
 
write-host Adding solution $PackageName to SharePoint ...
Add-SPSolution -LiteralPath $PackageFile -Confirm:$false
write-host Deploying solution $PackageName ...
Install-SPSolution -Identity $PackageName  -local -GACDeployment -Confirm:$false
write-host Activating feature ...
Enable-SPFeature -Identity "3bd1ede7-cfa3-45a7-b19e-70ae69a50db6" -url $TargetWebUrl -Confirm:$false
write-host Activating feature ...
Enable-SPFeature -Identity "e240c347-7fd4-4ef8-9f57-424664e53e01" -url $TargetWebUrl -Confirm:$false
 
Надеюсь эта информация поможет вам принять решения, и начать использовать Powershell в своей повседневной работе.
 
PS Это мой последний про Sharepoint. В связи со сменой работы, у меня несколько сместился акцент деятельность. Теперь я буду плотно заниматься продуктами из линейки System Center, в частности Operations Manager, Configurations Manager и Service Manager.

Sharepoint и FBA: создание пользователей из PowerShell. Часть 2

Этап второй. Включение пользователя в Sharepoint.

На этом “грабли” FBA не заканчиваются, а только начинаются. Для того. чтобы включить пользователя в Sharepoint, необходимо выполнить два действия:

  1. Вызвать метод класса SPWeb EnsureUser(string login)
  2. Добавить пользователя в какую-нибудь группу.

Проблемы у вас начнутся, как только вы попытаетесь подключиться к сайту Sharepoint с включенным FBA — API не обладает средствами авторизации для работы с Sharepoint с помощью FBA. И если вы просто подключитесь к сайту и вызовите метод EnsureUser, вы получите ошибку “Exception calling "EnsureUser" with "1" argument(s): "Attempted to perform an unauthorized operation."”. И вот тут начинается магия .NET и API Sharepoint. Решение с HttpContext я честно подсмотрел в инете. Подключение к сайту Sharepoint с включенным FBA будет работать вот так и только так:

   1: [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Sharepoint") | Out-Null
   2:  
   3: [Microsoft.Sharepoint.SPSecurity]::RunWithElevatedPrivileges({ 
   4:  
   5: [Microsoft.Sharepoint.SPSite]$site = new-object Microsoft.Sharepoint.SPSite("http://fbasite")
   6: [Microsoft.Sharepoint.SPWeb]$web = $site.RootWeb
   7: if($web)
   8: {
   9:     $web.AllowUnsafeUpdates = $True
  10:     if (![System.Web.HttpContext]::Current)
  11:     {
  12:         $request = new-object System.Web.HttpRequest("", $web.Url, "");
  13:         $writer = new-object System.IO.StringWriter
  14:         $response = new-object System.Web.HttpResponse($writer)
  15:         [System.Web.HttpContext]::Current = new-object System.Web.HttpContext($request, $response);
  16:         [System.Web.HttpContext]::Current.Items["HttpHandlerSPWeb"] = $web;
  17:     }
  18:  
  19:     [string]$fullName = "Иванов иван Иванович"
  20:     [string]$username = "CustomSQLMembershipProvider:TestLogin"
  21:         
  22:     [Microsoft.Sharepoint.SPUser]$curUser = $web.EnsureUser($username);
  23:  
  24:     if ($curUser)
  25:     {
  26:        $curUser.Name = $fullName;
  27:        $curUser.Update();
  28:        $web.SiteGroups["Посетители"].AddUser($curUser);
  29:     }
  30:     
  31:     $web.AllowUnsafeUpdates = $False
  32:     
  33:     $web.Dispose()
  34:     $site.Dispose()
  35: }
  36: })

Обратите внимание на строки 10-17 – тут  мы создаем текущий контекст для работы с FBA, иначе вызов метода UnsureUser вызовет ошибку. Кроме этого, весь код работы с API Sharepoint выполнен внутри метода  RunWithElevatedPrivileges – это необходимо даже в том случае, если вы работаете из под учетной записи администратора фермы Sharepoint. Кроме того, обратите внимание в каком виде необходимо передавать логин методу UnsureUser – с обязательным указанием имени провайдера.

Замечание: Еще одним способом является создание альтернативного узла IIS, который затем будет включен в SharePoint и настроен на тот же сайт, что и узел с FBA. В этом случае вы можете подключаться к этому альтернативному узлу по средствам Windows-аутентификации, но такая настройка мягко скажем не тривиальна.

В итоге у меня получился вот такой скриптик, который выполняет все необходимые действия по добавлению пользователей в Sharepoint с включенным FBA:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Sharepoint") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null
#====================================================================================
function Get-MembershipProvider([string]$ProviderName)
{
if($ProviderName)
{
#Находим провайдер по имени
return [System.Web.Security.Membership]::Providers[$ProviderName]
}
else
{
#Если имя не было указано, возвращаем провайдер по умолчанию
return [System.Web.Security.Membership]::Provider
}
}
#====================================================================================
function Create-ProviderUser($login, $password, $mail)
{
#проверяем, "подан ли на вход" провайдер
$provider = $input | select -First 1
if($provider -isnot [System.Web.Security.MembershipProvider])
{
$provider = Get-MembershipProvider
}

$status = 0
$question = "q"
$answer = "a"
$approved = $True
$retStatus = 0
$newUser = $provider.CreateUser($login, $password, $mail, $question, $answer, $approved, $null, [ref]$retStatus)
write-host "Статус создания пользвоателя а MembershipProvider: $retStatus"

return [System.Web.Security.MembershipUser]$newUser
}
#====================================================================================
function Create-SharepointUser([string]$SiteUrl,[System.Web.Security.MembershipUser]$User, [string]$FullName, [string]$GroupName)
{
[Microsoft.Sharepoint.SPSecurity]::RunWithElevatedPrivileges({
[Microsoft.Sharepoint.SPSite]$site = new-object Microsoft.Sharepoint.SPSite($SiteUrl)
[Microsoft.Sharepoint.SPWeb]$web = $site.RootWeb
if($web)
{
$web.AllowUnsafeUpdates = $True
if (![System.Web.HttpContext]::Current)
{
$request = new-object System.Web.HttpRequest("", $web.Url, "");
$writer = new-object System.IO.StringWriter
$response = new-object System.Web.HttpResponse($writer)
[System.Web.HttpContext]::Current = new-object System.Web.HttpContext($request, $response);
[System.Web.HttpContext]::Current.Items["HttpHandlerSPWeb"] = $web;
}

[Microsoft.Sharepoint.SPUser]$curUser = $web.EnsureUser($User.UserName);
if ($curUser -is [Microsoft.Sharepoint.SPUser])
{
$curUser.Name = $FullName
#После вызова метода Update может выскочить ошибка "Unable to cast object of type 'System.Management.Automation.PSObject' to type 'Microsoft.SharePoint.SPWeb'."
#При этом всё работает. Причину и решение я не нашел.
try{ $curUser.Update();}catch{}
[Microsoft.Sharepoint.SPGroup]$group = $web.SiteGroups[$GroupName]
$group.AddUser($curUser)
}

$web.AllowUnsafeUpdates = $False

$web.Dispose()
$site.Dispose()
}
})
}
#====================================================================================

#собственно код создания
$provider = Get-MembershipProvider "AtlantisSQLMembershipProvider"
$login = "TestLogin2"
$password = "!@#_s123QWE"
$email = "my@mail.local"
$user = $provider | Create-ProviderUser $login $password $email

if($user)
{
Create-SharepointUser http://fbasite $user "Иванов Иван Иванович" "Посетители"
}

Sharepoint и FBA: создание пользователей из PowerShell. Часть 1

Я уже давно работаю с Sharepoint, приличное время с PowerShell. И вот недавно мне поставили задачу – перевести функционал сайта, сделанного в 1С:Битрикс на WSS. Всё было просто, пока мы не дошли до стадии создания логинов на сайте.

Т.к. сайт предназначался для доступа из вне, естественным было использовать FBA в Sharepoint – Form Based Authentication. Встала необходимость создать порядка 50 пользователей, список которых был выгружен из 1С:Битрикс. Создание пользователей для Sharepoint  в обычной среде (с доменом и авторизацией в AD)  проблемой не является. Но, как оказалось, с FBA всё сильно сложнее.

Я не буду останавливаться на процессе собственно включения FBA в Sharepoint, благо про это написано не одна статья. В итоге у нас должен появиться свой собственный провайдер аутентификации и RoleManagement-а. Итак, процесс создания пользователя в общих чертах выглядит следующих образом:

  1. Создать пользователя в нашем провайдере аутентификации. Для этого нам надо указать логин, пароль, и электронную почту (в зависимости от настроек провайдера может потребоваться также подстановка контрольного вопроса и ответа). После этого пользователь будет создан в БД.
  2. Включить пользователя в Sharepoint, и добавить его в необходимую группу.

Этап первый.

Для создания пользователей в провайдере используется пространство имен [System.Web.Security]. В данном пространстве есть класс [System.Web.Security.MembershipProvider], экземпляры которого содержит в себе несколько методов для работы с пользователями, в том числе метод CreateUser, который нам и нужен.

Собственно код для создания пользователя в провайдере достаточно прост:

   1: [System.Reflection.Assembly]::LoadWithPartialName("System.Web")  | Out-Null
   2: $provider = [System.Web.Security.Membership]::Providers["CustomSqlMembershipProvider"]
   3: $login = "TestLogin"
   4: $password = "Secure1_Password"
   5: $mail = "test@mail.local"
   6: $question = "q"
   7: $answer = "a"
   8: $approved = $true
   9: $provider.CreateUser($login, $password, $mail, $question, $answer, $approved, $null, [ref]$status)

На вид – ничего сложного. Но когда вы запустите этот код, ваш созданный ранее провайдер не будет найден. Дело всё в том, что пространство имен [System.Web.Security] рассчитано на то, что все его классы будут использоваться внутри веб-сервера, и как следствие иметь доступ к настройках текущего узла. Точно также работает и класс [System.Web.Security.MembershipProvider] – вызов свойства [System.Web.Security.MembershipProvider]::Providers в свою очередь вызывает внутренние методы, которые обращаются к файлу настроек веб-сервера (а точнее, что важно как вы увидите потом – к файлу настроек приложения веб-вервера). Все настройки веб-севрера IIS хранятся в файле c:\Windows\Microsoft.NET\Framework64\v2.0.50727\CONFIG\web.config. Там же, в секции <configuration><roleManager> хранится и созданный провайдер. Логично, PowerShell вообще ничего не знает об этом файле настроек и не умеет его использовать.

Вот тут проявляется вся сила и простота .NET Framework. Всё, что нам нужно сделать – создать файл настроек (.config) для PowerShell. Для этого достаточно каталоге с файлом powershell.exe (или powershell_ise.exe, в зависимости от того, чем вы пользуетесь) создать одноименный файл powershell.config и\или powershell_ise.config со следующим шаблоном:

   1: <?xml version ="1.0"?>
   2: <configuration>
   3:   <system.web>
   4:   </system.web>
   5: </configuration>

После этого внутрь секции syste.web скопировать секции <roleManager> и <membership> из web.config, а также вставить после секции </system.web> секцию <connectionStrings> из того же web.config. В итоге у вас должно получиться примерно следующее:

   1: <?xml version ="1.0"?>
   2: <configuration>
   3:  <system.web>
   4:   <roleManager>
   5:    <providers>
   6:     <add name="CustomSqlRoleprovider" type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" applicationName="/" connectionStringName="LocalSqlServer" />
   7:    </providers>
   8:   </roleManager>
   9:   <membership>
  10:     <providers>
  11:       <add name="CustomSQLMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" applicationName="/" connectionStringName="LocalSqlServer" enablePasswordReset="true" enablePasswordRetrieval="false" passwordFormat="Hashed" requiresQuestionAndAnswer="false" requiresUniqueEmail="true" minRequiredNonalphanumericCharacters="1" minRequiredPasswordLength="8" />
  12:     </providers>
  13:   </membership>
  14:  </system.web>
  15:  <connectionStrings>
  16:    <remove name="LocalSqlServer" />
  17:    <add connectionString="Server=localhost;Database=FormAuthDB;Integrated Security=true" name="LocalSqlServer" providerName="System.Data.SqlClient" />
  18:  </connectionStrings>
  19: </configuration>

После этого, если вы запустите тот же самый скрипт – он должен отработать корректно.

Powershell v2 и Sharepoint: скриптописание или программирование для администраторов. Часть 2.

В предыдущей статье мы рассмотрели общие аспекты использования Powershell и Sharepoint, сейчас мы подробно разберем события элементов списков и события списков.

ListItemEventReceivers и ListEventReceivers

Для всех библиотек и списков в Sharepoint предусмотрен ряд обработчиков событий, часть которых отвечают за события непосредственно списка (изменение свойств, добавление столбцов и т.д.), а часть за события элементов (создание, изменение, удалении и т.д.).

В общем случае, для того, чтобы обрабатывать эти события необходимо создать класс, наследованный от SPItemEventProperties, и реализовать в нем нужные методы. После этого класс необходимо зарегистрировать в Sharepoint с помощью Feature или с помощью сторонних инструментов. Но т.к. C#, компиляция и прочие страшные слова – это не то, что нам сейчас нужно, мы посмотрим что же можно сделать с этими событиями с помощью Powershell.

На помощь нам придет замечательная Feature PowerEventReceivers из пакета iLoveSharepoint. Данная Feature добавляет в каждый список или библиотеку документов возможность вставлять обработчики событий на скриптах Powershell.

Тут следует отвлечься, и немного рассказать о некоторых аспектах безопасности, связанных с событиями. Все обработчики событий в списках и элементах списков выполняются от имени того пользователя, который инициировал изменения. В связи с этим и скрипты Powershell будут выполняться от имени этих пользователей, а пользователю необходимы права на выполнения скриптов на сервере, где установлена front-end MOSS\WSS. В противном случае вы получите ошибку “Requested registry access is not allowed”. Решить эту проблему можно, используя метод SPSecurity.RunWithElevatedPrivileges в WSS\Sahrepoint. Благодаря ему все вызовы будут происходить с привелегиями Системной учетной записи (от которой запущен пул приложений IIS). Но при этом нужно понимать, что ВСЕ скрипты в обработчиках будут запускаться от имени этой учетной записи, и с помощью неё можно наделать не мало бед. Подробно аспекты безопасности будут рассмотрены в конце цикла статей.

Какой из методов использовать – решать вам. Я создал PowerEventReceivers, который выполняется с повышенными привилегиями. Вы можете использовать его или оригинальный.

Установка крайне проста – запустите deploy.bat на сервере Sharepoint, затем активируйте эту Feature на нужном узле (и только на нужном, по соображениям безопасности и производительности):

image

После активации будут доступны два новых пункта в свойствах списков и библиотеках документов:

image

Смысл их понятен из названия, первый отвечает на обработку событий элемента, второй – за обработку событий списка (или библиотеки). Приведу полностью доступные обработчики элемента списка:

ItemAdding Во время добавления элемента
ItemUpdating Во время изменения элемента
ItemDeleting Во время удаления элемента
ItemCheckingIn Во время возврата документа
ItemCheckingOut Во время извлечения документа
ItemUncheckingOut Во время отмены извлечения документа
ItemAttachmentAdding Во время добавления вложения
ItemAttachmentDeleting Во время удаления вложения
ItemFileMoving Во время перемещения файла
ItemAdded После добавления элемента
ItemUpdated После изменения элемента
ItemDeleted После удаления элемента
ItemCheckedIn После возврата документа
ItemCheckedOut После извлечения документа
ItemUncheckedOut После отмены извлечения документа
ItemAttachmentAdded После добавления вложения
ItemAttachmentDeleted После удаления вложения
ItemFileMoved После перемещения файла
ItemFileConverted После конвертации файла (MOSS)
ContextEvent “Ручной” вызов события

и события списка (библиотеки):

FieldAdded После добавления столбца
FieldAdding Во время добавления столбца
FieldDeleted После удаления столбца
FieldDeleting Во время удаления столбца
FieldUpdated После изменения столбца
FieldUpdating Во время изменения столбца

Все обработчики с постфиксом –ing являются синхронными, то есть выполняются одновременно с действием, их породивших. Это позволяет влиять на событие вплоть до его отмены.

Для редактирования доступно как обычное текстовое поле прямо на веб-странице, так и специальный ActiveX для интеграции PowerEventreceivers с редактором PowerGUI. ActiveX доступен на официальном сайте.

Давайте посмотрим, что мы можем сделать с помощью этих обработчиков событий и Powershell (также несколько примеров доступно на страничке PowerEventReceivers).

1. Проверка значений перед вставкой элемента:

    1 function ItemAdding

    2 {

    3     [int]$curVal = $properties.AfterProperties["Title"]

    4     if ($curVal -ge 8)

    5     {

    6         $properties.Cancel = $true

    7         $properties.ErrorMessage = "Нельзя указывать значения поля Название больше или равное 8. Вы указали $curVal"

    8     }

    9 }

Обратите внимание на приведения типов в строке 3. Столбец Название (Title) на самом деле имеет тип “строка”, но это Powershell. Тут мы можем делать и вот так.

Если пользователь ввел значение больше или равное 8, то элемент не будет создан, а ему будет выдана вот такая красивая ошибка:

image

2. Оценка поля до изменения и после, вставка разницы в другой столбец. Мы будем использовать ItemUpdating для получения изменений, т.к. только в нем доступны как свойства до изменения, так и после. Кроме этого мы будем использовать ItemUpdated для фиксации изменений в поле, т.к. вызов метода Update в ItemUpdating приведет к конфликту сохранений:

    1 function ItemUpdating

    2 {

    3     $oldVal = $item["Title"]

    4     $newVal = $properties.AfterProperties["Title"]

    5     $val = "Было $oldVal, а стало $newVal"

    6     $this.DisableEventFiring()

    7     $item.Properties["_Temp"]  = $val

    8     $item.SystemUpdate($False)

    9     $this.EnableEventFiring()

   10 

   11 }

   12 

   13 function ItemUpdated

   14 {

   15     $this.DisableEventFiring()

   16     $item["Field2"] = $item.Properties["_Temp"]

   17     $item.SystemUpdate($False)

   18     $this.EnableEventFiring()

   19 }

Обратите внимание на строки 6, 9, 15 и 18. Методы DisableEventFiring и EnableEventFiring позволяют отключить обработчики событий на время, чтобы у нас не было циклического из вызова из-за изменений в коде.

Также интересна конструкция $item.Properties["_Temp"]  = $val. Свойство Properties позволяет нам записывать любые значения в элемент, которые мы затем можем получить. В основном данное свойство применяется в рабочих процессах (Workflow), но как видно может пригодиться и тут.

Вот результат работы скрипта:

image

3. Создание сложных вычисляемых полей. Данный пример – следствие предыдущего. Формулы в Sharepoint хоть и обширны, но им очень далеко до функционала Powershell. Здесь мы можем применять любые функции, доступные нам в Powershell (и .NET соответственно) для создания вычисляемых полей:

    1 function GetListFromLookupField([string]$InternalFieldName)

    2 {

    3 

    4     $typeField = [Microsoft.SharePoint.SPFieldLookup]$list.Fields.GetFieldByInternalName($InternalFieldName)

    5     $typeListGuid = newobject Guid($typeField.LookupList)

    6     $typeList = $web.Lists[$typeListGuid]

    7     return $typeList

    8 }

    9 

   10 function ItemUpdated

   11 {

   12     $lookupList = GetListFromLookupField("LookupField")

   13 

   14     $this.DisableEventFiring()

   15     $item["LinkField"] = $site.Url + $lookupList.DefaultViewUrl+", Ссылка на список"

   16     $item.SystemUpdate($False)

   17     $this.EnableEventFiring()

   18 }

У нас в списке 2 поля. LookupField – поле типа “Подстановка”, LinkField – поле типа “Гиперссылка”. В результате выполнения в поле LinkField будет записана ссылка на представление по умолчанию списка. из которого берутся данные в поле LookupField. Результат выполнения:

image

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

Отладка.

Хотелось бы сказать пару слов об отладке. Первое, что отмечу – все ошибки выполнения PowerEventReceivers записывают в системный журнал Приложения. Т.е. если у вас что-то не выполнилось – смотрите журнал:

image

Для отладки же и получения значений каких-либо переменных я использую следующую конструкцию:

    1 ($item["Field"] | ConvertTo-XML).Save("d:\FieldValue_"+[datetime]::Now.ToString("HH.mm.ss.FFFFF")+".xml")

Т.е. просто преобразую значение переменной в XML, а затем записываю на диск в виде XML-файла с меткой времени.