English version

Пример сценария развертывания пакета решений для SharePoint через PowerShell

Как Вы можете знать, существует несколько сценариев развертывания пакетов решений на ферме SharePoint

  1. Развертывание средствами центра администрирования SharePoint
  2. Развертывание средствами командлетов и сценариев PowerShell
    1. Обновление существующего решения, если оно уже развернуто
    2. Отзыв существующего решения и новое развертывание
  3. Развертывание средствами stsadm (устаревшее)

Более подробно об этом можно почитать тут (ссылка приведена на версию Microsoft SharePoint 2010. Существенных изменений по отношению к версии SharePoint 2013 нет): 

Сегодня мы рассмотрим пример одного из самых распространенных сценариев развертывания (через PowerShell с отзывом существующего решения) и возможными трудностями их использования у начинающего программиста или администратора SharePoint.

Командлеты, используемые в данном сценарии:

Add-SPSolution (http://technet.microsoft.com/ru-ru/library/ff607552(v=office.15).aspx) – Добавляет пакет решений на ферму SharePoint

Install-SPSolution (http://technet.microsoft.com/ru-ru/library/ff607534(v=office.15).aspx) – Развертывание добавленное на ферму решение

Uninstall-SPSolution (http://technet.microsoft.com/ru-ru/library/ff607873(v=office.15).aspx) – Отзывает развернутое ранее решение на ферме

Remove-SPSolution (http://technet.microsoft.com/ru-RU/library/ff607748.aspx) – удаляет отозванное ранее решение

Get-SPSolution (http://technet.microsoft.com/ru-RU/library/ff607754.aspx) – Получает и возвращает решение SharePoint для выполнения дальнейших операций

Последовательность выполнения операций должна быть следующей:

  1. Выполняется команда Get-SPSolution для определения наличия требуемого решения и его состояния, если оно добавлено на ферме
  2. Если же решение существует и развернуто, его необходимо отозвать с помощью команды Uninstall-SPSolution
  3. Если же решение существует, его необходимо удалить с фермы с помощью команды Remove-SPSolution
  4. Добавить решение на ферму с помощью команды Add-SPSolution
  5. С помощью команды Get-SPSolution получить добавленное решение и определить область его применения
  6. С помощью команды Install-SPSolution развернуть решение на ферме

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

Например, если последовательно вызвать команды Uninstall-SPSolution и Remove-SPSolution

Uninstall-SPSolution -Identity TestSolution.wsp -AllWebApplications -Confirm:$false

Remove-SPSolution -Identity TestSolution.wsp -Confirm:$false

то на экране может появиться следующее сообщение об ошибке:

Remove-SPSolution : Решение "testsolution.wsp" развернуто в ферме. Отзовите развертывание, прежде чем удалять решение. Для принудительного удаления решения можно также использовать параметр -override, однако это не позволит отозвать развертывание решения.

(Remove-SPSolution : The solution " testsolution.wsp" has been deployed in the farm. Please retract the deployment before removing the solution.You can also use the 
-override parameter to forcibly remove the solution, but you will not be able to retract the solution deployment.)

Если же немного подождать и снова выполнить команду

Remove-SPSolution -Identity TestSolution.wsp -Confirm:$false

Ошибки уже не будет и решение будет отозвано.

Что же происходит на самом деле и как быть в данной ситуации? На самом деле вместо того, чтобы моментально выполнить данную операцию, командлет создает задание (Timer Job) на выполнение данной операции (это неплохо, это дает возможность формировать отложенный отзыв или развертывание) и необходимо каким-то образом определять состояние выполнения данного задания. Для этого служит свойство JobExists у полученного SPSolution через команду Get-SPSolution, которое сообщает о наличии инициированного задания для данного решения. Как только свойство возвращает значение false, решение может быть отозвано.

Если же изначально выполнить следующий код в командной строке PowerShell

function RemoveTestSolution(){
    $Solution = Get-SPSolution -Identity TestSolution.wsp
    Write-Host "Start Uninstall ..." -ForegroundColor Yellow
    Uninstall-SPSolution -Identity TestSolution.wsp -AllWebApplications -Confirm:$false
    Write-Host "Uninstalling solution ..." -ForegroundColor Blue
    while($Solution.JobExists){
        Write-Host -NoNewline "..." -ForegroundColor Blue
        Start-Sleep -Seconds 3
    }                      
    Write-Host ""
    Remove-SPSolution -Identity TestSolution.wsp -Confirm:$false
    Write-Host "Solution removed..." -ForegroundColor Green
}
 
RemoveTestSolution

То прежде чем удалить решение с фермы, оно будет отозвано, дождется выполнения операции отзыва и удалит его с фермы

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

function RemoveSolution($SolutionName) {
    Write-Host "Removing solution $SolutionName" -ForegroundColor Yellow
    $Solution = Get-SPSolution -Identity $SolutionName -ErrorAction SilentlyContinue
    if ($Solution -ne $null) {
        $SolutionDisplayName = $Solution.Name
        Write-Host "Solution found: $SolutionDisplayName" -ForegroundColor Yellow
        $DeploymentState = $Solution.DeploymentState
        Write-Host "$SolutionName was deployed as: $DeploymentState" -ForegroundColor Yellow
        if ($DeploymentState -ne "NotDeployed") {
            if ($DeploymentState -eq "GlobalDeployed" ) {
                Uninstall-SPSolution -Identity $SolutionName -Confirm:$false
            }
            else {
                Uninstall-SPSolution -Identity $SolutionName -AllWebApplications -Confirm:$false
            }
            Write-Host -NoNewline "Retracting solution $SolutionName ..." -ForegroundColor Blue
            while ($Solution.JobExists) {
                Write-Host -NoNewline "..." -ForegroundColor Blue
                Start-Sleep -Seconds 3
            }
        }
        Write-Host ""
        Remove-SPSolution -Identity $SolutionName -Confirm:$false
        Write-Host "Removed: $SolutionName" -ForegroundColor Green
    }
    else {
        Write-Host "Solution $SolutionName not found" -ForegroundColor Red
    }
}

function AddSolution($WspPath, $WebApplication, $Retract) {
    $SolutionName = GetWspNameByPath $WspPath     
    if ($Retract) {
        RemoveSolution $SolutionName
    }
    Write-Host "Installing solution $SolutionName" -ForegroundColor Yellow    
    $Solution = Get-SPSolution -Identity $SolutionName -ErrorAction SilentlyContinue
    if ($Solution -eq $null) {
        Add-SPSolution -LiteralPath $WspPath | Out-Null
        $Solution = Get-SPSolution -Identity $SolutionName -ErrorAction SilentlyContinue
    }    
    $DeploymentState = $Solution.DeploymentState    
    if ($DeploymentState -eq "NotDeployed") {
        $InstallKeys = ""
        if ($Solution.ContainsGlobalAssembly){ $InstallKeys += " -GACDeployment"}
        if ($Solution.ContainsWebApplicationResource) {    
           if ($WebApplication) { 
              $InstallKeys += " -WebApplication $WebApplication" 
           } 
           else { 
              $InstallKeys += " -AllWebApplications" 
           }
        }

        iex "Install-SPSolution -Identity $SolutionName $InstallKeys -Force"

        Write-Host -NoNewline "Installing solution $SolutionName ..." -ForegroundColor Blue
        while($Solution.JobExists){
            Write-Host -NoNewline "..." -ForegroundColor Blue
            Start-Sleep -Seconds 3
        }        
        Write-Host ""
        Write-Host "Installed: $SolutionName" -ForegroundColor Green        
    }
    else {
        Write-Host "Solution $SolutionName already intalled. Retract solution before install" `
                   -ForegroundColor Red        
    }    
}

function GetWspNameByPath ($WspPath) {
    $WspPathArr = $WspPath -split ""
    $WspName = $WspPathArr[$WspPathArr.length-1]
    return $WspName
}

AddSolution "C:TempTestSolution.wsp" "" true

Опубликовано: 10.02.2014
Автор: Сергей Снитко