From cfd0bf4b1ecfb742c0031b84bf1c93c0428e7b37 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 9 Dec 2021 14:26:46 +0100 Subject: [PATCH 1/6] Add the `Remove-PoshGitFromProfile` function This is needed to be able to install/uninstall Posh-Git via Git for Windows' installer/uninstaller. See https://github.com/git-for-windows/build-extra/pull/401 for details. Signed-off-by: Johannes Schindelin --- src/Utils.ps1 | 117 +++++++++++++++++++++++++++++++++++++++++++ src/posh-git.psd1 | 1 + src/posh-git.psm1 | 1 + test/Utils.Tests.ps1 | 21 ++++++++ 4 files changed, 140 insertions(+) diff --git a/src/Utils.ps1 b/src/Utils.ps1 index 3756a84d6..2d660343d 100644 --- a/src/Utils.ps1 +++ b/src/Utils.ps1 @@ -216,6 +216,123 @@ function Add-PoshGitToProfile { } } +<# +.SYNOPSIS + Modifies your PowerShell profile (startup) script so that it does not import + the posh-git module when PowerShell starts. +.DESCRIPTION + Checks if your PowerShell profile script is importing posh-git and if it does, + removes the command to import the posh-git module. This will cause PowerShell + to no longer load posh-git whenever PowerShell starts. +.PARAMETER AllHosts + By default, this command modifies the CurrentUserCurrentHost profile + script. By specifying the AllHosts switch, the command updates the + CurrentUserAllHosts profile (or AllUsersAllHosts, given -AllUsers). +.PARAMETER AllUsers + By default, this command modifies the CurrentUserCurrentHost profile + script. By specifying the AllUsers switch, the command updates the + AllUsersCurrentHost profile (or AllUsersAllHosts, given -AllHosts). + Requires elevated permissions. +.EXAMPLE + PS C:\> Remove-PoshGitFromProfile + Updates your profile script for the current PowerShell host to stop importing + the posh-git module when the current PowerShell host starts. +.EXAMPLE + PS C:\> Remove-PoshGitFromProfile -AllHosts + Updates your profile script for all PowerShell hosts to no longer import the + posh-git module whenever any PowerShell host starts. +.INPUTS + None. +.OUTPUTS + None. +#> +function Remove-PoshGitFromProfile { + [CmdletBinding(SupportsShouldProcess)] + param( + [Parameter()] + [switch] + $AllHosts, + + [Parameter()] + [switch] + $AllUsers, + + [Parameter(ValueFromRemainingArguments)] + [psobject[]] + $TestParams + ) + + if ($AllUsers -and !(Test-Administrator)) { + throw 'Removing posh-git from an AllUsers profile requires an elevated host.' + } + + $underTest = $false + + $profileName = $(if ($AllUsers) { 'AllUsers' } else { 'CurrentUser' }) ` + + $(if ($AllHosts) { 'AllHosts' } else { 'CurrentHost' }) + Write-Verbose "`$profileName = '$profileName'" + + $profilePath = $PROFILE.$profileName + Write-Verbose "`$profilePath = '$profilePath'" + + # Under test, we override some variables using $args as a backdoor. + if (($TestParams.Count -gt 0) -and ($TestParams[0] -is [string])) { + $profilePath = [string]$TestParams[0] + $underTest = $true + if ($TestParams.Count -gt 1) { + $ModuleBasePath = [string]$TestParams[1] + } + } + + if (!$profilePath) { $profilePath = $PROFILE } + + if (!$profilePath) { + Write-Warning "Skipping add of posh-git import to profile; no profile found." + Write-Verbose "`$PROFILE = '$PROFILE'" + Write-Verbose "CurrentUserCurrentHost = '$($PROFILE.CurrentUserCurrentHost)'" + Write-Verbose "CurrentUserAllHosts = '$($PROFILE.CurrentUserAllHosts)'" + Write-Verbose "AllUsersCurrentHost = '$($PROFILE.AllUsersCurrentHost)'" + Write-Verbose "AllUsersAllHosts = '$($PROFILE.AllUsersAllHosts)'" + return + } + + if (Test-Path -LiteralPath $profilePath) { + # If the profile script exists and is signed, then we should not modify it + if (!(Get-Command Get-AuthenticodeSignature -ErrorAction SilentlyContinue)) + { + Write-Verbose "Platform doesn't support script signing, skipping test for signed profile." + } + else { + $sig = Get-AuthenticodeSignature $profilePath + if ($null -ne $sig.SignerCertificate) { + Write-Warning "Skipping add of posh-git import to profile; '$profilePath' appears to be signed." + Write-Warning "Add the command 'Import-Module posh-git' to your profile and resign it." + return + } + } + + $oldProfile = @(Get-Content $profilePath) + + . $currentVersionPath\src\Utils.ps1 + $oldProfileEncoding = Get-FileEncoding $profilePath + + $newProfile = @() + foreach($line in $oldProfile) { + if ($line -like '*PoshGitPrompt*') { continue; } + if ($line -like '*Load posh-git example profile*') { continue; } + + if($line -like '. *posh-git*profile.example.ps1*') { + continue; + } + if($line -like 'Import-Module *\posh-git.psd1*') { + continue; + } + $newProfile += $line + } + Set-Content -path $profilePath -value $newProfile -Force -Encoding $oldProfileEncoding + } +} + <# .SYNOPSIS Gets the file encoding of the specified file. diff --git a/src/posh-git.psd1 b/src/posh-git.psd1 index 72b760e7c..50c63728d 100644 --- a/src/posh-git.psd1 +++ b/src/posh-git.psd1 @@ -33,6 +33,7 @@ FunctionsToExport = @( 'Get-PromptPath', 'New-GitPromptSettings', 'Remove-GitBranch', + 'Remove-PoshGitFromProfile', 'Update-AllBranches', 'Write-GitStatus', 'Write-GitBranchName', diff --git a/src/posh-git.psm1 b/src/posh-git.psm1 index 7324774fd..fad6ca185 100644 --- a/src/posh-git.psm1 +++ b/src/posh-git.psm1 @@ -171,6 +171,7 @@ $exportModuleMemberParams = @{ 'Get-PromptPath', 'New-GitPromptSettings', 'Remove-GitBranch', + 'Remove-PoshGitFromProfile', 'Update-AllBranches', 'Write-GitStatus', 'Write-GitBranchName', diff --git a/test/Utils.Tests.ps1 b/test/Utils.Tests.ps1 index 3360a4781..80be899f8 100644 --- a/test/Utils.Tests.ps1 +++ b/test/Utils.Tests.ps1 @@ -101,6 +101,27 @@ New-Alias pscore C:\Users\Keith\GitHub\rkeithhill\PowerShell\src\powershell-win- $expectedContent += "${newLine}${newLine}Import-Module '$(Join-Path $moduleBasePath posh-git).psd1'" $content -join $newLine | Should -BeExactly $expectedContent } + It 'Removes import from the profile correctly' { + $profileContent = @' +Import-Module PSCX +'@ + Set-Content $profilePath -Value $profileContent -Encoding Ascii + + $moduleBasePath = Split-Path $profilePath -Parent + Add-PoshGitToProfile $profilePath $moduleBasePath + + $output = Remove-PoshGitFromProfile $profilePath 3>&1 + + Write-Host "output: $output" + $output.Length | Should -Be 0 + Get-FileEncoding $profilePath | Should -Be 'ascii' + $content = Get-Content $profilePath + $content.Count | Should -Be 2 + $content[0] | Should -BeExactly $profileContent + $content[1] | Should -BeExactly '' + $expectedContent = Convert-NativeLineEnding $profileContent + $content -join "" | Should -BeExactly $expectedContent + } } Context 'Get-PromptConnectionInfo' { From 8fe7e5ac0c6c9cda0540455418cdba64fb3f2cad Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Thu, 31 Mar 2022 01:51:18 -0500 Subject: [PATCH 2/6] Adjust warnings --- src/Utils.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Utils.ps1 b/src/Utils.ps1 index 2d660343d..9d2976ef0 100644 --- a/src/Utils.ps1 +++ b/src/Utils.ps1 @@ -287,7 +287,7 @@ function Remove-PoshGitFromProfile { if (!$profilePath) { $profilePath = $PROFILE } if (!$profilePath) { - Write-Warning "Skipping add of posh-git import to profile; no profile found." + Write-Warning "Skipping removal of posh-git import from profile; no profile found." Write-Verbose "`$PROFILE = '$PROFILE'" Write-Verbose "CurrentUserCurrentHost = '$($PROFILE.CurrentUserCurrentHost)'" Write-Verbose "CurrentUserAllHosts = '$($PROFILE.CurrentUserAllHosts)'" @@ -305,8 +305,8 @@ function Remove-PoshGitFromProfile { else { $sig = Get-AuthenticodeSignature $profilePath if ($null -ne $sig.SignerCertificate) { - Write-Warning "Skipping add of posh-git import to profile; '$profilePath' appears to be signed." - Write-Warning "Add the command 'Import-Module posh-git' to your profile and resign it." + Write-Warning "Skipping removal of posh-git import from profile; '$profilePath' appears to be signed." + Write-Warning "Remove the command 'Import-Module posh-git' from your profile and resign it." return } } From 1296dd302156a2f888ff06c8374e8c6b090668aa Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Thu, 31 Mar 2022 01:57:46 -0500 Subject: [PATCH 3/6] Drop self-import --- src/Utils.ps1 | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Utils.ps1 b/src/Utils.ps1 index 9d2976ef0..e96eafab2 100644 --- a/src/Utils.ps1 +++ b/src/Utils.ps1 @@ -312,8 +312,6 @@ function Remove-PoshGitFromProfile { } $oldProfile = @(Get-Content $profilePath) - - . $currentVersionPath\src\Utils.ps1 $oldProfileEncoding = Get-FileEncoding $profilePath $newProfile = @() From 5454d1c59ed3dc3f5cbb4d377e6a3bcd71278f40 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Thu, 31 Mar 2022 02:28:54 -0500 Subject: [PATCH 4/6] Split out new Context --- test/Utils.Tests.ps1 | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/Utils.Tests.ps1 b/test/Utils.Tests.ps1 index 80be899f8..1bde38879 100644 --- a/test/Utils.Tests.ps1 +++ b/test/Utils.Tests.ps1 @@ -101,6 +101,20 @@ New-Alias pscore C:\Users\Keith\GitHub\rkeithhill\PowerShell\src\powershell-win- $expectedContent += "${newLine}${newLine}Import-Module '$(Join-Path $moduleBasePath posh-git).psd1'" $content -join $newLine | Should -BeExactly $expectedContent } + } + + Context 'Remove-PoshGitFromProfile Tests' { + BeforeAll { + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssigments', '')] + $newLine = [System.Environment]::NewLine + } + BeforeEach { + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssigments', '')] + $profilePath = [System.IO.Path]::GetTempFileName() + } + AfterEach { + Remove-Item $profilePath -Recurse -ErrorAction SilentlyContinue + } It 'Removes import from the profile correctly' { $profileContent = @' Import-Module PSCX From 8ed98be393e4ca81dfb178b1b1baca69abf47a3e Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Thu, 31 Mar 2022 02:29:10 -0500 Subject: [PATCH 5/6] Format --- test/Utils.Tests.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/Utils.Tests.ps1 b/test/Utils.Tests.ps1 index 1bde38879..a300bc52d 100644 --- a/test/Utils.Tests.ps1 +++ b/test/Utils.Tests.ps1 @@ -18,7 +18,7 @@ Describe 'Utils Function Tests' { } It 'Creates profile file if it does not exist that imports absolute path' { Mock Get-PSModulePath { - return @() + return @() } Remove-Item -LiteralPath $profilePath Test-Path -LiteralPath $profilePath | Should -Be $false @@ -150,7 +150,8 @@ Import-Module PSCX AfterEach { if ($ssh_connection) { Set-Item Env:SSH_CONNECTION $ssh_connection - } elseif (Test-Path Env:SSH_CONNECTION) { + } + elseif (Test-Path Env:SSH_CONNECTION) { Remove-Item Env:SSH_CONNECTION } } From c6f4a64f363d6208d3ad325513cf004cef83daaf Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Thu, 31 Mar 2022 02:29:28 -0500 Subject: [PATCH 6/6] Try to simplify assert --- test/Utils.Tests.ps1 | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/test/Utils.Tests.ps1 b/test/Utils.Tests.ps1 index a300bc52d..0f77383b0 100644 --- a/test/Utils.Tests.ps1 +++ b/test/Utils.Tests.ps1 @@ -118,6 +118,8 @@ New-Alias pscore C:\Users\Keith\GitHub\rkeithhill\PowerShell\src\powershell-win- It 'Removes import from the profile correctly' { $profileContent = @' Import-Module PSCX + +# import posh-git here: '@ Set-Content $profilePath -Value $profileContent -Encoding Ascii @@ -129,12 +131,8 @@ Import-Module PSCX Write-Host "output: $output" $output.Length | Should -Be 0 Get-FileEncoding $profilePath | Should -Be 'ascii' - $content = Get-Content $profilePath - $content.Count | Should -Be 2 - $content[0] | Should -BeExactly $profileContent - $content[1] | Should -BeExactly '' - $expectedContent = Convert-NativeLineEnding $profileContent - $content -join "" | Should -BeExactly $expectedContent + $content = Get-Content $profilePath -Raw + $content | Should -Be "$profileContent${newline}" } }