Disable featureIDs by SolutionID

This topic contains 6 replies, has 3 voices, and was last updated by Profile photo of Ketty 3-bit Ketty 3-bit 2 years, 1 month ago.

  • Author
    Posts
  • #19854
    Profile photo of Ketty 3-bit
    Ketty 3-bit
    Participant

    Hello,

    I'm fairly new to Powershell (10 months) and I think is great – but still a novice (learning).
    I've been tasked with providing scripts for automating content deployment. I am stuck on how to write a script disabling and re-enabling features associated with a solutionID. The below script runs fine in an environment with only (1) site/webapp/web but fails when run on a farm with multiple sites/webapps/webs.

    How can I add to the script to traverse all sites/webapps/webs to identify all featureIDs assiciated with (a) solution ID and disable/enable at each level successfully.
    Please respond soon. I've been stuck here for a very long time...way too long.

    The Script loads data from an XML file
    ## Locate FeatureIDs and deactivate all features associated with this solution

    $s = get-spsite | ForEach{ $_.URL }
    $F = Get-SPFeature | where-object {$_.solutionid -eq $currentSolutionID} |%{ disable-SPFeature -Identity $_ -URL $s -confirm:$false } -ErrorAction SilentlyContinue
    $feature = Get-spfeature| where-object {$_.solutionid -eq $currentsolutionid} |%{ write-host " Deactivating feature: " $_.displayname } -ErrorAction SilentlyContinue

    Thank you in advance for your assistance.

  • #19855
    Profile photo of Alexander Johansson
    Alexander Johansson
    Participant

    Hello!

    $s = get-spsite | ForEach{ $_.URL }

    Sets the variable $s to the last item in the ForEach loop, since it overwrites the item in the variable everytime it loops.

    You should rather insert the code that you want to run in the ForEach-Object loop.

    Also when you use

    Get-SPFeature

    You should filter the object you want in that cmdlet and the just pipe it to

    Disable-SPFeature

    Instead of using all those ForEach-Object loops.

    I dont have access to the SP module at the moment so I cant try it out.

    In which way does it fail when you run it on multiple sites? Does it only run on one site?

    /Alexander

  • #19858
    Profile photo of Ketty 3-bit
    Ketty 3-bit
    Participant

    Thanks for your response.
    I believe I can understand what you mean by "not so many foreach statements" but being a novice, I am unaware of another way to do this (at this time).
    Also, I have filtered first and then piped output to the disable-spfeature with this line :
    $F = Get-SPFeature | where-object {$_.solutionid -eq $currentSolutionID} |%{ disable-SPFeature -Identity $_ -URL $s -confirm:$false }
    To be clear, are you saying that this line could be more efficient?

    The solution file has many features with some scoped at farm level, some at site, and some at webapp level.

    There is a dev farm with one server, site/webapp and the script runs fine to disable all features under the same solutionID.

    There is a test farm with (3) servers, (5) webapps and multiple subsites. The script has been added to one of the WFEs.
    The script fails when retrieving the feature URL with the error "can't convert object to a string", so no features are disabled or re-enabled.

    The desired state for the automated process is for the script to be standardized and traverse Get-SPFarm -> Get-SPsolution -> Get-SPFeature ...
    with an XML file that holds srandard/solution data (servers, solution IDs, etc.) so that needed changes are made in the XML file only.

    Hope this helps to explain better.

    Thanks again,

    Kem

  • #19860
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    $s = get-spsite | ForEach{ $_.URL }
    Sets the variable $s to the last item in the ForEach loop, since it overwrites the item in the variable everytime it loops.

    This is not entirely accurate. It would be true if the code looked like this:

    Get-SPSite | ForEach { $s = $_.URL }
    

    The difference being that the assignment to $s is happening inside the ForEach loop body. When you assign the result of the entire pipeline to $s, on the other hand, $s will typically be an array (though it can also be $null or a single URL value, if Get-SPSite returns zero or one results.) This can also be written as:

    $s = Get-SPSite | Select-Object -ExpandProperty URL
    
    # In PowerShell v3 or later:
    
    $s = (Get-SPSite).URL
    
  • #19861
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    The documentation for Disable-SPFeature (found here: http://technet.microsoft.com/en-us/library/ff607879(v=office.15).aspx ) says that the type of the -URL parameter is System.String. That's a single string, not an array. If Get-SPSite returns multiple values, $s will be an array, which can be casted back to a string, but doesn't have quite the effect you were after. If you need to call Disable-SPFeature for each site, then you'll need another loop. Something along these lines, though I can't test this code as I don't have a SharePoint environment handy:

    # Using the @() operator here ensures that $sites is an array, even if Get-SPSite only returns zero or one result.
    # This can be important in PowerShell 2.0. 
    $urls = @(Get-SPSite | ForEach-Object { $_.URL })
    
    Get-SPFeature |
    Where-Object {$_.solutionid -eq $currentSolutionID} |
    ForEach-Object {
        $feature = $_
    
        Write-Host " Deactivating feature: $($feature.displayname)"
    
        foreach ($url in $urls)
        {
            Disable-SPFeature -Identity $feature -URL $url -Confirm:$false -ErrorAction SilentlyContinue
        }
    }
    
    
  • #19865
    Profile photo of Ketty 3-bit
    Ketty 3-bit
    Participant

    Thank you Dave,

    I understand a little better now. I knew I didn't have the formula quite right.
    I think this is what I was looking for. I'll try it right away and let you know.

    Thank you also Alexander.

  • #19984
    Profile photo of Ketty 3-bit
    Ketty 3-bit
    Participant

    Hi Dave,

    I was finally able to test this and it works just fine.
    Thank you very much again.

    I hope I'm able to assist someone else in the future. You guys ROCK!

    Thanks again.

You must be logged in to reply to this topic.