UninstallFastLinqPowerKit.psm1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
# Script level parameters
Param (
    [Switch] $UninstallRESTServerOnly = $false
)

# 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-IfServerCore {
    # Check if OS is Server Core
    $regKey = 'hklm:/software/microsoft/windows nt/currentversion'
    return (Get-ItemProperty $regKey).InstallationType -eq 'Server Core'
}

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.

    if ($Script:isServerCore) {
        $appxCmdletsPath = "$env:ProgramFiles\QLogic Corporation\PowerKit\Cmdlets"
    } else {
        $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
    if ($Script:isServerCore) {
        $mofCompFilePath = "$env:ProgramFiles\QLogic Corporation\PowerKit\QLGCProviderUninstall.mof"
    } else {
        $mofCompFilePath = (Get-AppxPackageWrapper -AppxName 'QLGCProvider').InstallLocation
        $mofCompFilePath += '\QLGCProviderUninstall.mof'
    }

    # $mofcompOutput = & mofcomp.exe -N:root\qlgcfastlinq -class:forceupdate $appxPath\QLGCProviderUninstall.mof 2>&1
    $mofcompOutput = & mofcomp.exe -N:root\qlgcfastlinq $mofCompFilePath 2>&1
    if ($mofcompOutput -match 'Error') {
        Write-Host "Failed to unregister `"$mofCompFilePath`": $($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-CmdletsFromProgramFiles {
    Remove-Item -Path "$env:ProgramFiles\QLogic Corporation\PowerKit" -Recurse -Force 2>&1 | Out-Null
}

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 Test-LastExitCode {
    Param (
        [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] $ExitCode,
        [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] $Message,
        [Parameter(Mandatory=$false)] [AllowNull()] [Switch] $ExitScriptIfBadErrorCode
    )
    if ($ExitCode -eq 0) { return; }

    if (-not $ExitScriptIfBadErrorCode) {
        Write-Host "WARNING: $Message" -ForegroundColor Yellow
    } else {
        Write-Host "ERROR: $Message" -ForegroundColor Red
        Exit
    }
}

Function UnInstall-PowerKit {
# Encapulate uninstaller logic here
#--------------------------------------------------------------------------------------------------
# Globals
$Script:CLSID = '{BC33E6C0-DB6A-4781-B924-CB1CDA88E4A1}'
$Script:isNano = Test-IfNano
$Script:isServerCore = Test-IfServerCore

#--------------------------------------------------------------------------------------------------
# Script - Cmdlets Uninstall
if (-not $UninstallRESTServerOnly) {
    if ($Script:isServerCore) {
        Remove-CmdletsPathFromPSModulePath
        Remove-CLSIDRegistryPaths
        Uninstall-MofComp
        Remove-CmdletsFromProgramFiles
    } else {
        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 - Old REST API Uninstall
$oldRestIsInstalled = (Get-AppxPackage | Where-Object { $_.Name -eq 'QLGCProviderREST' }) -ne $null
if ($oldRestIsInstalled) {
    Remove-ProviderAppxProvisionedPackage -AppxDisplayName 'QLGCProviderREST'
    Remove-RESTFilesFromProgramData
    Remove-AppxPackageWrapper -AppxDisplayName 'QLGCProviderREST'
    Remove-FromIIS
    Write-Host 'Successfully uninstalled FastLinq REST API PowerKit.' -ForegroundColor Green
}

#--------------------------------------------------------------------------------------------------
# Script - New REST API Uninstall
$restServerRegistryPath = 'HKLM:\Software\QLogic Corporation\PowerShell Cmdlets REST Server'
if (Test-Path -Path $restServerRegistryPath) {

    # Check if running inside a container
    $runningInContainer = $env:USERNAME -eq 'ContainerAdministrator' -and $env:USERDOMAIN -eq 'User Manager'

    # Get values from registry
    $restServerInstallPath = (Get-ItemProperty -Path $restServerRegistryPath).path
    $restServerProtocol = (Get-ItemProperty -Path $restServerRegistryPath).protocol
    $restServerHttpPort = (Get-ItemProperty -Path $restServerRegistryPath).http_port
    $restServerHttpsPort = (Get-ItemProperty -Path $restServerRegistryPath).https_port
    $restServerThumbprint = (Get-ItemProperty -Path $restServerRegistryPath).thumbprint

    # Uninstall Windows service
    Write-Host "`nUninstalling Windows service" -ForegroundColor Cyan
    $null = & "$restServerInstallPath\PowerShellCmdletsRestServer.exe" -uninstall
    Test-LastExitCode -ExitCode $LASTEXITCODE -Message "Failed to uninstall Windows service" -ExitScriptIfBadErrorCode


    # Wait for service to stop before continuing
    Write-Host "`nWaiting for service to stop before continuing." -ForegroundColor Cyan
    $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
    $timeoutSecs = 60
    while ($true) {
        Start-Sleep -Milliseconds 2500
        $service = Get-Service -Name $restServerServiceName -ErrorAction SilentlyContinue
        if ($service -eq $null) {
            Write-Host "... service not found with name '$restServerServiceName'; assuming it was successfully deleted." -ForegroundColor Cyan
            break;
        }
        if ($service -ne $null -and $service.Status -eq 'Stopped') {
            Write-Host '... service stopped!' -ForegroundColor Cyan
            break;
        }
        if ($stopwatch.Elapsed.TotalSeconds -gt $timeoutSecs) {
            Test-LastExitCode -ExitCode 1 -Message "`n$restServerServiceName service never stopped after $timeoutSecs seconds; giving up." -ExitScriptIfBadErrorCode
        }
        Write-Host 'Still waiting for service to stop ...' -ForegroundColor Cyan
    }


    # Delete installation directory
    Write-Host "`nDeleting installation directory" -ForegroundColor Cyan
    Remove-Item -Path $restServerInstallPath -Recurse -Force

    if ($restServerProtocol -eq 'http' -or $restServerProtocol -eq 'both') {
        # Unregister URL with Windows
        Write-Host "`nUnregistering HTTP URL with Windows" -ForegroundColor Cyan
        $null = netsh http delete urlacl url="http://localhost:$restServerHttpPort/"
        Test-LastExitCode -ExitCode $LASTEXITCODE -Message "Failed to unregister HTTP URL with Windows."
    }

    if ($restServerProtocol -eq 'https' -or $restServerProtocol -eq 'both') {
        
        # Unregister URL with Windows
        Write-Host "`nUnregistering HTTPS URL with Windows" -ForegroundColor Cyan
        $null = netsh http delete urlacl url="https://localhost:$restServerHttpsPort/"
        Test-LastExitCode -ExitCode $LASTEXITCODE -Message "Failed to unregister HTTPS URL with Windows."
        $null = netsh http delete sslcert ipport="0.0.0.0:$restServerHttpsPort"
        
        # Delete certificate
        if ($restServerThumbprint -ne $null) {
            Write-Host "`nDeleting HTTPS certificate" -ForegroundColor Cyan
            dir Cert:\LocalMachine -Recurse | ? Thumbprint -Match $restServerThumbprint | Remove-Item
        } else {
            Write-Host "`nNOT deleting HTTPS certificate" -ForegroundColor Cyan
        }
    }

    # Delete Windows registry entries
    if (Test-Path -Path $restServerRegistryPath) {
        Write-Host "`nDeleting Windows registry entries" -ForegroundColor Cyan
        Remove-Item -Path $restServerRegistryPath -Recurse
    }

    # Remove any existing firewall rules
    if (-not $runningInContainer) {
        $fwRules = Get-NetFirewallRule | Where-Object { ($_.DisplayName).StartsWith('QLogic PowerShell Cmdlets REST Server') }
        foreach ($fwRule in $fwRules) {
            Remove-NetFirewallRule -DisplayName $fwRule.DisplayName
        }
    }
    Write-Host "`nSuccessfully uninstalled FastLinq PowerKit REST Server." -ForegroundColor Green
}
else {
    Write-Host 'Could not uninstall REST server because it does not seem to be installed.' -ForegroundColor Red
}

}

Export-ModuleMember -function UnInstall-PowerKit