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

#Last edited 2022-07-14 - ktagupa
#Updates: 
#  RemoveDrivers_0.4 (2022-07-14): 
#         -Updated the script in the Remove-CstApplicationVersion function to accomodate the removal of the registry key
#          in the  new path created by ICST 2.1.x.x drivers.
#  RemoveDrivers_0.3 (2022-01-26): 
#         -Updated the script to include the Remove-CstApplicationVersion function as recommended by the CST user guide 
#          for CST uninstallation.
#  RemoveDrivers_0.2 (2021-12-07): 
#         -Updated the script so that the removelist.ini file name is not fixed and the list file reference will be flexible indicating it as a parameter.



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
                {    

                    #----start of the removal of devices script-----#
                    $stringInfName = "InfName = '" + $p["Inf"] + "'"
                    
                    $deviceIDQuery = Get-CimInstance win32_PnPSignedDriver -Filter $stringInfName | Select DeviceID  
                   
                    
                    if(![string]::IsNullOrEmpty($deviceIDQuery))
                    {
                       $multipleDeviceHolder = $deviceIDQuery.DeviceID.split()
                       $numOfDevices = $multipleDeviceHolder.count 
                       Write-LogFile ($numOfDevices)
            
                       for($ib = 0; $ib -lt $numOfDevices; $ib++)
                       {
                          Write-LogFile ("...Removing " + $multipleDeviceHolder[$ib])
                          PnpUtil.exe /remove-device $multipleDeviceHolder[$ib]
                       } 
                       PnpUtil.exe /remove-device $deviceIDQuery.DeviceID
                    }
                    #----end of the removal of devices script-----#

                    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)
         { 
            #----start of the removal of devices script-----#
            $stringextInfName = "InfName = '" + $e + "'"
           
            $extdeviceIDQuery = Get-CimInstance win32_PnPSignedDriver -Filter $stringextInfName | Select DeviceID  
        
            if(![string]::IsNullOrEmpty($extdeviceIDQuery))
            {
                $multipleExtDeviceHolder = $extdeviceIDQuery.DeviceID.Split()
                $numOfExtDevices = $multipleExtDeviceHolder.count 
                Write-LogFile ($numOfExtDevices)
            
                for($ie = 0; $ie -lt $numOfExtDevices; $ie++)
                { 
                   Write-LogFile ("...Removing " + $multipleExtDeviceHolder[$ie])
                   PnpUtil.exe /remove-device $multipleExtDeviceHolder[$ie]
                }
            }      
            #----end of the removal of devices script-----#
        
            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"
         }

         Remove-CstApplicationVersion

        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
    }
}

function Remove-CstApplicationVersion()
{
 	if(-not(Test-Path "HKU:\"))
        {
          New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS
        } 
        $registryPath = @(
                         #CstApplicationVersion path for ICST 2.0.x.x
                         "HKU:\S-1-5-19\SOFTWARE\Intel\IntelCstService"
                         #CstApplicationVersion path for ICST 2.1.x.x
                         "HKU:\.DEFAULT\SOFTWARE\Intel\IntelCstService"
                        )
        $propertyName = "CstApplicationVersion"
        
        Foreach($regPath in $registryPath){
            if(Test-Path $regPath)
            {
              Write-Output "Removing CST Application Version Key..."
              Remove-ItemProperty -Path $regPath -Name $propertyName -Force -ErrorAction SilentlyContinue
            }
        }

}
#Getting list for driver removal .ini file which was indicated as a parameter.
$param1 = $args[0]

#Get contents of ini file
$curLoc = Split-Path -Parent $MyInvocation.MyCommand.Definition 
$targetFile = $curLoc + "\" + $param1
$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
}
