#Test script to uninstall Drivers, UWP Apps and delete files
#Script will remove all versions of drivers
#Will return to Inbox driver, if available

#Last edit 2019-03-26 - nceleste


Function Get-IniContents 
{
    [CmdletBinding()]
    Param ([string] $IniFilePath)
    Process
    {
        $ini = @{}  
        switch -regex -file $IniFilePath
        {  
            "^\[(.+)\]$" # Section  
            {  
                $section = $matches[1]  
                $ini[$section] = @{}  
                $CommentCount = 0  
            }  

            "^(;.*)$" # Comment  
            {  
                $section = "Comment" 

                if($ini.Keys -notcontains "Comment")
                {
                    $ini[$section] = @{}  
                }
                  
                $value = $matches[1]  
                $CommentCount = $CommentCount + 1  
                $name = "Comment" + $CommentCount  
                $ini[$section][$name] = $value  
            }  
         
            "(.+?)\s*=\s*(.*)" # Key  
            {  
                if (!($section))  
                {  
                    $section = "No-Section"  
                    $ini[$section] = @{}  
                }  
                $name,$value = $matches[1..2]  
                $ini[$section][$name] = $value  
            }  
        }  
        
        return $ini  
    }
}

Function Write-LogFile
{
    [CmdletBinding()]
    Param([Parameter(ValueFromPipeline)] $logEvent)
    Process
    {
        Add-Content -Path $logPath -Value $logEvent
    }

}

Function Remove-Driver
{   
    [CmdletBinding()]
    Param([hashtable] $infs)
    Process
    {
        Write-LogFile "[Uninstall Drivers]"

        $retCode = 0
        $extensionInfs = @{}

        if($infs.Count -eq 0)
        {
            Write-LogFile ">> No driver to remove"
            return $retCode
        }
    
        #Re-order keys (01,02...); else it will be on a random order
        $ordInfs = $infs.GetEnumerator() | sort key
       
        #Get driver list; 
        $drv = PnpUtil.exe /enum-drivers

        #Can't use the ff as it doesn't list the original driver name
        #$DevName = Get-WmiObject Win32_PnPSignedDriver| select * | where {$_.DeviceName -like "*Realtek*"}

     
        foreach($i in $ordInfs)
        {                       
            Write-LogFile ("> Uninstalling " + $i.Value)

            #Get Published Name (Ex. oem1.inf) and Class Name (ex. Extension)
            $publishedName = $drv | Select-String -Pattern $i.Value -Context 2,2 | ForEach { @{ "Inf" = ($_.Context.PreContext[1] -split ':')[1].trim() ; "ClassName" = ($_.Context.PostContext[1] -split ':')[1].trim()} } 

            if ($publishedName.Count -eq 0)
            {
                Write-LogFile "...Cannot find inf`r`n" 
                $retCode = -1
            }

            foreach($p in $publishedName)
            {
                if($p["ClassName"] -contains "Extensions")
                {
                    Write-LogFile "...Found Extension INF; To remove later`r`n"
                
                    #Add into Extension Inf List
                    $extensionInfs.Add($p["Inf"], $i.Value)

                }
                else
                {
                    Write-LogFile ("...Deleting " + $p["Inf"])
                
                    #Uninstall driver
                    PnpUtil.exe /delete-driver $p["Inf"] /uninstall /force | Write-LogFile

                    switch ($LASTEXITCODE)
                    {
                        0: {} #success
                        259: {} #reboot
                        default: { $retCode = $LASTEXITCODE }
                    }

                    Write-LogFile "`n"
                }

            }        

         }

         foreach($e in $extensionInfs.Keys)
         {
        
            Write-LogFile ("> Uninstalling Extension INF: " + $extensionInfs[$e])
            Write-LogFile ("`...Deleting " + $e)

            #Uninstall Extension Inf
            PnpUtil.exe /delete-driver $e /uninstall /force | Write-LogFile

            switch ($LASTEXITCODE)
            {
                0: {} #success
                259: {} #reboot
                default: { $retCode = $LASTEXITCODE }
            }

            Write-LogFile "`n"
         }
    
        return $retCode
    }
}

Function Remove-App
{
    [CmdletBinding()]
    Param([hashtable] $apps)
    Process
    {
        Write-LogFile "`r`n`r`n[Uninstall Appx Packages]"

        $retCode = 0

        if($apps.Count -eq 0)
        {
            Write-LogFile ">> No HSA to remove"
            return $retCode
        }

        #Re-order keys (01,02...)
        $ordApps = $apps.GetEnumerator() | sort key

        $provAppx =  Dism /Online /Get-ProvisionedAppxPackages
     
        foreach($uwp in $ordApps)
        {
            Write-LogFile (">> Uninstalling " + $uwp.Value)

            #Get Package Name    
            $pkgName = $provAppx | Select-String -Pattern ('DisplayName : '+$uwp.Value) -Context 0,4 | ForEach { ($_.Context.PostContext[3] -split 'PackageName : ')[1].trim() }
        
            if($pkgName.Count -eq 0)
            {
                Write-LogFile "...Cannot find App`r`n" 
                $retCode = -1
            }

            foreach($n in $pkgName)
            {
                Write-LogFile ("...Removing package: " + $n)

                #Remove app from user
                Remove-AppxPackage -Package $n | Write-LogFile

                #Remove Provisioned Package
                Dism /Online /Remove-ProvisionedAppxPackage /PackageName:$n | Write-LogFile

                if($LASTEXITCODE -ne 0)
                {
                    $retCode = $LASTEXITCODE
                }

                Write-LogFile "`n"
            }
            
        }
        return $retCode
    }
}

Function Remove-File 
{
    [CmdletBinding()]
    Param ([hashtable] $files)
    Process
    {
        Write-LogFile "`r`n`r`n[Delete Files]"
    
        $retCode = 0

        if($files.Count -eq 0)
        {
            Write-LogFile ">> No files to remove"
            return $retCode
        }

        #Re-order keys (01,02...)
        $ordFiles = $files.GetEnumerator() | sort key

        foreach($f in $ordFiles)
        {
            if(Test-Path $f.Value)
            {
                #Delete File
                Remove-Item -Path $f.Value -Recurse -Force
                Write-LogFile (">> Deleted: " + $f.Value)
            }
            else
            {
                Write-LogFile (">> File does not exist:  " + $f.Value)
                $retCode = -1
            }
        }

        return $retCode
    }
}


#Get contents of ini file
$curLoc = Split-Path -Parent $MyInvocation.MyCommand.Definition 
$targetFile = $curLoc + "\RemoveList.ini"
$iniContent = Get-IniContents $targetFile

#Create log file
$timestmp = Get-Date -Format yyyyMMdd-HHmmss
$logName = "\Result_" + $timestmp + ".log"

$logFile = New-Item -Path $curLoc -Name $logName -ItemType "file" 
$logPath = $curLoc +"\"+$logName

#Remove drivers, apps and files
$removeINF = Remove-Driver $iniContent["INF"]
$removeApp = Remove-App $iniContent["HSA"]
$removeFile = Remove-File $iniContent["Files"]

if($removeINF -ne 0)
{
    #TODO
}
if($removeApp -ne 0)
{
    #TODO
}
if($removeFile -ne 0)
{
    #TODO
}
