none
Overwriting Fonts

    Question

  • Hi, I can successfully install fonts with PS, but it prompts me to overwrite each individual font that already exists. We have to overwrite quite a few and I am trying to incorporate this in some sort of script so having to answer about 100 dialog boxes just really doesn't work out.

    I can not seem to find any way around this and surely there has to be some solution. 

    This is a sample block of code I have been messing around with.

    $FONTS = 0x14
    $Path="c:\fonts"
    $objShell = New-Object -ComObject Shell.Application
    $objFolder = $objShell.Namespace($FONTS)
    New-Item $Path -type directory
    Copy-Item "path\*" $Path
    Copy-Item "path\*" $Path
    Copy-Item "path\*" $Path
    Copy-Item "path\*" $Path
    $Fontdir = dir $Path
    foreach($File in $Fontdir) {
      $objFolder.CopyHere($File.fullname)
    }
    remove-item $Path -recurse
    write-host "Installing Fonts Complete"; sleep -m 10000
    Any help is greatly appreciated.
    jeudi 7 février 2013 15:05

Réponses

  • the delete-and-copy-then-reboot technique should work for any conflicts. Here's a slightly modified form of the script I showed you before, with two significant changes.

    The first change is that if the file exists, we delete it and then replace it. The second change is implementing a $rebootFlag variable that gets set to true if it IS necessary to overwrite any files.

    $ssfFonts = 0x14
    $fontSourceFolder = "c:\fonts"
    $Shell = New-Object -ComObject Shell.Application
    $SystemFontsFolder = $Shell.Namespace($ssfFonts)
    $FontFiles = Get-ChildItem $fontSourceFolder
    $SystemFontsPath = $SystemFontsFolder.Self.Path
    $rebootFlag = $false
    
    foreach($FontFile in $FontFiles) {
    	# $FontFile will be copied to this path:
    	$targetPath = Join-Path $SystemFontsPath $FontFile.Name
    	# So, see if target exists...
    	if(Test-Path $targetPath){
    		# font file with the same name already there.
    		# delete and replace.
    		$rebootFlag = $true
    		Remove-Item $targetPath -Force
    		Copy-Item $FontFile.FullName $targetPath -Force
    	}else{
    		#install the font.
    		$SystemFontsFolder.CopyHere($FontFile.fullname)
    	}
    }
    
    #Follow-up message
    if($rebootFlag){
    	Write-Host "At least one existing font overwritten. A reboot may be necessary."
    }
    

    • Marqué comme réponse JustinDS lundi 11 février 2013 14:33
    lundi 11 février 2013 01:16

Toutes les réponses

  • Try changing your loop to

    foreach($File in $Fontdir) {
      $objFolder.CopyHere($File.fullname, 16)
    }
    

    The option flag value 16 tells CopyHere to respond "Yes to All" for any questions. See the following ref for option details:

    http://msdn.microsoft.com/en-us/library/windows/desktop/bb787866(v=vs.85).aspx

    jeudi 7 février 2013 19:18
  • Yeah I knew it did, but when testing I couldn't seem to get the option flags to work. I will try it again in the morning and see what results I get.

    Thanks

    jeudi 7 février 2013 23:41
  • Tested again and does no good at all. Other people have had similar issues with the copyhere command and not using option flags properly.

    There has to be some way around this.

    vendredi 8 février 2013 16:40
  • Have you tried putting the -Force parameter on the Copy-Item cmdlet?

    .:|:.:|:. tim

    vendredi 8 février 2013 22:24
  • I don't believe so. I will test that soon as I get the chance. Unfortunately that will be Monday morning. Thanks though will post back.
    samedi 9 février 2013 03:32
  • Justin,

    I'm seeing the issue as well on a Windows 7 install, but I believe it affects all OS versions. The problem is that the dialog popping up is not a standard file/folder confirmation, but one specific to font installation (which I should have thought about before telling you to use 0x16 flag). It does nothing since the font confirmation just isn't listening to it.

    By the same token, you can't just perform a deletion

    Could you give us some more details? Specifically, what's the issue with files that you're overwriting - are you updating a specific set of font files with newer versions? Or is this generalized code to install a standard set of fonts, some of which may already be present on some systems? Or something else?

    There are workarounds for most scenarios.

    One case: From script, you can perform a test for whether or not a specific file already exists in the fonts directory. If you don't need to copy fonts that are already there, you can simply skip them; if you do need to update them, you can switch from using CopyHere to using Copy-Item.

    The one disadvantage to this technique is that it is possible certain fonts won't be updated properly until after a system reboot. Also, we're skipping over the font registration step that normally occurs when installing font. Normally, the font's display name is read from the font file by Windows, then stored with the font file name under the registry key HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts. If the friendly name is still the same - for example, if you're installing an updated century.ttf file, but both the old and the new TTF fonts use the name "Century (TrueType)" - there won't be a problem.

    Another case: if you know the font file display names and can wait for a reboot before changes take effect, you can completely ignore Shell.Application. Instead, all you need to do is copy each file to the Windows Fonts folder and add a named value under the Fonts registry key mentioned above.

    Below is a script that assumes it doesn't need to overwrite existing fonts. Note that it's a bit different from yours; I assume that c:\fonts already exists and is populated with the files I need to copy.

    $ssfFonts = 0x14
    $fontSourceFolder = "c:\fonts"
    $Shell = New-Object -ComObject Shell.Application
    $SystemFontsFolder = $Shell.Namespace($ssfFonts)
    $FontFiles = Get-ChildItem $fontSourceFolder
    $SystemFontsPath = $SystemFontsFolder.Self.Path
    
    foreach($FontFile in $FontFiles) {
    	# $FontFile will be copied to this path:
    	$targetPath = Join-Path $SystemFontsPath $FontFile.Name
    	# So, see if target exists...
    	if(Test-Path $targetPath){
    		#doing nothing, since font is already installed.
    	}else{
    		#install the font.
    		$SystemFontsFolder.CopyHere($FontFile.fullname)
    	}
    }

    samedi 9 février 2013 10:06
  • Very informative post, that would explain why that flag was not working.

    The issue is that some of the font files need to be updated in the process of adding in new ones. Some of the fonts have been updated or added to.

    I have no problem with doing a restart if I could just get the fonts over there as they should be.\

    Do you think deleting the existing font files and then copying the nex ones over would be best?

    If so how do I go about that?

    Much appreciated.

    samedi 9 février 2013 23:21
  • the delete-and-copy-then-reboot technique should work for any conflicts. Here's a slightly modified form of the script I showed you before, with two significant changes.

    The first change is that if the file exists, we delete it and then replace it. The second change is implementing a $rebootFlag variable that gets set to true if it IS necessary to overwrite any files.

    $ssfFonts = 0x14
    $fontSourceFolder = "c:\fonts"
    $Shell = New-Object -ComObject Shell.Application
    $SystemFontsFolder = $Shell.Namespace($ssfFonts)
    $FontFiles = Get-ChildItem $fontSourceFolder
    $SystemFontsPath = $SystemFontsFolder.Self.Path
    $rebootFlag = $false
    
    foreach($FontFile in $FontFiles) {
    	# $FontFile will be copied to this path:
    	$targetPath = Join-Path $SystemFontsPath $FontFile.Name
    	# So, see if target exists...
    	if(Test-Path $targetPath){
    		# font file with the same name already there.
    		# delete and replace.
    		$rebootFlag = $true
    		Remove-Item $targetPath -Force
    		Copy-Item $FontFile.FullName $targetPath -Force
    	}else{
    		#install the font.
    		$SystemFontsFolder.CopyHere($FontFile.fullname)
    	}
    }
    
    #Follow-up message
    if($rebootFlag){
    	Write-Host "At least one existing font overwritten. A reboot may be necessary."
    }
    

    • Marqué comme réponse JustinDS lundi 11 février 2013 14:33
    lundi 11 février 2013 01:16
  • I believe that should be along the lines of what I am looking for. I should be able to do some testing on this tomorrow.

    I really appreciate the help. Was somewhat lost on what to do with this exactly other than just doing it manually which would be a bit of a hassle.

    Will post back and let you know.

    Thanks

    lundi 11 février 2013 01:21
  • Had a chance to test this out. Was quite a bit slower than doing it manually, but seemed to work overall. Atleast it is automated.

    Once again thanks for your help.

    lundi 11 février 2013 14:35