UninstallFastLinqPowerKit.psm1

# Functions

Function Test-IfNano {
    # Check if OS is Nano or Non-Nano
    $envInfo = [Environment]::OSVersion.Version
    $envInfoCimInst = Get-CimInstance Win32_OperatingSystem
    return ( ($envInfo.Major -eq 10) -and ($envInfo.Minor -eq 0) -and ($envInfoCimInst.ProductType -eq 3) -and ($envInfoCimInst.SuiteMask -eq 272) )
}

Function Test-RegistryValue {
    Param (
        [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] $Path,
        [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] $Value
    )

    try {
        Get-ItemProperty -Path $Path | Select-Object -ExpandProperty $Value -ErrorAction Stop 2>&1 | Out-Null
        return $true
    } catch {
        return $false
    }
}

Function Get-AppxPackageWrapper {
    Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] $AppxName )

    $numAttempts = 3
    $numSecondsBetweenAttempts = 5
    for ($i=0; $i -lt $numAttempts; $i++) {
        $appxPkg = Get-AppxPackage | Where-Object { $_.name -eq $AppxName }
        if ($appxPkg -ne $null) { break }
        Write-Host "Couldn't find Appx package. Trying again in $numSecondsBetweenAttempts seconds (attempt $($i+1) of $numAttempts) ..." -ForegroundColor DarkRed
        Start-Sleep -Seconds $numSecondsBetweenAttempts
    }
    if ($appxPkg -eq $null) {
        Write-Host 'Failed to find Appx package. Please try running this script again.' -ForegroundColor Red
        Exit
    }
    return $appxPkg
}

Function Remove-ProviderAppxProvisionedPackage {
    Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] $AppxDisplayName )
    if ($Script:isNano) { return } # Skip if Nano
    $appxProvPkg = Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -eq $AppxDisplayName }
    if ($appxProvPkg -ne $null) {
        Remove-AppxProvisionedPackage -Online -PackageName $appxProvPkg.PackageName 2>&1 | Out-Null
        Write-Host "Removed AppxProvisionedPackage $($appxProvPkg.PackageName)"
    }
}

Function Remove-CmdletsPathFromPSModulePath {
    # This function removes cmdlet module path(s) from system PSModulePath environment variable.

    $appxCmdletsPath = (Get-AppxPackageWrapper -AppxName 'QLGCProvider').InstallLocation + '\Cmdlets'
    if (Test-RegistryValue -Path 'HKLM:\System\CurrentControlSet\Control\Session Manager\Environment' -Value 'PSModulePath') {
        $currPSModulePathArr = ((Get-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Session Manager\Environment').PSModulePath).Split(';')
        $newPSModulePathArr = @()
        # Remove any paths containing 'QLGCProvider' from PSModulePath
        foreach ($path in $currPSModulePathArr) {
            if (-not $path.Contains('QLGCProvider')) {
                $newPSModulePathArr += $path
            } else {
                Write-Host "Removed '$path' from PSModulePath."
            }
        }
        $newPSModulePathStr = $newPSModulePathArr -join ';'

        # Write PSModulePath to registry and set local session variable
        & setx /s $env:COMPUTERNAME PSModulePath $newPSModulePathStr /m 2>&1 | Out-Null
        $env:PSModulePath = $newPSModulePathStr
    }
}

Function Remove-CLSIDRegistryPaths {
    if (Test-Path -Path "Registry::HKCR\CLSID\$Script:CLSID") {
        Remove-Item -Path "Registry::HKCR\CLSID\$Script:CLSID" -Recurse
        Write-Host "Removed HKCR:\CLSID\$Script:CLSID from registry."
    }
    if (Test-Path -Path "HKLM:\Software\Classes\CLSID\$Script:CLSID") {
        Remove-Item -Path "HKLM:\Software\Classes\CLSID\$Script:CLSID" -Recurse
        Write-Host "Removed HKLM:\Software\Classes\CLSID\$Script:CLSID from registry."
    }
}

Function Uninstall-MofComp {
    # TODO - Determine if this function is always necessary
    $appxPath = (Get-AppxPackageWrapper -AppxName 'QLGCProvider').InstallLocation

    # $mofcompOutput = & mofcomp.exe -N:root\qlgcfastlinq -class:forceupdate $appxPath\QLGCProviderUninstall.mof 2>&1
    $mofcompOutput = & mofcomp.exe -N:root\qlgcfastlinq $appxPath\QLGCProviderUninstall.mof 2>&1
    if ($mofcompOutput -match 'Error') {
        Write-Host "Failed to unregister `"$appxPath\QLGCProviderUninstall.mof`": $($mofcompOutput -match 'Error')" -ForegroundColor Red
    } else {
        Write-Host "QLGCProvider unregistered."
    }
    if (Test-RegistryValue -Path 'HKLM:\Software\Microsoft\Wbem\CIMOM\SecuredHostProviders' -Value 'Root/qlgcfastlinq:__Win32Provider.Name="QLGCProvider"') {
        Remove-ItemProperty -Path 'HKLM:\Software\Microsoft\Wbem\CIMOM\SecuredHostProviders' -Name 'Root/qlgcfastlinq:__Win32Provider.Name="QLGCProvider"'
    }
}

Function Remove-CmdletsFromProgramData {
    # Remove any ProgramData directories containing 'QLGCProvider_'
    $progDataPaths = (Get-ChildItem $env:ProgramData | Where-Object { ($_.Name).StartsWith('QLGCProvider_') }).FullName
    foreach ($path in $progDataPaths) {
        Remove-Item $path -Recurse -Force
        Write-Host "Cmdlets removed from `"$path`"."
    }
}

Function Remove-RESTFilesFromProgramData {
    # Remove any ProgramData directories containing 'QLGCProviderREST_'
    $progDataPaths = (Get-ChildItem $env:ProgramData | Where-Object { ($_.Name).StartsWith('QLGCProviderREST_') }).FullName
    foreach ($path in $progDataPaths) {
        Remove-Item $path -Recurse -Force
        Write-Host "REST files removed from `"$path`"."
    }
}

Function Remove-AppxPackageWrapper {
    Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] $AppxDisplayName )
    $appxPkg = Get-AppxPackage | Where-Object { $_.Name -eq $AppxDisplayName }
    if ($appxPkg -ne $null) {
        $savedProgressPreference = $Global:ProgressPreference
        $Global:ProgressPreference = 'SilentlyContinue'
        Remove-AppxPackage -Package $appxPkg 2>&1 | Out-Null
        $Global:ProgressPreference = $savedProgressPreference
        Write-Host "Removed $AppxDisplayName AppxPackage."
    }
}

Function Remove-FromIIS {
    $appcmd = "$env:SystemRoot\system32\inetsrv\appcmd.exe"

    # Stop all sites
    $sites = (& $appcmd list site 2>&1)
    if ($sites -ne $null) {
        if ($sites.GetType() -eq [System.String]) {
            $siteName = $sites.Split('"')[1]
            $appcmdOutput = (& $appcmd stop site $siteName 2>&1)
        } else {
            foreach ($s in $sites) {
                $siteName = $s.Split('"')[1]
                $appcmdOutput = (& $appcmd stop site $siteName 2>&1)
            }
        }
    }

    # Stop DefaultAppPool and MOData apppool
    $appcmdOutput = (& $appcmd stop apppool /apppool.name:DefaultAppPool 2>&1)
    $appcmdOutput = (& $appcmd stop apppool /apppool.name:MOData 2>&1)

    # Delete MOData appool
    $appcmdOutput = (& $appcmd delete apppool /apppool.name:MOData 2>&1)

    # Delete MODataSvc app
    $appcmdOutput = (& $appcmd delete app MODataSvc/MODataSvc 2>&1)

    # Delete MODataSvc site
    $appcmdOutput = (& $appcmd delete site MODataSvc 2>&1)
    Remove-Item "$env:HOMEDRIVE\inetpub\wwwroot\MOData" -Recurse -Force

    # Start DefaultAppPool apppool
    $appcmdOutput = (& $appcmd start apppool /apppool.name:DefaultAppPool 2>&1)

    # Start all sites
    $sites = (& $appcmd list site 2>&1)
    if ($sites -ne $null) {
        if ($sites.GetType() -eq [System.String]) {
            $siteName = $sites.Split('"')[1]
            $appcmdOutput = (& $appcmd start site $siteName 2>&1)
        } else {
            foreach ($s in $sites) {
                $siteName = $s.Split('"')[1]
                $appcmdOutput = (& $appcmd start site $siteName 2>&1)
            }
        }
    }

    # Remove any existing firewall rules
    if ((Get-NetFirewallRule | Where-Object { ($_.DisplayName).StartsWith('MOData_IIS_Port') }) -ne $null) {
        Remove-NetFirewallRule -DisplayName 'MOData_IIS_Port'
    }

    Write-Host "Removed from IIS."
}
Function UnInstall-PowerKit {
    # Encapulate uninstaller logic here
    #--------------------------------------------------------------------------------------------------
    # Globals
    $Script:CLSID = '{BC33E6C0-DB6A-4781-B924-CB1CDA88E4A1}'
    $Script:isNano = Test-IfNano
    $restIsInstalled = (Get-AppxPackage | Where-Object { $_.Name -eq 'QLGCProviderREST' }) -ne $null

    #--------------------------------------------------------------------------------------------------
    # Script - Cmdlets Uninstall
    Remove-ProviderAppxProvisionedPackage -AppxDisplayName 'QLGCProvider'
    Remove-CmdletsPathFromPSModulePath
    Remove-CLSIDRegistryPaths
    Uninstall-MofComp
    Remove-CmdletsFromProgramData
    Remove-AppxPackageWrapper -AppxDisplayName 'QLGCProvider'
    Write-Host "Successfully uninstalled FastLinq PowerKit.`n" -ForegroundColor Green

    #--------------------------------------------------------------------------------------------------
    # Script - REST API Uninstall
    if ($restIsInstalled) {
        Remove-ProviderAppxProvisionedPackage -AppxDisplayName 'QLGCProviderREST'
        Remove-RESTFilesFromProgramData
        Remove-AppxPackageWrapper -AppxDisplayName 'QLGCProviderREST'
        Remove-FromIIS
        Write-Host 'Successfully uninstalled FastLinq REST API PowerKit.' -ForegroundColor Green
    }
}

Export-ModuleMember -function UnInstall-PowerKit