Install fonts using Invoke-Command

Welcome Forums General PowerShell Q&A Install fonts using Invoke-Command

This topic contains 2 replies, has 2 voices, and was last updated by

 
Participant
9 months, 4 weeks ago.

  • Author
    Posts
  • #91719

    Participant
    Points: 1
    Rank: Member

    EDIT *** WORKING SOLUTION POSTED BELOW INITIAL QUESTION ***

    Hello,

    I think the issue with the script is my use of the -Scriptblock. It is confusing because the only variables I am using in the -Scriptblock are created there. They are not(?) local variables, but I get the error: You cannot call a method on a null-valued expression.

    Here is my script:

    #provide lab pc names
    $labPCs = @("pc1","pc2")
    
    #foreach lab $labPC, check for \tempFont directory. if false, create it and copy fonts. if true, copy new fonts to it
    ForEach ($pc in $labPCs) {
    
        #define $localFolder
        $localFolder = "\\$($pc)\c$\tempFont\"
    
        #test path to $localFolder, create and copy fonts if false, else copy fonts
        if (!(Test-Path -Path $localFolder)) {
    
            New-Item -ItemType Directory -Path $localFolder -Force
            Copy-Item -Path $newFonts -Destination $localFolder
    
        }
    
        Else {
        
        Copy-Item -Path $newFonts -Destination $localFolder
        
        }
        
    #for each font, check if it exists by name in the Fonts folder on the target machine. if not, attempt to install it...
        ForEach ($font in $newFonts) {
        
                if (!(Test-Path -Path ('\\'+$($pc)+'\C$\Windows\Fonts\'+$($font).Name))) {
    #start scriptblock
                    Invoke-Command -ComputerName $pc -ScriptBlock {
                    #create a new com object Shell.Application
                        $shell = New-Object -ComObject Shell.Application
                    #create fonts com object
                        $fontNS = $shell.NameSpace(0x14)
                    #grab newly copied fonts
                        $copiedFonts = Get-ChildItem "C:\tempFont\"
    #create com object from that directory
                        $copiedFontsNS = $shell.NameSpace($copiedFonts)
                    #use CopyHere method to copy items in $copiedFonts to Fonts namespace
                        $fontNS.CopyHere($copiedFontsNS.Items(), 0x14)
    
                        }
    
                }
        
        }
    
    }

    *** WORKING SOLUTION *** – my issues were a lack of understand of Invoke-Command, Scriptblock, and the asynchronous CopyHere method. I read up and understand these much better (so I stopped using CopyHere altogether :)), and now the script works great...

    #grab new fonts from share
    $newFonts = Get-ChildItem -Path C:\path\to\newFonts -Recurse -Include *.ttf,*.otf,*.fon
    
    #provide lab pc names
    $labPCs = @("pc1","pc2")
    
    #foreach lab $labPC, check for \tempFont directory. if false, create it and copy fonts. if true, copy new fonts to it
    ForEach ($pc in $labPCs) {    
    
        #define $localFolder
        $localFolder = "\\$($pc)\c$\tempFont\"
    
        #test path to $localFolder, create and copy fonts if false, else copy fonts
        if (!(Test-Path -Path $localFolder)) {
    
            New-Item -ItemType Directory -Path $localFolder -Force
            Copy-Item -Path $newFonts -Destination $localFolder
    
        }
    
        Else {
        
        Copy-Item -Path $newFonts -Destination $localFolder
        
        }
    
        #run the following commands on target lab PC's
        Invoke-Command -ComputerName $pc -ScriptBlock {
            
            #set dest path
            $destPath = "C:\Windows\Fonts\"
    
            #grab existing dest objects
            $destFiles = Get-ChildItem -Path $destPath -Recurse         
    
            #set new font source path
            $sourcePath = 'C:\tempFont\'
    
            #use this to grab all new font source objects
            $sourceFiles = Get-ChildItem -Path $sourcePath -Include *.ttf,*.otf,*.fon -Recurse
            
            #set directory for placing fonts to install
            $fontInstall = New-Item -Path $sourcePath -ItemType Directory -Name 'Install' -Force
    
            #set path to \Fonts in registry
            $regPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts"      
    
            #for each source file, see if it exists in \Fonts on the lab PC... 
            ForEach ($s in $sourceFiles) {
    
                $regName = "$($s.Name)"
    
                #if not...
                if (-not(Test-Path ($destPath + $s.Name))) {
    
                    #copy to the Install directory...
                    Copy-Item -Path $s.FullName -Destination $fontInstall.FullName -Force;
    
                    #grab the full path to the font in it's new location...
                    $install = $fontInstall.FullName + '\' + $s.Name;
    
                    #for each font in the Install directory, copy it to \Fonts via shell object. This copy method is asynchronous...
                    #so I used a While loop with Start-Sleep to make sure the copy finishes before the script moves on...
                    #logic is 'While the font to install does not exist in \Fonts, sleep the script for 1 second until the asynch copy finishes...
                    ForEach ($i in $install) {
    
                        #copy the font file to the \Fonts folder
                        Copy-Item $i -Destination $destPath -Force
    
                        #register the newly copied fonts in the registry
                        New-ItemProperty -Path $regPath -Name $regName -Value $regName -Force | Out-Null;
    
                        }
    
                    #register the newly copied fonts in the registry
                    New-ItemProperty -Path $regPath -Name $regName -Value $regName -Force | Out-Null
                    
                    }                
    
                }
    
                #remove the Install folder from the lab PC.
                #Get-Item -Path $fontInstall.FullName | Remove-Item -Recurse -Force
    
            }
    
        }
    
    }
  • #91739

    Participant
    Points: 206
    Helping Hand
    Rank: Participant

    Step through your code one segment at a time to make sure you are getting what you'd expect.
    Comment out that whole Invoke-Command segment, and put some other dummy code there and see what your results are.

    • #91787

      Participant
      Points: 1
      Rank: Member

      Hi there,

      Thank you for the comments.

      I have stepped through the code and everything works up to the scriptblock. If I do something like New-Item ... in the first line of the scriptblock, it works. The item is created on the remote computer.

      Thanks again!

The topic ‘Install fonts using Invoke-Command’ is closed to new replies.