Skip to content

Commit

Permalink
🩹 [Patch]: Support wildcard on Name for Uninstall-Font (#25)
Browse files Browse the repository at this point in the history
## Description

- Support wildcard on `Name` for `Uninstall-Font`

## Type of change

<!-- Use the check-boxes [x] on the options that are relevant. -->

- [ ] 📖 [Docs]
- [ ] 🪲 [Fix]
- [x] 🩹 [Patch]
- [ ] ⚠️ [Security fix]
- [ ] 🚀 [Feature]
- [ ] 🌟 [Breaking change]

## Checklist

<!-- Use the check-boxes [x] on the options that are relevant. -->

- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
  • Loading branch information
MariusStorhaug authored Apr 6, 2024
1 parent 71eb227 commit 542d2d4
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 79 deletions.
38 changes: 38 additions & 0 deletions src/private/common.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,41 @@ $script:OS = if ([System.Environment]::OSVersion.Platform -eq 'Win32NT') {
} else {
throw 'Unsupported OS'
}

$script:SupportedFonts = @(
[pscustomobject]@{
Extension = '.ttf'
Type = 'TrueType'
Description = 'TrueType Font'
}
[pscustomobject]@{
Extension = '.otf'
Type = 'OpenType'
Description = 'OpenType Font'
}
[pscustomobject]@{
Extension = '.ttc'
Type = 'TrueType'
Description = 'TrueType Font Collection'
}
[pscustomobject]@{
Extension = '.pfb'
Type = 'PostScript Type 1'
Description = 'PostScript Type 1 Font'
}
[pscustomobject]@{
Extension = '.pfm'
Type = 'PostScript Type 1'
Description = 'PostScript Type 1 Outline Font'
}
[pscustomobject]@{
Extension = '.woff'
Type = 'Web Open Font Format'
Description = 'Web Open Font Format'
}
[pscustomobject]@{
Extension = '.woff2'
Type = 'Web Open Font Format 2'
Description = 'Web Open Font Format 2'
}
)
3 changes: 1 addition & 2 deletions src/public/Get-Font.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,7 @@
Write-Verbose "[$functionName] - [$scopeName] - Filtering based on [$nameCount] name pattern(s)"
foreach ($fontFilter in $Name) {
Write-Verbose "[$functionName] - [$scopeName] - [$fontFilter] - Filtering font(s)"
$filteredFonts = $installedFonts | Where-Object { $_.Name -like "*$fontFilter*" }

$filteredFonts = $installedFonts | Where-Object { $_.BaseName -like $fontFilter }
foreach ($fontItem in $filteredFonts) {
$fontName = $fontItem.BaseName
$fontPath = $fontItem.FullName
Expand Down
18 changes: 9 additions & 9 deletions src/public/Install-Font.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,14 @@ Please run the command again with elevated rights (Run as Administrator) or prov
$fontFilePath = $fontFile.FullName
Write-Verbose "[$functionName] - [$scopeName] - [$fontFilePath] - Processing"

# Check if font is supported
$fontExtension = $fontFile.Extension.ToLower()
$supportedFont = $script:SupportedFonts | Where-Object { $_.Extension -eq $fontExtension }
if (-not $supportedFont) {
Write-Verbose "[$functionName] - [$scopeName] - [$fontFilePath] - Font type [$fontExtension] is not supported. Skipping."
continue
}

$folderExists = Test-Path -Path $fontDestinationFolderPath -ErrorAction SilentlyContinue
if (-not $folderExists) {
Write-Verbose "[$functionName] - [$scopeName] - [$fontFilePath] - Creating folder [$fontDestinationFolderPath]"
Expand Down Expand Up @@ -174,15 +182,7 @@ Please run the command again with elevated rights (Run as Administrator) or prov
continue
}
if ($script:OS -eq 'Windows') {
$fontType = switch ($fontFile.Extension) {
'.ttf' { 'TrueType' } # TrueType Font
'.otf' { 'OpenType' } # OpenType Font
'.ttc' { 'TrueType' } # TrueType Font Collection
'.pfb' { 'PostScript Type 1' } # PostScript Type 1 Font
'.pfm' { 'PostScript Type 1' } # PostScript Type 1 Outline Font
'.woff' { 'Web Open Font Format' } # Web Open Font Format
'.woff2' { 'Web Open Font Format 2' } # Web Open Font Format 2
}
$fontType = $script:SupportedFonts | Where-Object { $_.Extension -eq $fontExtension } | Select-Object -ExpandProperty Type
$registeredFontName = "$fontName ($fontType)"
Write-Verbose "[$functionName] - [$scopeName] - [$fontFilePath] - Registering font as [$registeredFontName]"
$regValue = if ('AllUsers' -eq $Scope) { $fontFileName } else { $fontDestinationFilePath }
Expand Down
134 changes: 66 additions & 68 deletions src/public/Uninstall-Font.ps1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#Requires -Modules Admin, DynamicParams
#Requires -Modules Admin

function Uninstall-Font {
<#
Expand Down Expand Up @@ -31,32 +31,17 @@ function Uninstall-Font {
ValueFromPipeline,
ValueFromPipelineByPropertyName
)]
[Scope[]] $Scope = 'CurrentUser'
)

DynamicParam {
$paramDictionary = New-DynamicParamDictionary

$dynName = @{
Name = 'Name'
Type = [string[]]
Alias = @('FontName', 'Font')
Mandatory = $true
HelpMessage = 'Name of the font to uninstall.'
ValueFromPipeline = $true
ValueFromPipelineByPropertyName = $true
ValidationErrorMessage = "The font name provided was not found in the selected scope [$Scope]."
ValidateSet = if ([string]::IsNullOrEmpty($Scope)) {
(Get-Font -Scope 'CurrentUser' -Verbose:$false).Name
} else {
(Get-Font -Scope $Scope -Verbose:$false).Name
}
DynamicParamDictionary = $paramDictionary
}
New-DynamicParam @dynName
[Scope[]] $Scope = 'CurrentUser',

return $paramDictionary
}
# Name of the font to uninstall.
[Parameter(
Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName
)]
[SupportsWildcards()]
[string[]] $Name
)

begin {
$functionName = $MyInvocation.MyCommand.Name
Expand Down Expand Up @@ -85,54 +70,57 @@ Please run the command again with elevated rights (Run as Administrator) or prov
Write-Verbose "[$functionName] - [$scopeName] - Processing [$nameCount] font(s)"
foreach ($fontName in $Name) {
Write-Verbose "[$functionName] - [$scopeName] - [$fontName] - Processing"
$font = Get-Font -Name $fontName -Scope $Scope
Write-Verbose ($font | Out-String) -Verbose
$filePath = $font.Path

$fileExists = Test-Path -Path $filePath -ErrorAction SilentlyContinue
if (-not $fileExists) {
Write-Warning "[$functionName] - [$scopeName] - [$fontName] - File [$filePath] does not exist. Skipping."
} else {
Write-Verbose "[$functionName] - [$scopeName] - [$fontName] - Removing file [$filePath]"
$retryCount = 0
$fileRemoved = $false
do {
try {
Remove-Item -Path $filePath -Force -ErrorAction Stop
$fileRemoved = $true
} catch {
# Common error; 'file in use'. Usually VSCode or any web browser.
$retryCount++
if (-not $fileRemoved -and $retryCount -eq $maxRetries) {
Write-Error $_
Write-Error "Failed [$retryCount/$maxRetries] - Stopping"
break
$fonts = Get-Font -Name $fontName -Scope $Scope
Write-Verbose ($fonts | Out-String)
foreach ($font in $fonts) {

$filePath = $font.Path

$fileExists = Test-Path -Path $filePath -ErrorAction SilentlyContinue
if (-not $fileExists) {
Write-Warning "[$functionName] - [$scopeName] - [$fontName] - File [$filePath] does not exist. Skipping."
} else {
Write-Verbose "[$functionName] - [$scopeName] - [$fontName] - Removing file [$filePath]"
$retryCount = 0
$fileRemoved = $false
do {
try {
Remove-Item -Path $filePath -Force -ErrorAction Stop
$fileRemoved = $true
} catch {
# Common error; 'file in use'.
$retryCount++
if (-not $fileRemoved -and $retryCount -eq $maxRetries) {
Write-Error $_
Write-Error "Failed [$retryCount/$maxRetries] - Stopping"
break
}
Write-Verbose $_
Write-Verbose "Failed [$retryCount/$maxRetries] - Retrying in $retryIntervalSeconds seconds..."
#TODO: Find a way to try to unlock file here.
Start-Sleep -Seconds $retryIntervalSeconds
}
Write-Verbose $_
Write-Verbose "Failed [$retryCount/$maxRetries] - Retrying in $retryIntervalSeconds seconds..."
#TODO: Find a way to try to unlock file here.
Start-Sleep -Seconds $retryIntervalSeconds
}
} while (-not $fileRemoved -and $retryCount -lt $maxRetries)
} while (-not $fileRemoved -and $retryCount -lt $maxRetries)

if (-not $fileRemoved) {
break # Break to skip unregistering the font if the file could not be removed.
if (-not $fileRemoved) {
break # Break to skip unregistering the font if the file could not be removed.
}
}
}

if ($script:OS -eq 'Windows') {
Write-Verbose "[$functionName] - [$scopeName] - [$fontName] - Searching for font in registry"
$keys = Get-ItemProperty -Path $script:FontRegPathMap[$scopeName]
$key = $keys.PSObject.Properties | Where-Object { $_.Value -eq $filePath }
if (-not $key) {
Write-Verbose "[$functionName] - [$scopeName] - [$fontName] - Font is not registered. Skipping."
} else {
$keyName = $key.Name
Write-Verbose "[$functionName] - [$scopeName] - [$fontName] - Unregistering font [$keyName]"
Remove-ItemProperty -Path $script:FontRegPathMap[$scopeName] -Name $keyName -Force -ErrorAction Stop
if ($script:OS -eq 'Windows') {
Write-Verbose "[$functionName] - [$scopeName] - [$fontName] - Searching for font in registry"
$keys = Get-ItemProperty -Path $script:FontRegPathMap[$scopeName]
$key = $keys.PSObject.Properties | Where-Object { $_.Value -eq $filePath }
if (-not $key) {
Write-Verbose "[$functionName] - [$scopeName] - [$fontName] - Font is not registered. Skipping."
} else {
$keyName = $key.Name
Write-Verbose "[$functionName] - [$scopeName] - [$fontName] - Unregistering font [$keyName]"
Remove-ItemProperty -Path $script:FontRegPathMap[$scopeName] -Name $keyName -Force -ErrorAction Stop
}
}
Write-Verbose "[$functionName] - [$scopeName] - [$fontName] - Done"
}
Write-Verbose "[$functionName] - [$scopeName] - [$fontName] - Done"
}
Write-Verbose "[$functionName] - [$scopeName] - Done"
}
Expand All @@ -150,3 +138,13 @@ Please run the command again with elevated rights (Run as Administrator) or prov
Write-Verbose "[$functionName] - Done"
}
}

Register-ArgumentCompleter -CommandName Uninstall-Font -ParameterName Name -ScriptBlock {
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)
$null = $commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters
if ([string]::IsNullOrEmpty($fakeBoundParameters['Scope'])) {
Get-Font -Scope 'CurrentUser' | Where-Object { $_.Name -like "$wordToComplete*" } | Select-Object -ExpandProperty Name
} else {
Get-Font -Scope $fakeBoundParameters['Scope'] | Where-Object { $_.Name -like "$wordToComplete*" } | Select-Object -ExpandProperty Name
}
}
12 changes: 12 additions & 0 deletions tests/Fonts.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ Describe 'Fonts' {
It 'Should install a font' {
$fontPath = Join-Path -Path $PSScriptRoot -ChildPath 'Fonts/CascadiaCodePL.ttf'
{ Install-Font -Path $fontPath -Verbose } | Should -Not -Throw
Write-Verbose "Installed font: 'CascadiaCodePL'" -Verbose
Write-Verbose (Get-Font | Out-String) -Verbose
}
It "Should return the installed font 'CascadiaCodePL'" {
$font = Get-Font -Name 'CascadiaCodePL'
Expand All @@ -69,5 +71,15 @@ Describe 'Fonts' {
Write-Verbose ($font | Out-String) -Verbose
$font | Should -BeNullOrEmpty
}
It 'Should install and uninstall a font based on wildcard' {
$fontPath = Join-Path -Path $PSScriptRoot -ChildPath 'Fonts/CascadiaCodePL.ttf'
{ Install-Font -Path $fontPath -Verbose } | Should -Not -Throw
Write-Verbose "Installed font: 'CascadiaCodePL'" -Verbose
Write-Verbose (Get-Font | Out-String) -Verbose
{ Uninstall-Font -Name 'CascadiaCode*' -Verbose } | Should -Not -Throw
$font = Get-Font -Name 'CascadiaCodePL'
Write-Verbose ($font | Out-String) -Verbose
$font | Should -BeNullOrEmpty
}
}
}

0 comments on commit 542d2d4

Please sign in to comment.