如何将选项标志传递到PowerShell中的Folder.CopyHere?

nr9pn0ug  于 2022-12-23  发布在  Shell
关注(0)|答案(8)|浏览(195)

我正在尝试编写一个脚本,自动地、静默地将一堆字体移动到Fonts special folder中,这样它们就可以像你从资源管理器中"安装"它们一样可用(通过拖放、复制或右键单击并选择安装)。

$FONTS = 0x14
$shell = New-Object -ComObject Shell.Application
$source = $shell.Namespace($downloaded_path)
$target = $shell.Namespace($FONTS)
$target.CopyHere($source.Items())

然而,有些系统可能已经安装了字体,我希望进度对话框被隐藏,任何提示都被默默接受。

因此,我正在研究Folder.CopyHere选项标志。

  • 4不显示进度对话框
  • 16对于显示的任何对话框,回答"Yes to All"(全部是)。

我希望在这个文件夹中支持它们(有些选项被设计忽略了)。而且我认为这些是十进制的,对吗?它们需要转换吗?不管我怎么传递它们,我仍然看到两个对话框。我试过了

$options = 4           <-- don't expect int to work
$options = 0x4         <-- thought hexidecimal would be ok, the VB documentation shows &H4&
$options = "4"         <-- string's the thing?
$options = [byte]4     <-- no luck with bytes
$options = [variant]4  <-- this isn't even a type accelerator!

而且,如果我可以让一个选项工作,我如何让两个工作?我bor他们在一起?格式化呢?

$options = 4 -bor 16

或者我把它们加起来或者转换成十六进制?

$options = "{0:X}" -f (4 + 16)
i34xakig

i34xakig1#

你可以使用4 -bor 16。由于类型是VARIANT,所以很难判断这个方法期望什么。我认为它应该取一个整数值。如果这不起作用,MSDN topic on Folder.CopyHere中的这条注解暗示字符串应该起作用:

function CopyFileProgress
{
    param( $Source, $DstFolder, $CopyType = 0 )

    # Convert the decimal to hex
    $copyFlag = [String]::Format("{0:x}", $CopyType)

    $objShell = New-Object -ComObject "Shell.Application"
    $objFolder = $objShell.NameSpace($DestLocation) 
    $objFolder.CopyHere($Source, $copyFlag)
}

虽然我想知道格式字符串是否应该是"0x{0:x}"
请注意,对于普通的.NET标志样式的枚举,您可以将多个标志传递给一个.NET(或命令参数),该.NET(或命令参数)是强类型枚举,如下所示:

$srv.ReplicationServer.Script('Creation,SomeOtherValue')

Oisin已经在这个blog post中写了一些关于这个主题的信息。

sbdsn5lh

sbdsn5lh2#

我有同样的问题,并发现这在另一个线程,完美地为我工作.
如果您希望它覆盖并保持静默,请将0x10更改为0x14(docs)。

$destinationFolder.CopyHere($zipPackage.Items(), 0x14)
mzaanser

mzaanser3#

Folder.CopyHere选项标志可能只是not work,这让我很难过,我必须研究这些其他方法中的一个,所有这些方法都给我带来了一些束缚。

单独过程

在一个新进程中调用副本,并使用ProcessStartInfo属性隐藏窗口。我还没有实现这个,但我想知道它是否会解决用户提示覆盖现有文件的问题?

Dim iProcess As New System.Diagnostics.ProcessStartInfo(AppDomain.CurrentDomain.BaseDirectory + “unzip.exe”)

iProcess.CreateNoWindow = True
Dim sArgs As String = ZippedFile
iProcess.Arguments = sArgs
iProcess.WindowStyle = ProcessWindowStyle.Hidden
Dim p As New System.Diagnostics.Process
iProcess.UseShellExecute = False
p = System.Diagnostics.Process.Start(iProcess)
p.WaitForExit(30000)
Dim s As Integer = p.ExitCode
iProcess.UseShellExecute = True

p.Dispose()
iProcess = Nothing

For循环

只有copy non-existing items。当我实际上想用同名的新字体文件更新现有字体时,这似乎会失败。

foreach($File in $Fontdir) {
    $fontName = $File.Name.Replace(".ttf", " Regular")
    $objFolderItem = $objFolder.ParseName($fontName);
    if (!$objFolderItem) {
      $objFolder.CopyHere($File.fullname,0x14)
    }
}

删除现有

我在考虑删除所有与我正在复制的字体同名的字体,然后复制这套字体。虽然这有点残忍。而且我相信,如果该字体因为正在使用而无法删除,会有 * 另一个 * 提示。* 叹气 *

3qpi33ja

3qpi33ja4#

复制标志对我不起作用。我在安装字体脚本中设置了一个作业,该作业检测“安装字体”窗口并向其发送{Enter},这样我就不会覆盖现有字体。

Start-Job –Name DetectAndClosePrompt –Scriptblock {
  $i=1
  [void] [System.Reflection.Assembly]::LoadWithPartialName("'System.Windows.Forms")
  [void] [System.Reflection.Assembly]::LoadWithPartialName("'Microsoft.VisualBasic")
  while ($i -eq 1) { 
    $windowPrompt = Get-Process -ErrorAction SilentlyContinue |? {$_.MainWindowTitle -like "*Installing Fonts*"} 
    [Microsoft.VisualBasic.Interaction]::AppActivate($windowPrompt.ID)
    [System.Windows.Forms.SendKeys]::SendWait("{Enter}")
    sleep 2 
  }
}

所有字体复制/安装后...我删除作业,按名称。

Get-Job DetectAndClosePrompt | Remove-Job -Force

这对我来说在Windows 7,8. x和10上是有效的。

2mbi3lxu

2mbi3lxu5#

我看到了很多解压文件夹的操作,但是真的没有人写一个解决方案来适应Fonts文件夹的情况。所以我写了我自己的!事实证明,Fonts文件夹确实实现了Shell.Folder.CopyHere方法,但是不支持为该方法的第二个参数传递的任何重载。为什么?谁知道呢!我怀疑'The Old new Thing' Windows Developer博客的Raymond Chen可以解释这一点,但是我不知道答案。所以我们需要在复制字体之前聪明地寻找它们,否则我们会得到一个令人讨厌的信息。
在我的代码中,我们通过通配符搜索来检查字体名称的前四个字符是否匹配,如果字体不存在,我们假设这是我们第一次在这个系统上安装字体,并设置一个名为$FirstInstall的特殊标志。
从那时起,如果$FirstInstall为true,我们将安装源字体目录中的所有字体。在随后的执行中,我们将检查每个字体是否匹配,如果匹配,我们将中止复制。如果不匹配,我们将继续复制。到目前为止,这似乎适用于我的大多数客户端。
给你!

<#
.SYNOPSIS
    Script to quietly handle the installation of fonts from a network source to a system

.DESCRIPTION
    We Can't just move files into the %windir%\Fonts directory with a script, as a simple copy paste from command line doesn't trigger windows to note the new font
If we used that approach, the files would exist within the directory, but the font files woudln't be registered in windows, nor would applications 
display the new font for use.  Instead, we can make a new object of the Shell.Application type (effectively an invisible Windows Explorer Windows) and use its Copy method
Which is the functional equivalent of dragging an dropping font files into the Font folder, which does trigger the font to be installed the same as if you right clicked the font
and choose install.

.PARAMETER FontPath
    The path of a folder where fonts reside on the network

.EXAMPLE
    .\Install-Fonts.ps1 -FontPath "\\corp\fileshare\Scripts\Fonts"

    Installing font...C:\temp\Noto\NotoSans-Bold.ttf
    Installing font...C:\temp\Noto\NotoSans-BoldItalic.ttf
    Installing font...C:\temp\Noto\NotoSans-Italic.ttf
    Installing font...C:\temp\Noto\NotoSans-Regular.ttf

    In this case, the fonts are copied from the network down to the system and installed silently, minus the logging seen here
    import files needed for step 1, step 2, and step 5 of the migration process.

.EXAMPLE
    .\Install-Fonts.ps1 -FontPath "\\corp\fileshare\Scripts\Fonts"

    Font already exists, skipping
    Font already exists, skipping
    Font already exists, skipping
    Font already exists, skipping
    In this case, the fonts already existed on the system.  Rather than display an annoying 'Overwrite font' dialog, we simply abort the copy and try the next file

.INPUTS
    String.

.OUTPUTS
    Console output

.NOTES
    CREATED: 06/11/2015
    Author: sowen@ivision.com

    MODIFIED:06/11/2015
    Author: sowen@ivision.com   -Reserved...

#> 
param
    ( 
        [Parameter(Mandatory)][string]$FontPath="C:\temp\Noto" 
    ) 

#0x14 is a special system folder pointer to the path where fonts live, and is needed below. 
$FONTS = 0x14

#Make a refrence to Shell.Application
$objShell = New-Object -ComObject Shell.Application
$objFolder = $objShell.Namespace($FONTS)

ForEach ($font in (dir $fontsPath -Recurse -Include *.ttf,*.otf)){

    #check for existing font (to suppress annoying 'do you want to overwrite' dialog box
    if ((($objShell.NameSpace($FONTS).Items() | where Name -like "$($font.BaseName.Split('-')[0].substring(0,4))*") | measure).Count -eq 0){
        $firstInstall = $true}

    if ($firstInstall -ne $true) {Write-Output "Font already exists, skipping"}

        else{    
        $objFolder.CopyHere($font.FullName)
        Write-Output "Installing font...$($font.FullName)"
        $firstInstall = $true
        }

    }

.\Install-Fonts.ps1 -FontPath "\\corp\fileshare\Scripts\Fonts"
du7egjpx

du7egjpx6#

@FoxDeploy的答案有几个问题,这就是它不起作用的原因。第一个问题是,您还希望检查%USERPROFILE%中的Fonts文件夹,否则您将看到确认对话框。第二个问题是,您希望避免在字体名称中使用“-”。
以下是从CodeFonts存储库安装字体的修复版本示例:

$ErrorActionPreference = "Stop"
Add-Type -AssemblyName System.Drawing

# Clone chrissimpkins/codeface from which we will install fonts
if (!(Test-Path /GitHubSrc/codeface)){
    git clone git://github.com/chrissimpkins/codeface.git /GitHubSrc/codeface
}

#0x14 is a special system folder pointer to the path where fonts live, and is needed below. 
$FONTS = 0x14
$fontCollection = new-object System.Drawing.Text.PrivateFontCollection

#Make a refrence to Shell.Application
$objShell = New-Object -ComObject Shell.Application
$objFolder = $objShell.Namespace($FONTS)

# local path

$localSysPath = "$Env:USERPROFILE\AppData\Local\Microsoft\Windows\Fonts"
$localSysFonts = Get-ChildItem -Path $localSysPath -Recurse -File -Name | ForEach-Object -Process {[System.IO.Path]::GetFileNameWithoutExtension($_)}

$fontsPath="\GitHubSrc\codeface\fonts"
ForEach ($font in (dir $fontsPath -Recurse -Include *.ttf,*.otf)){
    if ($localSysFonts -like $font.BaseName) {
        Write-Output "SKIP: Font ${font} already exists in ${localSysPath}"
    }
    else {
        $fontCollection.AddFontFile($font.FullName)
        $fontName = $fontCollection.Families[-1].Name

        #check for existing font (to suppress annoying 'do you want to overwrite' dialog box
        if ((($objShell.NameSpace($FONTS).Items() | where Name -ieq $fontName) | measure).Count -eq 0){
            Write-Output "INST: Font ${font}"
            $objFolder.CopyHere($font.FullName)
            $firstInstall = $true
        }
        else {
            Write-Output "SKIP: Font ${font} already exists in SYSTEM FONTS"
        }
    }
    # Read-Host -Prompt "Press Enter to continue"
}
b5buobof

b5buobof7#

你可以只采取你的选择之和。我需要运行CopyHere与两个选项-沉默和NOCONFIRMATION。看看下面的例子:

function Unzip-Archive($targetpath, $destination)
{    
    $shell_app=new-object -com shell.application

    $FOF_SILENT_FLAG = 4
    $FOF_NOCONFIRMATION_FLAG = 16

    $zip_file = $shell_app.namespace("$targetpath")

    #Set the destination directory for the extracts
    $destination = $shell_app.namespace("$destination")

    #unzip the files
    $destination.Copyhere($zip_file.items(), $FOF_SILENT_FLAG + $FOF_NOCONFIRMATION_FLAG)    
}
y0u0uwnf

y0u0uwnf8#

我只是通过简单地使用+ i.e.

function Expand-ZIPFile($file, $destination)
{
    $shell = new-object -com shell.application
    $zip = $shell.NameSpace($file)
    foreach($item in $zip.items())
    {
        $shell.Namespace($destination).copyhere($item, 16+1024)
    }
}

相关问题