# encoding: ascii
# api: powershell
# title: SUG Cleanup Installer
# description: This is a modified version of the script included with the Clean Software Update Groups console extension for SCCM 2012R2
# version: 0.1
# type: script
# author: Neighborgeek
# license: CC0
# x-poshcode-id: 5980
# x-archived: 2015-08-22T03:18:27
# x-published: 2015-08-19T17:30:00
#
#
<#
.Synopsis
   Installs or uninstalls the Clean Software Update Groups console extension for 
   System Center Configuration Manager 2012 & 2012R2
.DESCRIPTION
   Configures settings for and installs a console extension to remove expired and (optionally) superseded 
   updates from software update groups in SCCM.
.PARAMETER SiteServer
   Specifies the name of the Site Server where the SMS Provider is installed. (NOT the Site Code!)

.PARAMETER Path
    Sets the path where the Clean Software Update Groups script file will be stored (Or removed from, 
    if the run with -Uninstall).  This path must already exist, the script will not create the path 
    if it is not found. 
.PARAMETER Uninstall 
   Runs the script in "Uninstall" mode, to remove the console extension from a computer where it has
   been previously installed. 
.EXAMPLE
    PS > Invoke-ToolInstallation.ps1 -SiteServer Siteserver.domain.com -Path C:\Scripts -Verbose
    VERBOSE: ConfigMgr console environment variable detected: C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\i386
    VERBOSE: Creating folder: 'C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\XmlStorage\Extensions\Actions\23e7a3fe-b0f0-4b24-813a-dc425239f9a2'
    VERBOSE: Editing 'CleanSoftwareUpdateGroups.xml' to contain the correct path to script file
    VERBOSE: Copying 'CleanSoftwareUpdateGroups.xml' to Software Update Groups node action folder
    VERBOSE: Copying 'Clean-CMSoftwareUpdateGroups.ps1' to: 'C:\Scripts'
.EXAMPLE
    PS > Invoke-ToolInstallation.ps1 -Uninstall -path c:\scripts\ -Verbose
    VERBOSE: ConfigMgr console environment variable detected: C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\i386
    VERBOSE: Found folder: 'C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\XmlStorage\Extensions\Actions\23e7a3fe-b0f0-4b24-813a-dc425239f9a2'
    VERBOSE: Removing 'CleanSoftwareUpdateGroups.xml' from Software Update Groups node action folder
#>

[CmdletBinding(SupportsShouldProcess=$true) ]
param(
    [parameter(Mandatory=$true, HelpMessage="Site server where the SMS Provider is installed", ParameterSetName="Install")]
    [ValidateNotNullOrEmpty()]
    [string]$SiteServer,
    [parameter(Mandatory=$true, HelpMessage="Specify a valid path to where the Clean Software Update Groups script file will be stored", ParameterSetName="Install")]
    [parameter(Mandatory=$true, ParameterSetName="Uninstall")]
    [ValidateNotNullOrEmpty()]
    [ValidatePattern("^[A-Za-z]{1}:\\\w+")]
    [ValidateScript({
        # Check if path contains any invalid characters
        if ((Split-Path -Path $_ -Leaf).IndexOfAny([IO.Path]::GetInvalidFileNameChars()) -ge 0) {
            throw "$(Split-Path -Path $_ -Leaf) contains invalid characters"
        }
        else {
            # Check if the whole path exists
            if (Test-Path -Path $_ -PathType Container) {
                    return $true
            }
            else {
                throw "Unable to locate part of or the whole specified path, specify a valid path"
            }
        }
    })]
    [string]$Path,
    [parameter(Mandatory=$true, ParameterSetName="Uninstall")]
    [switch]$Uninstall
)
Begin {
    # Validate that the script is being executed elevated
    try {
        $CurrentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent()
        $WindowsPrincipal = New-Object Security.Principal.WindowsPrincipal -ArgumentList $CurrentIdentity
        if (-not($WindowsPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))) {
            Write-Warning -Message "Script was not executed elevated, please re-launch." ; break
        }
    } 
    catch {
        Write-Warning -Message $_.Exception.Message ; break
    }
    # Determine PSScriptRoot
    $ScriptRoot = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
    # Validate ConfigMgr console presence
    if ($env:SMS_ADMIN_UI_PATH -ne $null) {
        try {
            if (Test-Path -Path $env:SMS_ADMIN_UI_PATH -PathType Container -ErrorAction Stop) {
                Write-Verbose -Message "ConfigMgr console environment variable detected: $($env:SMS_ADMIN_UI_PATH)"
            }
        }
        catch [Exception] {
            Write-Warning -Message $_.Exception.Message ; break
        }
    }
    else {
        Write-Warning -Message "ConfigMgr console environment variable was not detected" ; break
    }
    # Define installation file variables
    $XMLFile = "CleanSoftwareUpdateGroups.xml"
    $ScriptFile = "Clean-CMSoftwareUpdateGroups.ps1"
    # Define node folders
    $Node = "23e7a3fe-b0f0-4b24-813a-dc425239f9a2"
    # Validate if required files are present in the script root directory
    if (-not(Test-Path -Path (Join-Path -Path $ScriptRoot -ChildPath $XMLFile) -PathType Leaf -ErrorAction SilentlyContinue)) {
        Write-Warning -Message "Unable to determine location for '$($XMLFile)'. Make sure it's present in '$($ScriptRoot)'." ; break
    }
    if (-not(Test-Path -Path (Join-Path -Path $ScriptRoot -ChildPath $ScriptFile) -PathType Leaf -ErrorAction SilentlyContinue)) {
        Write-Warning -Message "Unable to determine location for '$($ScriptFile)'. Make sure it's present in '$($ScriptRoot)'." ; break
    }
    # Determine Admin console root
    $AdminConsoleRoot = ($env:SMS_ADMIN_UI_PATH).Substring(0,$env:SMS_ADMIN_UI_PATH.Length-9)
    # Create Action folders if not exists
    $FolderList = New-Object -TypeName System.Collections.ArrayList
    $FolderList.AddRange(@(
        (Join-Path -Path $AdminConsoleRoot -ChildPath "XmlStorage\Extensions\Actions\$($Node)")
    )) | Out-Null
    foreach ($CurrentNode in $FolderList) {
        if (-not(Test-Path -Path $CurrentNode -PathType Container)) {
            Write-Verbose -Message "Creating folder: '$($CurrentNode)'"
            New-Item -Path $CurrentNode -ItemType Directory -Force | Out-Null
        }
        else {
            Write-Verbose -Message "Found folder: '$($CurrentNode)'"
        }
    }
    if ($Uninstall){
        $Method = "Uninstall"
    }
    else {
        $Method = "Install"
    }
}
Process {
    switch ($Method) {
        "Install" {
            # Edit XML files to contain correct path to script file
            if (Test-Path -Path (Join-Path -Path $ScriptRoot -ChildPath $XMLFile) -PathType Leaf -ErrorAction SilentlyContinue) {
                Write-Verbose -Message "Editing '$($XMLFile)' to contain the correct path to script file"
                $XMLDataFilePath = Join-Path -Path $ScriptRoot -ChildPath $XMLFile
                [xml]$XMLDataFile = Get-Content -Path $XMLDataFilePath
                $XMLDataFile.ActionDescription.ActionGroups.ActionDescription.Executable | Where-Object { $_.FilePath -like "*powershell.exe*" } | ForEach-Object {
                    $_.Parameters = $_.Parameters.Replace("#PATH#","'$($Path)\$($ScriptFile)'").Replace("'",'"').Replace("#SERVER#","$($SiteServer)")
                }
                $XMLDataFile.Save($XMLDataFilePath)
            }
            else {
                Write-Warning -Message "Unable to load '$($XMLFile)' from '$($Path)'. Make sure the file is located in the same folder as the installation script." ; break
            }
            # Copy XML to Software Update Groups node
            Write-Verbose -Message "Copying '$($XMLFile)' to Software Update Groups node action folder"
            $XMLStorageSUGArgs = @{
                Path = Join-Path -Path $ScriptRoot -ChildPath $XMLFile
                Destination = Join-Path -Path $AdminConsoleRoot -ChildPath "XmlStorage\Extensions\Actions\$($Node)\$($XMLFile)"
                Force = $true
            }
            Copy-Item @XMLStorageSUGArgs
            # Copy script file to specified path
            Write-Verbose -Message "Copying '$($ScriptFile)' to: '$($Path)'"
            $ScriptFileArgs = @{
                Path = Join-Path -Path $ScriptRoot -ChildPath $ScriptFile
                Destination = Join-Path -Path $Path -ChildPath $ScriptFile
                Force = $true
            }
            Copy-Item @ScriptFileArgs
        }
        "Uninstall" {
            # Remove XML file from Software Update Groups node
            Write-Verbose -Message "Removing '$XMLFile' from Software Update Groups node action folder"
            $XMLStorageDevicesArgs = @{
                Path = Join-Path -Path $AdminConsoleRoot -ChildPath "XmlStorage\Extensions\Actions\$Node\$XMLFile"
                Force = $true
                ErrorAction = "SilentlyContinue"
            }
            Remove-Item @XMLStorageDevicesArgs
            # Remove script file from specified path
            Write-Verbose -Message "Removing '$ScriptFile' from: '$Path'"
            $ScriptFileArgs = @{
                Path = Join-Path -Path $Path -ChildPath $ScriptFile
                Force = $true
            }
            Remove-Item @ScriptFileArgs
        }
    }
}
