Repair-Command.ps1

function Repair-Command
{
    <#
    .Synopsis
        Repair-Command attempts to fix your scripts.
    .Description
        Repair-Command will use a set of repair scripts to attempt to automatically
        resolve an issue uncovered with ScriptCop.
 
        Repair-Command will take all issues thru the pipeline, and will output
        an object with the Rule, Problem, ItemWithProblem, and WasFixed.
    .Link
        Test-Command
    .Example
        Get-Module MyModule | Test-Command | Repair-Command
    #>

    param(
    # The Rule that flagged the problem
    [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
    [ValidateScript({
        if ($_ -is [Management.Automation.CommandInfo]) {
            return $true
        }
        if ($_ -is [Management.Automation.PSModuleInfo]) {        
            return $true
        } 
        
        throw 'Must be a CommandInfo or a PSModuleInfo'            
    })]
    [PSObject]$Rule,
    
    # The Problem
    [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
    [Management.Automation.ErrorRecord]
    $Problem,
    
    # The Item with the Problem
    [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
    [ValidateScript({
        if ($_ -is [Management.Automation.CommandInfo]) {
            return $true
        }
        if ($_ -is [Management.Automation.PSModuleInfo]) {        
            return $true
        } 
        
        throw 'Must be a CommandInfo or a PSModuleInfo'            
    })]
    [PSObject]$ItemWithProblem,
    
    # If set, only fixers which have indicated they will not require user interaction will be run.
    [Switch]$NotInteractive
    )
    
    #region Initialize The List of Problems
    begin {

        # Make a quick pair of functions to help people output the right thing
        function CouldNotFixProblem
        {
            param([string]$ErrorId)
            
            $info = @{
                WasIdentified=$false
                CouldFix=$false                
                WasFixed=$false
                ErrorId = $errorID
                Problem=$Problem
                ItemWithProblem=$ItemWithProblem
                Rule=$Rule
                FixRequiresRescan=$false
            }
            
            New-Object PSObject -Property $Info
        }                        
                
        function TriedToFixProblem
        {
            param([string]$ErrorId,
            [Switch]$FixRequiresRescan)
            
            $stillHasThisProblem = $ItemWithProblem | 
                Test-Command -Rule "$Rule" |
                Where-Object {                     
                    $_.Problem.FullyQualifiedErrorId -like "$ErrorId*"                    
                }
                        
            New-Object PSObject -Property @{
                WasIdentified = $true
                CouldFix = $true
                WasFixed = -not ($stillHasThisProblem -as [bool])
                ErrorId = $errorId
                Problem=$Problem
                ItemWithProblem=$ItemWithProblem
                Rule=$Rule
                FixRequiresRescan=$FixRequiresRescan
            } 
        }        

        
        # Declare a list to hold the problems (for speed)
        $problems = New-Object Collections.ArrayList
        
        
    }  
    #endregion
    
    #region Add Each Problem to the List
    process {
        $null = $problems.Add((New-Object PSObject -Property $psBoundParameters))
        Write-Verbose "Processing
$($_ | Out-String)
"
 
    }
    #endregion
    
    
    end {
        try {
            #region Fix the Problems That You Can
            $script:ScriptCopFixers |
                ForEach-Object -Begin {
                    $holdUp = $false
                } {
                    $fixer = $_
                                    
                    $problems | 
                        & $fixer | 
                        ForEach-Object {
                            $fix = $_
                            if ($_.FixRequiresRescan) {
                                $holdUp = $true
                            }
                            throw $holdup
                        }
                        
                    trap 
                    {
                        if (-not (Get-Variable -Scope 1 -Name holdUp -ErrorAction SilentlyContinue)) { 
                            throw $_ 
                        } else { break }                                         
                    }                    
                }
        } catch {
            if ($_.InvocationInfo.Line -like '*throw $holdup*') {
                Write-Warning "Fixed $($fix.Problem) on $($Fix.ItemWithProblem), but that fix changed files, so you must rescan"
                return
            } else {
                Write-Error -ErrorRecord $_
                return
            }
        }
        #endregion
    }       
}