diff --git a/src/Utils.ps1 b/src/Utils.ps1 index 3756a84d6..e96eafab2 100644 --- a/src/Utils.ps1 +++ b/src/Utils.ps1 @@ -216,6 +216,121 @@ 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 removal of posh-git import from 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 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 + } + } + + $oldProfile = @(Get-Content $profilePath) + $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 b80170182..06e45159a 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..0f77383b0 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 @@ -103,6 +103,39 @@ New-Alias pscore C:\Users\Keith\GitHub\rkeithhill\PowerShell\src\powershell-win- } } + 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 + +# import posh-git here: +'@ + 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 -Raw + $content | Should -Be "$profileContent${newline}" + } + } + Context 'Get-PromptConnectionInfo' { BeforeEach { if (Test-Path Env:SSH_CONNECTION) { @@ -115,7 +148,8 @@ New-Alias pscore C:\Users\Keith\GitHub\rkeithhill\PowerShell\src\powershell-win- 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 } }