1+ # Font Renamer Script - Renames fonts with Family (Subfamily) (vVersion) structure
2+ Add-Type - AssemblyName System.Drawing
3+
4+ function Get-FontInfo {
5+ param ([string ]$FontPath )
6+
7+ try {
8+ $fontCollection = New-Object System.Drawing.Text.PrivateFontCollection
9+ $fontCollection.AddFontFile ($FontPath )
10+
11+ if ($fontCollection.Families.Count -eq 0 ) {
12+ return $null
13+ }
14+
15+ $fontFamily = $fontCollection.Families [0 ]
16+ $fileName = [System.IO.Path ]::GetFileNameWithoutExtension($FontPath )
17+
18+ # Default values
19+ $fontInfo = @ {
20+ Family = $fontFamily.Name
21+ Subfamily = " Regular"
22+ Version = " 1.0"
23+ }
24+
25+ # Try to extract version from font metadata or filename patterns
26+ try {
27+ # Look for version patterns in filename
28+ if ($fileName -match " (?i)version?[_\-\s]*(\d+\.?\d*)" ) {
29+ $fontInfo.Version = $matches [1 ]
30+ }
31+ elseif ($fileName -match " (?i)v[_\-\s]*(\d+\.?\d*)" ) {
32+ $fontInfo.Version = $matches [1 ]
33+ }
34+ elseif ($fileName -match " \b(\d+\.\d+)\b" ) {
35+ $fontInfo.Version = $matches [1 ]
36+ }
37+ elseif ($fileName -match " \b(\d+)\b" -and $matches [1 ] -match " ^\d{1,2}$" ) {
38+ $fontInfo.Version = $matches [1 ] + " .0"
39+ }
40+
41+ # Try to read actual font version from font tables (basic attempt)
42+ $bytes = [System.IO.File ]::ReadAllBytes($FontPath )
43+ if ($bytes.Length -gt 100 ) {
44+ # Look for version string in font data (simplified approach)
45+ $fontString = [System.Text.Encoding ]::ASCII.GetString($bytes )
46+ if ($fontString -match " Version\s+(\d+\.\d+)" ) {
47+ $fontInfo.Version = $matches [1 ]
48+ }
49+ }
50+ }
51+ catch {
52+ # Keep default version if extraction fails
53+ }
54+
55+ # Detect subfamily from filename (case-insensitive)
56+ $fileNameLower = $fileName.ToLower ()
57+
58+ # Check for combinations first
59+ if ($fileNameLower -match " bolditalic|bold.*italic|italic.*bold" ) {
60+ $fontInfo.Subfamily = " Bold Italic"
61+ }
62+ elseif ($fileNameLower -match " lightitalic|light.*italic|italic.*light" ) {
63+ $fontInfo.Subfamily = " Light Italic"
64+ }
65+ elseif ($fileNameLower -match " mediumitalic|medium.*italic|italic.*medium" ) {
66+ $fontInfo.Subfamily = " Medium Italic"
67+ }
68+ elseif ($fileNameLower -match " thinitalic|thin.*italic|italic.*thin" ) {
69+ $fontInfo.Subfamily = " Thin Italic"
70+ }
71+ elseif ($fileNameLower -match " blackitalic|black.*italic|italic.*black" ) {
72+ $fontInfo.Subfamily = " Black Italic"
73+ }
74+ # Single styles
75+ elseif ($fileNameLower -match " bold" ) {
76+ $fontInfo.Subfamily = " Bold"
77+ }
78+ elseif ($fileNameLower -match " italic" ) {
79+ $fontInfo.Subfamily = " Italic"
80+ }
81+ elseif ($fileNameLower -match " light" ) {
82+ $fontInfo.Subfamily = " Light"
83+ }
84+ elseif ($fileNameLower -match " thin" ) {
85+ $fontInfo.Subfamily = " Thin"
86+ }
87+ elseif ($fileNameLower -match " medium" ) {
88+ $fontInfo.Subfamily = " Medium"
89+ }
90+ elseif ($fileNameLower -match " black" ) {
91+ $fontInfo.Subfamily = " Black"
92+ }
93+ elseif ($fileNameLower -match " regular" ) {
94+ $fontInfo.Subfamily = " Regular"
95+ }
96+ elseif ($fileNameLower -match " semibold" ) {
97+ $fontInfo.Subfamily = " SemiBold"
98+ }
99+ elseif ($fileNameLower -match " extrabold" ) {
100+ $fontInfo.Subfamily = " ExtraBold"
101+ }
102+ elseif ($fileNameLower -match " ultralight" ) {
103+ $fontInfo.Subfamily = " UltraLight"
104+ }
105+
106+ # Clean invalid characters
107+ $fontInfo.Family = $fontInfo.Family -replace ' [\\/:*?"<>|]' , ' '
108+ $fontInfo.Subfamily = $fontInfo.Subfamily -replace ' [\\/:*?"<>|]' , ' '
109+ $fontInfo.Version = $fontInfo.Version -replace ' [\\/:*?"<>|]' , ' '
110+
111+ return $fontInfo
112+ }
113+ catch {
114+ Write-Error " Error processing font: $ ( $_.Exception.Message ) "
115+ return $null
116+ }
117+ }
118+
119+ function Rename-Fonts {
120+ param (
121+ [string ]$Path = (Get-Location ).Path,
122+ [switch ]$WhatIf = $false
123+ )
124+
125+ $fontExtensions = @ (" *.ttf" , " *.otf" , " *.woff" , " *.woff2" , " *.fon" , " *.ttc" )
126+ $timestamp = Get-Date - Format " yyyy-MM-dd_HH-mm-ss"
127+ $logFile = Join-Path $Path " FontRenamer_Log_$timestamp .txt"
128+ $processedFolder = Join-Path $Path " Processed_Fonts"
129+
130+ # Create processed folder if not in simulation mode
131+ if (-not $WhatIf ) {
132+ if (-not (Test-Path $processedFolder )) {
133+ New-Item - Path $processedFolder - ItemType Directory | Out-Null
134+ }
135+ }
136+
137+ # Initialize log file
138+ $logHeader = @"
139+ Font Renamer Log - $ ( Get-Date - Format " yyyy-MM-dd HH:mm:ss" )
140+ Directory: $Path
141+ Processed Folder: $processedFolder
142+ Mode: $ ( if ($WhatIf ){" SIMULATION" }else {" EXECUTION" })
143+ ============================================
144+
145+ "@
146+
147+ $logHeader | Out-File - FilePath $logFile - Encoding UTF8
148+
149+ function Write-Log {
150+ param ([string ]$Message , [string ]$Color = " White" )
151+ Write-Host $Message - ForegroundColor $Color
152+ $Message | Out-File - FilePath $logFile - Append - Encoding UTF8
153+ }
154+
155+ Write-Log " Processing fonts in: $Path " " Green"
156+
157+ $processedCount = 0
158+ $errorCount = 0
159+ $skippedCount = 0
160+
161+ foreach ($extension in $fontExtensions ) {
162+ $fonts = Get-ChildItem - Path $Path - Filter $extension - File
163+
164+ foreach ($font in $fonts ) {
165+ Write-Log " `n Processing: $ ( $font.Name ) " " Cyan"
166+
167+ $fontInfo = Get-FontInfo - FontPath $font.FullName
168+
169+ if ($null -eq $fontInfo ) {
170+ Write-Log " ERROR: Cannot extract font info - Skipped" " Red"
171+ $errorCount ++
172+ continue
173+ }
174+
175+ $newName = " $ ( $fontInfo.Family ) ($ ( $fontInfo.Subfamily ) ) (v$ ( $fontInfo.Version ) )$ ( $font.Extension ) "
176+ Write-Log " Detected: Family='$ ( $fontInfo.Family ) ', Subfamily='$ ( $fontInfo.Subfamily ) ', Version='$ ( $fontInfo.Version ) '" " Gray"
177+
178+ if ($font.Name -eq $newName ) {
179+ Write-Log " SKIPPED: No change needed" " Yellow"
180+ $skippedCount ++
181+
182+ # Move unchanged files to processed folder too
183+ if ($WhatIf ) {
184+ Write-Log " SIMULATION: Would move unchanged file to: $processedFolder " " Magenta"
185+ }
186+ else {
187+ try {
188+ $finalPath = Join-Path $processedFolder $font.Name
189+ Move-Item - Path $font.FullName - Destination $finalPath
190+ Write-Log " MOVED: Unchanged file moved to: $finalPath " " Yellow"
191+ }
192+ catch {
193+ Write-Log " ERROR: Failed to move unchanged file - $ ( $_.Exception.Message ) " " Red"
194+ $errorCount ++
195+ }
196+ }
197+ continue
198+ }
199+
200+ $newPath = Join-Path $Path $newName
201+
202+ if (Test-Path $newPath ) {
203+ Write-Log " ERROR: Target file already exists: $newName " " Red"
204+ $errorCount ++
205+ continue
206+ }
207+
208+ if ($WhatIf ) {
209+ Write-Log " SIMULATION: Would rename to: $newName " " Magenta"
210+ Write-Log " SIMULATION: Would move to: $processedFolder " " Magenta"
211+ $processedCount ++
212+ }
213+ else {
214+ try {
215+ # Rename the file first
216+ Rename-Item - Path $font.FullName - NewName $newName
217+ $renamedPath = Join-Path $Path $newName
218+
219+ # Move to processed folder
220+ $finalPath = Join-Path $processedFolder $newName
221+ Move-Item - Path $renamedPath - Destination $finalPath
222+
223+ Write-Log " SUCCESS: Renamed and moved to: $finalPath " " Green"
224+ $processedCount ++
225+ }
226+ catch {
227+ Write-Log " ERROR: Rename/Move failed - $ ( $_.Exception.Message ) " " Red"
228+ $errorCount ++
229+ }
230+ }
231+ }
232+ }
233+
234+ # Final report
235+ Write-Log " `n === SUMMARY ===" " Blue"
236+ Write-Log " Total fonts found: $ ( $processedCount + $skippedCount + $errorCount ) " " White"
237+ Write-Log " Renamed and moved: $processedCount " " Green"
238+ Write-Log " Moved unchanged: $skippedCount " " Yellow"
239+ Write-Log " Errors (remained in original folder): $errorCount " " Red"
240+
241+ if ($WhatIf ) {
242+ Write-Log " `n This was a SIMULATION. Remove -WhatIf to apply changes." " Yellow"
243+ Write-Log " All processed fonts would be moved to: $processedFolder " " Yellow"
244+ Write-Log " Only error fonts would remain in: $Path " " Yellow"
245+ }
246+ else {
247+ if (($processedCount + $skippedCount ) -gt 0 ) {
248+ Write-Log " `n All processed fonts moved to: $processedFolder " " Cyan"
249+ Write-Log " Only fonts with errors remain in: $Path " " Cyan"
250+ }
251+ }
252+
253+ Write-Log " `n Log file saved: $logFile " " Cyan"
254+ }
255+
256+ function Show-Help {
257+ Write-Host " Font Renamer Script" - ForegroundColor Blue
258+ Write-Host " "
259+ Write-Host " Commands:"
260+ Write-Host " Rename-Fonts # Process current directory"
261+ Write-Host " Rename-Fonts -WhatIf # Simulation mode"
262+ Write-Host " Rename-Fonts -Path 'C:\Fonts' # Process specific directory"
263+ Write-Host " Show-Help # Show this help"
264+ Write-Host " "
265+ Write-Host " Supported: .ttf, .otf, .woff, .woff2"
266+ Write-Host " Output format: Family (Subfamily) (vVersion).ext"
267+ Write-Host " "
268+ Write-Host " All valid fonts moved to Processed folder, only problematic fonts remain"
269+ Write-Host " Example: Arial-Bold.ttf -> Arial (Bold) (v1.0).ttf -> Moved to Processed folder"
270+ }
271+
272+ # Main execution
273+ Write-Host " Font Renamer Script Loaded" - ForegroundColor Blue
274+ Write-Host " Type 'Show-Help' for usage information" - ForegroundColor Gray
275+ Write-Host " Type 'Rename-Fonts -WhatIf' to simulate" - ForegroundColor Gray
276+ Write-Host " Type 'Rename-Fonts' to execute" - ForegroundColor Gray
0 commit comments