Администрирование
10
Сен
8

PowerShell и MS CRM

PowerShell Microsoft — оболочка командной строки и язык сценариев, cпроектированный для системного администрирования и автоматизации работы (в основном сисадминской). Его потенциальные преимущества для разработчиков и администраторов CRM бесконечны. Так как PowerShell может использовать .NET сборки и веб-службы, он может работать с CRM, чтобы автоматизировать любые (на вскидку) задачи администрирования или любой другой тип стандартных или рутинных задач.

А теперь пару примеров…

Экспорт CRM кастомизации

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

Требования:

  1. NET Framework 2.0 SDK;
  2. Запуск из под акаунта имеющего права на экспорт кастомизации из CRM.

Выполните следующие шаги:

  • Создайте файл Exporter.ps1 и поместите в него следующий скрипт (измените в нем название CRM-сервера, название организации, путь выгрузки и если хотите префокс выгружаемого файла):
    ## Измените эти переменные в соответствии с Вашими настройками
    $targetDir = "c:\customizations\"
    $filePrefix = "customizations_all_"
    $crmOrgName = "superfirma"
    $crmServiceUrl = "http://crm2008/mscrmservices/2007/crmservice.asmx"
    $wsdlLocation = "$crmServiceUrl" + "?wsdl&uniquename=$crmOrgName"
    $crmServiceUrl = "$crmServiceUrl" + "?uniquename=$crmOrgName"
     
    write-host $wsdlLocation
     
    ## Открываем WSDL
    [void] [Reflection.Assembly]::LoadWithPartialName("System.Web.Services")
    $wc = New-Object System.Net.WebClient
    $wc.UseDefaultCredentials = $true
    $wsdlStream = $wc.OpenRead($wsdlLocation)
    $serviceDescription = [Web.Services.Description.ServiceDescription]::Read($wsdlStream)
    $wsdlStream.Close()
     
    ## Импортируем web сервис в CodeDom
    $serviceNamespace = New-Object System.CodeDom.CodeNamespace
    $codeCompileUnit = New-Object System.CodeDom.CodeCompileUnit
    $serviceDescriptionImporter = New-Object Web.Services.Description.ServiceDescriptionImporter
    $serviceDescriptionImporter.AddServiceDescription($serviceDescription, $null, $null)
    [void] $codeCompileUnit.Namespaces.Add($serviceNamespace)
    [void] $serviceDescriptionImporter.Import($serviceNamespace, $codeCompileUnit)
     
    ## генерируем код из CodeDom в строку.
    $generatedCode = New-Object Text.StringBuilder
    $stringWriter = New-Object IO.StringWriter $generatedCode
    $provider = New-Object Microsoft.CSharp.CSharpCodeProvider
    $provider.GenerateCodeFromCompileUnit($codeCompileUnit, $stringWriter, $null)
     
    ## Компилируем исходный код
    $references = @("System.dll", "System.Web.Services.dll", "System.Xml.dll")
    $compilerParameters = New-Object System.CodeDom.Compiler.CompilerParameters
    $compilerParameters.ReferencedAssemblies.AddRange($references)
    $compilerParameters.GenerateInMemory = $true
    $compilerResults = $provider.CompileAssemblyFromSource($compilerParameters, $generatedCode)
     
    ## Получаем сборку которую мы только что скомпилировали
    $assembly = $compilerResults.CompiledAssembly
     
    ## Создаем инстанс CrmService
    $type = "CrmService"
    $instance = $assembly.CreateInstance($type)
     
    ## Задаем параметры инстанса
    $instance.UseDefaultCredentials = $true
    $token = new-object CrmAuthenticationToken 
    $tokenAuthenticationType=0 
    $Token.OrganizationName = $crmOrgName
    $instance.Url = $crmServiceUrl
    $instance.CrmAuthenticationTokenValue = $token 
    $CrmCredentials = [System.Net.CredentialCache].DefaultCredentials 
     
    ## Выполняем запрос на экспорт кастомизации
    $request = new-object "ExportAllXmlRequest"
    $response = $instance.Execute($request) -as [ExportAllXmlResponse]
    $responseXml = new-object XML
    $responseXml.LoadXml($response.ExportXml)
     
    ## Записываем экспортируемый XML-файл с кастомизацией и добавляем к нему окончание с текущей датой
    $date = (get-date).ToString('yyyyMMdd_HHmmss')
    $xmlfile = "$targetDir$filePrefix$date.xml"
    $responseXml.Save("$xmlfile")
     
    ## Если предыдущий экспортированный файл имеет тот же размер, что и только что созданный – удаляем предыдущую версию
    $XmlFiles = Get-ChildItem "$targetDir*.xml" | Sort-Object -Descending
    if ($XmlFiles.count -gt 1)
    {
     $previousXmlFile = $XmlFiles[1]
     $previousXmlFileSize = (Get-Item $previousXmlFile).length
     write-host $previousXmlFileSize
     if ($previousXmlFileSize -eq (Get-Item $xmlfile).length) { Remove-Item $previousXmlFile }
    }
    
  • В командной строке напишите powershell, откроется консоль для ввода команд;
  • Изменим политику PowerShell так, чтобы было разрешено выполнение не подписанных сценариев. Для этого нужно ввести следующий код:
    Set-ExecutionPolicy –executionPolicy Unrestricted
  • Теперь можно выполнять сам скрипт сохраненный в файле. Для этого введите полный путь к файлу Exporter.ps1. В данном случае:
    C:\Exporter.ps1
  • В папке, которую Вы указали для выгрузки в скрипте создасться xml-файл со всей CRM’ной кастомизацией (можете попробовать загрузить ее обратно в CRM 🙂 ).



Созание записи в CRM

Теперь попробуем использовать PowerShell для создания записи Контакт в MS CRM. На этот раз воспольpetvcz стандартной оболочкой CMВ для запуска Powershell и передачи ему файла со скриптом.

  • Создайте файл contact.ps1 и запишите в него следующий скрипт:
     ## Измените эти переменные в соответствии с Вашими настройками
    $targetDir = "c:\customizations\"
    $filePrefix = "customizations_all_"
    $crmOrgName = "superfirma"
    $crmServiceUrl = "http://crm2008/mscrmservices/2007/crmservice.asmx"
    $wsdlLocation = "$crmServiceUrl" + "?wsdl&uniquename=$crmOrgName"
    $crmServiceUrl = "$crmServiceUrl" + "?uniquename=$crmOrgName"
     
    write-host $wsdlLocation
     
    ## Открываем WSDL
    [void] [Reflection.Assembly]::LoadWithPartialName("System.Web.Services")
    $wc = New-Object System.Net.WebClient
    $wc.UseDefaultCredentials = $true
    $wsdlStream = $wc.OpenRead($wsdlLocation)
    $serviceDescription = [Web.Services.Description.ServiceDescription]::Read($wsdlStream)
    $wsdlStream.Close()
     
    ## Импортируем web сервис в CodeDom
    $serviceNamespace = New-Object System.CodeDom.CodeNamespace
    $codeCompileUnit = New-Object System.CodeDom.CodeCompileUnit
    $serviceDescriptionImporter = New-Object Web.Services.Description.ServiceDescriptionImporter
    $serviceDescriptionImporter.AddServiceDescription($serviceDescription, $null, $null)
    [void] $codeCompileUnit.Namespaces.Add($serviceNamespace)
    [void] $serviceDescriptionImporter.Import($serviceNamespace, $codeCompileUnit)
     
    ## генерируем код из CodeDom в строку.
    $generatedCode = New-Object Text.StringBuilder
    $stringWriter = New-Object IO.StringWriter $generatedCode
    $provider = New-Object Microsoft.CSharp.CSharpCodeProvider
    $provider.GenerateCodeFromCompileUnit($codeCompileUnit, $stringWriter, $null)
     
    ## Компилируем исходный код
    $references = @("System.dll", "System.Web.Services.dll", "System.Xml.dll")
    $compilerParameters = New-Object System.CodeDom.Compiler.CompilerParameters
    $compilerParameters.ReferencedAssemblies.AddRange($references)
    $compilerParameters.GenerateInMemory = $true
    $compilerResults = $provider.CompileAssemblyFromSource($compilerParameters, $generatedCode)
     
    ## Получаем сборку которую мы только что скомпилировали
    $assembly = $compilerResults.CompiledAssembly
     
    ## Создаем инстанс CrmService
    $type = "CrmService"
    $instance = $assembly.CreateInstance($type)
     
    ## Задаем параметры инстанса
    $instance.UseDefaultCredentials = $true
    $token = new-object CrmAuthenticationToken 
    $tokenAuthenticationType=0 
    $Token.OrganizationName = $crmOrgName
    $instance.Url = $crmServiceUrl
    $instance.CrmAuthenticationTokenValue = $token 
    $CrmCredentials = [System.Net.CredentialCache].DefaultCredentials 
    
    $contact = new-object "contact"
    $contact.lastname = "Smith" 
    $id = $instance.Create($contact)
    
  • Запустите оболочку CMD;
  • Введите команду:
    powershell.exe "C:\contact.ps1"

    Измените путь у файлу если он у Вас отличается.
    Этой командой мы запускаем оболочку Powershell и передаем ей наш файл со скриптом;

  • Откройте CRM и посмотрите на созданную запись контакта!



Выполнение скриптов по расписанию

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

  • Создайте новую задачу;
  • В качестве приложения для запуска укажите Powershell, а в качестве параметров запуска «& C:\Exporter.ps1» (измените путь к файлу если он у Вас отличается);
  • Задайте расписание запуска задания (в примере я установил запуск на каждые пять минут);
  • Все 🙂 ждите пока оно сработает 🙂



Комментарии (8)
  • Pavel 10.09.2009

    выполнял запрос от пользователя с правами системного админа и получил такой ответ

    Exception calling «Execute» with «1» argument(s): «The request failed with HTTP
    status 401: Unauthorized.»
    At C:\odc\scripts\export_cust.ps1:58 char:30
    + $response = $instance.Execute( <<<< $request) -as [ExportAllXmlResponse]
    Exception calling "LoadXml" with "1" argument(s): "Root element is missing."
    At C:\odc\scripts\export_cust.ps1:60 char:21
    + $responseXml.LoadXml( <<<< $response.ExportXml)
    Exception calling "Save" with "1" argument(s): "Invalid XML document, The docum
    ent does not have a root element.."
    At C:\odc\scripts\export_cust.ps1:65 char:18
    + $responseXml.Save( <<<< "$xmlfile")

  • slivka_83 10.09.2009

    Если Вы делали этот запрос с помощью PowerShell, то я не большой специалист в нем 🙂

  • Дмитрий 10.09.2009

    Добрый день!

    подскажите пож-та, по какой причине действие вложить файл (например в организации или заказе) может вываливаться с ошибкой? срм поставлен с нуля, при установке были выкачаны все обновления.

    за ранее признателен за помощь!

  • slivka_83 10.09.2009

    Боюсь без логов я не смогу ничего сказать 🙂

    Ролапы ставили?

  • Дмитрий 10.09.2009

    поставил 14 ролап — теперь все окей.
    странно, ведь при установке я выбрал скачать все обновления, предполагается что он автоматом должен был поставить их.

  • slivka_83 10.09.2009

    При установке скачиваются только хотфиксы необходимые для самой прграммы установщика! 🙂 А обновления в CRM 4 для самого приложения накатываюся только ролапами 🙂

  • cathy 10.09.2009

    Коллеги, пробовал ли кто составить систему тестирования при помощи powershell’ных скриптов? Насколько это может быть оправдано?
    У меня почти все объекты кастомные, много скриптов и workflow. Зачастую чтобы протестировать какой-нибудь плагин надо провернуть в системе с десятка полтора действий, притом не один раз. Хотелось бы как-то упростить процесс. Поделитесь, пожалуйста, идеями:)
    Спасибо за ответы!

  • slivka_83 10.09.2009

    Добрый день 🙂 а причем тут powershell 🙂 Можно использовать что-то вроде этого: http://www.automatedqa.com/products/testcomplete/

*

code