Take the 2-minute tour ×
SharePoint Stack Exchange is a question and answer site for SharePoint enthusiasts. It's 100% free, no registration required.

I'm trying to create a custom function that can uninstall and reinstall any SharePoint solution.

Some solutions requires the -GACDeployment switch, some requires the -AllWebApplications and some requires the -WebApplication switch.

How can I properly handle this multiple combinations?

By now, I have a function that works well with the two first possibilities (Gac and all web applications). But I having some troubles to make the multiple web application possibles.

Here is a sample of how the function should be called:

 # Already working :
 Update-SPSolutionWithCompleteReinstall .\SolutionwithGac.wsp
 Update-SPSolutionWithCompleteReinstall .\SolutionwithWebRes.wsp -AllWebApplications
 Update-SPSolutionWithCompleteReinstall .\SolutionwithWebRes.wsp -WebApplications "http://app1"
 $webApp = Get-SPWebApplication "http://app1"
 Update-SPSolutionWithCompleteReinstall .\SolutionwithWebRes.wsp -WebApplications $webApp

 # Not working :
 Update-SPSolutionWithCompleteReinstall .\SolutionwithWebRes.wsp -WebApplications "http://app1","http://app2"
 $webApp1 = Get-SPWebApplication "http://app1"
 $webApp2 = Get-SPWebApplication "http://app2"
 Update-SPSolutionWithCompleteReinstall .\SolutionwithWebRes.wsp -WebApplications $webApp1,$webApp2

And here is the function itself :

function Update-SPSolutionWithCompleteReinstall
{
    [CmdLetBinding(DefaultParametersetName="NoWebApplication")]
    param(
        [Parameter(Mandatory=$true,ParameterSetName="NoWebApplication", Position=0)]
        [Parameter(Mandatory=$true,ParameterSetName="WebApplications", Position=0)]
        [Parameter(Mandatory=$true,ParameterSetName="AllWebApplications", Position=0)]
        [string]$filePath,
        [Parameter(ParameterSetName="AllWebApplications", Position=1)]
        [switch]$AllWebApplications,
        [Parameter(ParameterSetName="WebApplications", Position=1)]
        [Microsoft.SharePoint.PowerShell.SPWebApplicationPipeBind]$WebApplications
    )
    $filePath = Resolve-Path $filePath
    $wspFileName = Split-Path -leaf $filePath

    $currentSol = Get-SPSolution | ? { $_.Name -match $wspFileName }

    # 1. Uninstall the solution
    if($currentSol)
    {
        Write-Host "The solution $($currentSol.Name) has been found. Uninstalling it"
        if($currentSol.ContainsWebApplicationResource)
        {
            Uninstall-SPSolution $currentSol -AllWebApplications -Confirm:$false
        }
        else
        {
            Uninstall-SPSolution $currentSol -Confirm:$false            
        }
        Wait-SPSolutionDeploymentJobToFinish $currentSol.Name

        Write-Host "Remove $($currentSol.Name) from the solution store"
        Remove-SPSolution $currentSol -Confirm:$false       
    }

    # 2. install and deploy the new solution
    Write-Host "Adding the solution $filePath"
    $newSol = Add-SPSolution -LiteralPath $filePath

    $expr = 'Install-SPSolution $newSol'

    if($newSol.ContainsWebApplicationResource)
    {
        switch ($PsCmdlet.ParameterSetName) 
        {
            "AllWebApplications" {
                $expr += " -AllWebApplications"
            }
            "WebApplications" {
                $expr += " -WebApplication $($WebApplications.Read().Url)"
            }
        }
    }
    if($newSol.ContainsGlobalAssembly)
    {
        $expr += ' -GACDeployment'
    }

    Write-Host "Install the solution $filePath"
    Invoke-Expression -Command $expr 

    Wait-SPSolutionDeploymentJobToFinish $newSol.Name

}

The specific part of the function where the trouble is located, is where I'm building a custom expression to be invoked.

share|improve this question
add comment

1 Answer

up vote 2 down vote accepted

Basically handle it how you would when presented this in other languages, pass an array for the site parameter.

For format in powershell for this is:

[string[]]$stringArray

$stringArray = @("site1","site2")

That way you can handle how many you send and/or do another method depending what you pass.

[update]

There isn't a type you can pass in to handle this without something ugly as in:

$webApp1 = Get-SPWebApplication "http://app1"
$webApp2 = Get-SPWebApplication "http://app2"
$WebAppArray = @($webApp1, $webApp2);
Update-SPSolutionWithCompleteReinstall .\SolutionwithWebRes.wsp -WebApplications (,$WebAppArray)

I would be really tempted to handle the innards of this function differently, so you can consume a simpler string input. Another parameter set to consume this in a simpler format?

The reason you couldn't do it another way afaik is that all the variables passed after the parameter count get put into the final variable, and powershell parameters as cool as they are won't consume the input in the way you are expecting.

WebApplications now would accept multiple string inputs and convert that after the params to the required type.

// Post processing here
switch ($PsCmdlet.ParameterSetName)
{
    "WebApplications" { //code to handle here }
    "NoWebApplication" { ... }
    "AllWebApplications { ... }
}

// All common code here

Best I can come up with.

share|improve this answer
    
I know how to instanciate array. What I don't know is how to use them in my expression construction. And please note that I don't use string but SPWebApplicationPipeBind –  Steve B Dec 3 '12 at 10:28
    
Ah that makes your question a little clearer. Besides I try and include the whole thing in-case someone googles. Let me look at the code again. –  Hugh Wood Dec 3 '12 at 10:43
    
You are right, this does not works : Get-SPWebApplication "http://app1","http://app2" but this works : "http://app1","http://app2" | Get-SPWebApplication (without the need for the foreach-object). I'm wondering how the seconds works. –  Steve B Dec 3 '12 at 13:06
    
Probably an internal foreach over the $InputObject variable, I guess. I believe you are right, I'll have to deal with arrays. If I look at the Get-Process cmdlet, I think that I can declare my parameter as array, but still can pass a single value (PS will create an array on the fly with the single element) –  Steve B Dec 3 '12 at 13:13
1  
It basically calls it multiple times, it's a input command pipe, the input is passed as the parameter one at a time. You can use it invertly for filters too and display outputs. | Where-Object or | More (The most common pipe in a cmd window) –  Hugh Wood Dec 3 '12 at 13:55
show 2 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.