-
-
Save nohwnd/5c07fe62c861ee563f69c9ee1f7c9688 to your computer and use it in GitHub Desktop.
#Requires -RunAsAdministrator | |
function Uninstall-Pester ([switch]$All) { | |
if ([IntPtr]::Size * 8 -ne 64) { throw "Run this script from 64bit PowerShell." } | |
#Requires -RunAsAdministrator | |
$pesterPaths = foreach ($programFiles in ($env:ProgramFiles, ${env:ProgramFiles(x86)})) { | |
$path = "$programFiles\WindowsPowerShell\Modules\Pester" | |
if ($null -ne $programFiles -and (Test-Path $path)) { | |
if ($All) { | |
Get-Item $path | |
} | |
else { | |
Get-ChildItem "$path\3.*" | |
} | |
} | |
} | |
if (-not $pesterPaths) { | |
"There are no Pester$(if (-not $all) {" 3"}) installations in Program Files and Program Files (x86) doing nothing." | |
return | |
} | |
foreach ($pesterPath in $pesterPaths) { | |
takeown /F $pesterPath /A /R | |
icacls $pesterPath /reset | |
# grant permissions to Administrators group, but use SID to do | |
# it because it is localized on non-us installations of Windows | |
icacls $pesterPath /grant "*S-1-5-32-544:F" /inheritance:d /T | |
Remove-Item -Path $pesterPath -Recurse -Force -Confirm:$false | |
} | |
} | |
Uninstall-Pester |
Not sure if this makes it any 'cleaner' but here's my approach to finding any pre-existing path as we also were finding Pester in multiple folder locations especially if someone had also installed PowerShell v7:
$modules = Get-Module -Name Pester -ListAvailable
$pesterPaths = (get-item $modules.modulebase).parent.Fullname | Sort-Object -Unique
foreach ($pesterPath in $pesterPaths) {
....
}
@clemmesserli wouldn't this also take any version in the users profile directory too?
One thought to make the 64 bit/admin transition smoother, replace the top #Requires -RunAsAdministrator with this:
$isAdmin = (New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if ( ( ( $pshome -like "*syswow64*" ) -and ( ( Get-WmiObject Win32_OperatingSystem ).OSArchitecture -like "64*" ) ) -or -not $isAdmin ) {
write-warning "Restarting script under 64 bit powershell as admin"
# relaunch this script under 64 bit shell as adminstrator
$CommandLine = "-NoLogo -NoProfile -NoExit -File `"$( $MyInvocation.MyCommand.Path )`" $( $MyInvocation.UnboundArguments )"
Start-Process -FilePath "$( $pshome -replace "syswow64", "System32" )\powershell.exe" -Verb Runas -ArgumentList $CommandLine
# This will exit the original powershell process. This will only be done in case of an x86 process on a x64 OS.
exit
}
And delete the second #Requires -RunAsAdministrator
Grabbed this from https://gist.github.com/talatham/ad406d5428ccec641f075a7019cd29a8 and added the -Verb parameter.
@jcoryatjr Note that your version would fail on any 32-bit only systems. While it should be rare to nonexistent, it is a possibility to consider.
@jasonrush good point. I spent some time and refactored into a true cmdlet using advanced function syntax. The module name is Utils and must be installed in a location located within $env:PSModulePath. The file structure is:
- Utils
- Utils.psd1
- Utils.psm1
- /Public
- Uninstall-Pester.ps1
- /Private
The Utils.psd1
@{
ModuleVersion = "1.0.0"
GUID = "e38b14a6-0d85-4be5-869e-38ed7e270126"
Author = "Your Name Here"
CompanyName = "My Company"
Copyright = "(c) 2021 My Company All rights reserved."
RootModule = "Utils.psm1"
}
Utils.ps1 file
Get-ChildItem -Filter *.ps1 -Path "$PSScriptRoot\public","$PSScriptRoot\private" -Recurse | ForEach-Object { . $_.FullName; Write-Verbose "Loaded $_.BaseName" }
Get-ChildItem -Filter *.ps1 -Path "$PSScriptRoot\public" -Recurse | ForEach-Object { Export-ModuleMember $_.BaseName; Write-Verbose "Exported $_.BaseName" }
Uninstall-Pester.ps1 file
function Uninstall-Pester {
[CmdletBinding()]
[OutputType([ bool ])]
param(
[Parameter()]
[switch]
$All = $false
)
begin {
try {
Write-Verbose -Message "[$(( Get-Date ).TimeOfDay )][$( $MyInvocation.MyCommand )]-Begin Enter"
$result = $true
$pesterPath = 'WindowsPowerShell\Modules\Pester'
if ( -not $All ) {
$pesterPath += '\3.*'
}
# See if there is anything to do
$paths = @()
foreach ( $path in @(${env:ProgramFiles}, ${env:ProgramFiles(x86)} ) ) {
if ( $path -and ( Test-Path -Path "$path\$pesterPath" ) ) {
$paths += ( Get-ChildItem -Path "$path\$pesterPath" -Directory -ErrorAction SilentlyContinue ).FullName
}
}
if ( -not $paths.Count ) {
Write-Warning "There are no Pester$( if ( -not $All ) { " 3" } ) installations in Program Files and Program Files (x86)"
$result = $false
return
}
$isAdmin = (New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
$is32BitProcess = $pshome -like "*syswow64*"
$is64BitOS = ( Get-WmiObject Win32_OperatingSystem ).OSArchitecture -like "64*"
$filePath = $null
switch ( $true ) {
{ ( $is32BitProcess -and -not $is64BitOS ) -or ( -not $isAdmin -and $is64BitOS ) } {
Write-Warning "Restarting script under 64 bit powershell as admin"
# relaunch this script under 64 bit shell as adminstrator
$filePath = "$( $pshome -replace "syswow64", "System32" )\powershell.exe"
break
}
{ -not $isAdmin } {
Write-Warning "Restarting script using admin privs"
$filePath = 'powershell.exe'
}
}
if ( $filePath ) {
Start-Process -FilePath $filePath -Verb RunAs -ArgumentList "-NoLogo -NoExit -Command `" Import-Module -name Utils; Uninstall-Pester $( if( $All ) { "-All" } ) `""
$result = $false
return
}
}
catch {
$result = $false
Write-Verbose -Message "[$(( Get-Date ).TimeOfDay )][$( $MyInvocation.MyCommand )] Exception:`r`n$_"
throw $_
}
finally {
Write-Verbose -Message "[$(( Get-Date ).TimeOfDay )][$( $MyInvocation.MyCommand )]-Begin Exit"
}
}
process {
try {
Write-Verbose -Message "[$(( Get-Date ).TimeOfDay )][$( $MyInvocation.MyCommand )]-Process Enter"
if ( -not $result ) {
return
}
foreach ($path in $paths) {
takeown /F $path /A /R
icacls $path /reset
# grant permissions to Administrators group, but use SID to do
# it because it is localized on non-us installations of Windows
icacls $path /grant "*S-1-5-32-544:F" /inheritance:d /T
Remove-Item -Path $path -Recurse -Force -Confirm:$false -ErrorAction SilentlyContinue
}
}
catch {
$result = $false
Write-Verbose -Message "[$(( Get-Date ).TimeOfDay )][$( $MyInvocation.MyCommand )] Exception:`r`n$_"
throw $_
}
finally {
Write-Verbose -Message "[$(( Get-Date ).TimeOfDay )][$( $MyInvocation.MyCommand )]-Process Exit"
}
}
end {
try {
Write-Verbose -Message "[$(( Get-Date ).TimeOfDay )][$( $MyInvocation.MyCommand )]-End Enter"
return $result
}
catch {
Write-Verbose -Message "[$(( Get-Date ).TimeOfDay )][$( $MyInvocation.MyCommand )] Exception:`r`n$_"
throw $_
}
finally {
Write-Verbose -Message "[$(( Get-Date ).TimeOfDay )][$( $MyInvocation.MyCommand )]-End Exit"
}
}
}
@jcoryatjr my version is geared more towards non-interactive use. So I like that it fails when you are not admin. But thanks for sharing, hopefully someone will find it useful.
@jasonrush good point. I spent some time and refactored into a true cmdlet using advanced function syntax. The module name is Utils and must be installed in a location located within $env:PSModulePath. The file structure is:
Utils
Utils.psd1
Utils.psm1
/Public
- Uninstall-Pester.ps1
/Private
The Utils.psd1
@{ ModuleVersion = "1.0.0" GUID = "e38b14a6-0d85-4be5-869e-38ed7e270126" Author = "Your Name Here" CompanyName = "My Company" Copyright = "(c) 2021 My Company All rights reserved." RootModule = "Utils.psm1" }
Utils.ps1 file
Get-ChildItem -Filter *.ps1 -Path "$PSScriptRoot\public","$PSScriptRoot\private" -Recurse | ForEach-Object { . $_.FullName; Write-Verbose "Loaded $_.BaseName" } Get-ChildItem -Filter *.ps1 -Path "$PSScriptRoot\public" -Recurse | ForEach-Object { Export-ModuleMember $_.BaseName; Write-Verbose "Exported $_.BaseName" }
Uninstall-Pester.ps1 file
function Uninstall-Pester { [CmdletBinding()] [OutputType([ bool ])] param( [Parameter()] [switch] $All = $false ) begin { try { Write-Verbose -Message "[$(( Get-Date ).TimeOfDay )][$( $MyInvocation.MyCommand )]-Begin Enter" $result = $true $pesterPath = 'WindowsPowerShell\Modules\Pester' if ( -not $All ) { $pesterPath += '\3.*' } # See if there is anything to do $paths = @() foreach ( $path in @(${env:ProgramFiles}, ${env:ProgramFiles(x86)} ) ) { if ( $path -and ( Test-Path -Path "$path\$pesterPath" ) ) { $paths += ( Get-ChildItem -Path "$path\$pesterPath" -Directory -ErrorAction SilentlyContinue ).FullName } } if ( -not $paths.Count ) { Write-Warning "There are no Pester$( if ( -not $All ) { " 3" } ) installations in Program Files and Program Files (x86)" $result = $false return } $isAdmin = (New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) $is32BitProcess = $pshome -like "*syswow64*" $is64BitOS = ( Get-WmiObject Win32_OperatingSystem ).OSArchitecture -like "64*" $filePath = $null switch ( $true ) { { ( $is32BitProcess -and -not $is64BitOS ) -or ( -not $isAdmin -and $is64BitOS ) } { Write-Warning "Restarting script under 64 bit powershell as admin" # relaunch this script under 64 bit shell as adminstrator $filePath = "$( $pshome -replace "syswow64", "System32" )\powershell.exe" break } { -not $isAdmin } { Write-Warning "Restarting script using admin privs" $filePath = 'powershell.exe' } } if ( $filePath ) { Start-Process -FilePath $filePath -Verb RunAs -ArgumentList "-NoLogo -NoExit -Command `" Import-Module -name Utils; Uninstall-Pester $( if( $All ) { "-All" } ) `"" $result = $false return } } catch { $result = $false Write-Verbose -Message "[$(( Get-Date ).TimeOfDay )][$( $MyInvocation.MyCommand )] Exception:`r`n$_" throw $_ } finally { Write-Verbose -Message "[$(( Get-Date ).TimeOfDay )][$( $MyInvocation.MyCommand )]-Begin Exit" } } process { try { Write-Verbose -Message "[$(( Get-Date ).TimeOfDay )][$( $MyInvocation.MyCommand )]-Process Enter" if ( -not $result ) { return } foreach ($path in $paths) { takeown /F $path /A /R icacls $path /reset # grant permissions to Administrators group, but use SID to do # it because it is localized on non-us installations of Windows icacls $path /grant "*S-1-5-32-544:F" /inheritance:d /T Remove-Item -Path $path -Recurse -Force -Confirm:$false -ErrorAction SilentlyContinue } } catch { $result = $false Write-Verbose -Message "[$(( Get-Date ).TimeOfDay )][$( $MyInvocation.MyCommand )] Exception:`r`n$_" throw $_ } finally { Write-Verbose -Message "[$(( Get-Date ).TimeOfDay )][$( $MyInvocation.MyCommand )]-Process Exit" } } end { try { Write-Verbose -Message "[$(( Get-Date ).TimeOfDay )][$( $MyInvocation.MyCommand )]-End Enter" return $result } catch { Write-Verbose -Message "[$(( Get-Date ).TimeOfDay )][$( $MyInvocation.MyCommand )] Exception:`r`n$_" throw $_ } finally { Write-Verbose -Message "[$(( Get-Date ).TimeOfDay )][$( $MyInvocation.MyCommand )]-End Exit" } } }
Thanks your script worked out for to uninstall the module. And installing manually the newer version.
Thanks, helped me with this problem.
Doubt that.