如何使用 powershell 设置文件的保存位置?

Posted

技术标签:

【中文标题】如何使用 powershell 设置文件的保存位置?【英文标题】:How can I set the save location of a file using powershell? 【发布时间】:2017-06-14 11:23:07 【问题描述】:

我正在尝试将 PDF 打印为 XPS,脚本打开 PDF Print Output As 屏幕并输入正确的名称,然后将 ENTER 命令发送到窗口以保存文件。

如何选择地址栏输入所需的路径?或者如何更改默认保存路径?

编辑:感谢您的反馈。这是脚本:

function print_files($secure_pdf_dir)
    #Retrieves the name for the .xps files
    Get-ChildItem $secure_pdf_dir -Filter *.pdf -Recurse | Foreach-Object 
        #For each .pdf file in that directory, continue
        same_time $_.FullName
    

## The following function keeps checking for a new window called "Save Print Output As"
## When the window shows up, it enters the name of the file and press ENTER
function enter_my_names($xps_dir, $fullname)
    $wshell = New-Object -ComObject wscript.shell;
    while($wshell.AppActivate('Save Print Output As') -ne $true)
        $wshell.AppActivate('Save Print Output As')
    
    $basename = [io.path]::GetFileNameWithoutExtension($fullname)
    #This is where the name is actually entered
    $wshell.SendKeys($xps_dir\$basename)
    $wshell.SendKeys("ENTER")
   

## The following function launches simultaneously a print job on the input file 
## and a function waiting for the print job to show up to name the file
workflow same_time
    Param(
        $fullname
    )
    parallel
        Start-Process -FilePath $fullname –Verb Print -PassThru
        enter_my_names $xps_dir $fullname    
    

#MAIN PROGRAM
#Here the script saves your current printer as default
$defprinter = Get-WmiObject -Query "Select * from Win32_Printer Where Default=$true"
#Queries for a XPS printer
$printer = Get-WmiObject -Query "Select * from Win32_Printer Where Name='Microsoft XPS Document Writer'"
#Sets the XPS printer as Default
$printer.SetDefaultPrinter()
#Starts the main job
print_files($secure_pdf_dir)
#Sets the old default printer back as default again
$defprinter.SetDefaultPrinter()
#This is a small delay to be sure everything is completed before closing Adobe Reader. You can probably shorten it a bit
sleep 2
#Finally, close Adobe Reader
Get-Process "acrord32" | Stop-Process

$xps_dir 变量似乎没有正确传递给函数。

编辑:尝试将 $xps_dir 添加到 enter_my_names 函数时出现错误:

Microsoft.PowerShell.Utility\Write-Error : Cannot validate argument on parameter 
'FilePath'. The argument is null or empty. Provide an argument that is not null or 
empty, and then try the command again.
At same_time:115 char:115
+ 
    + CategoryInfo          : NotSpecified: (:) [Write-Error], ParameterBindingValidati 
   onException
    + FullyQualifiedErrorId : System.Management.Automation.ParameterBindingValidationEx 
   ception,Microsoft.PowerShell.Commands.WriteErrorCommand
    + PSComputerName        : [localhost]

【问题讨论】:

【参考方案1】:

我不确定您是否已经完全解决了这个问题,或者我误读了您的帖子,但我能够从您最初的帖子中实现一些代码来完成我的项目计算机科学人];所以我想分享一些我做的事情,希望能对你有所帮助(如果你还处于那个十字路口)。

一些兴趣点: -我的整个过程是一个批量报告生成器。可变数量的 .XML 样式表被发送到 IE,因为 javascript 子例程对报告进行编号;为此,我使用 Visual Basic 进行一些数据库解析,将值传递到形成 .XML 样式表所需的自定义脚本中,然后 VB 使用创建 IE com 对象所需的各种 PS 命令创建 PS .ps1 文件。最后VB调用.ps1脚本,将样式表发送到IE,等待html渲染,发送打印命令,关闭对象,生成报表。

-虽然您的最终目标是生成 XPS,但我的目标是完全渲染 HTML,然后使用 PDF 打印机打印;我假设我们有一个类似的过程,因为我们必须在中间阶段使用一个对话框(在这种情况下,使用 sendkeys 与之交互);这就是我将在下面讨论的内容,希望能有所帮助!

所以,有两点讨论:

    首先,更多的是一般性观察/查询:我看不到您的 $xps_dir 变量实际上是在哪里定义的;我提到这一点是因为 $xps_dir 传递的值可能存在与字符串相关的问题。检查字符串以确保其“漂亮”的一种方法是使用 OUT-FILE 命令将其传递给 .txt 或其他内容:

"$xps_dir" | Out-File -FilePath "C:\somefolder\sometext.txt" -Append

文本文件本身不需要存在,但文件确实存在……上面的命令将创建文本文件。

另外,如果您可以查看 powershell 提示符,可以使用 WRITE-HOST。

无论哪种方式,我都想知道最终编译的字符串是否没有正确编译,因此它无法将其识别为目录。

    我认为更可能发生的是 SENDKEYS 没有被发送到正确的字段。例如,通过使用您的代码,我 [终于] 能够将我的“另存为”对话框设置为对象并与之交互。 (使用我的 PDF 打印机时,我得到“另存为”对话框)。

一开始我尝试发送文件名,然后发送回车。我认为这很好,因为在手动交互期间,“另存为”对话框的焦点转到“文件名”字段;但是,尝试后:

$wshell.SendKeys($myfilename) $wshell.SendKeys("ENTER")

我意识到 SendKeys 命令正在将密钥发送到“保存在”下拉菜单(或者可能是“另存为”对话框的第一个元素)。因此,我手动单击“保存在”字段内,然后按选项卡直到我到达 1.“文件名”(写下标签的数量)和 2.“保存”按钮(写下标签的数量) )。通过添加 SendKeys("TAB") 以对应于我观察到的标签数量,我能够成功输入我的姓名字符串并关闭打印对话框:

$wshell.SendKeys("TAB")
    $wshell.SendKeys("TAB")
    $wshell.SendKeys("TAB")
    $wshell.SendKeys("TAB")
    $wshell.SendKeys("TAB")
$wshell.SendKeys($myfilename)
    $wshell.SendKeys("TAB")
    $wshell.SendKeys("TAB")
        $wshell.SendKeys("ENTER")

注意:您的对话框的选项卡数量可能会有所不同,因此我强烈建议您手动运行以计算有多少选项卡可以让您到达要与之交互的字段。

最后,我有一个想法供参考:

我已经(非常成功地)使用 VB 和 PS 来使用 html 元素来动态增强我的例程。由于我们能够将对话框设置为 Com 对象,我的下一个目标是尝试利用相应的“元素”,类似于如何访问 html 元素(或更一般地说,面向对象的语言允许) .这样,我也许可以更好地与对话框交互,而不会遭受 SendKeys 的缺点:

    必须作为活动进程运行;用户不能使用任何其他窗口,否则可能会向他们发送密钥; 密钥基于计数;该计数的任何变化都需要更新/编辑子例程,使其没有弹性;

此外,我还没有对错误窗口做任何工作,但我已经注意到“您的文档具有相同的名称等等”,所以请注意。

尽管我们正在做两件不同的事情,但这是我例程这部分的最终代码,以防它有助于提供上下文:

#send command to internet explorer application with execWB; 6 for print, 2 for no user prompt on window
while ( $ie.busy )  Start-Sleep -second 3 
$ie.execWB(6,2)

#create dialog box object
    $wshell = New-Object -ComObject wscript.shell;
    while($wshell.AppActivate('Save As') -ne $true) Start-Sleep -second 3 
        $wshell.AppActivate('Save As')


#create file string from 3 strings: directory,basename returned, file extension
#the return from my output log is: "c:\test_folder\mybasenamestring.PDF"
        $mydirectory = "c:\test_folder\"
            $mybasename = [io.path]::GetFileNameWithoutExtension($fullname)
            $myextension = ".PDF"
            $myfilename = "$mydirectory$mybasename$myextension"

#Using tabs to navigate around the dialog window; send my string to the 'File Name' field, then tab to 'Save' and send enter
#This is where the name is actually entered
    $wshell.SendKeys("TAB")
        $wshell.SendKeys("TAB")
        $wshell.SendKeys("TAB")
        $wshell.SendKeys("TAB")
        $wshell.SendKeys("TAB")
    $wshell.SendKeys($myfilename)
        $wshell.SendKeys("TAB")
        $wshell.SendKeys("TAB")
            $wshell.SendKeys("ENTER")

#going to add a command to report on the file size of the pdf; the pdf will stay 0kb until its fully generated.  Once fully generated will add the $ie.quit or the kill command here for the $ie object

#this sends a stop process command to kill powershell since I'm running it as a ps1 file and it will remain open otherwise

stop-process -Id $PID

最后一件事:我发现大写有些奇怪,所以我更新了最终的 SendKeys 以将字符串大写,因为无论如何我都想要全部大写:

$wshell.SendKeys($myfilename.toupper())

希望这会有所帮助!感谢发帖;我终于能够完成我的整个过程。当我清理和改进时,如果我发现这方面的改进,我会尽量记住分享。感谢您的帮助!

【讨论】:

【参考方案2】:

将包含所需目录的变量(在本例中为 $xps_dir)传递给进程中的每个函数,直到它到达 enter_my_names 函数,然后可以使用 $wshell.SendKeys("$xps_dir\$basename") 将其发送到窗口。

function print_files($xps_dir, $secure_pdf_dir)
    #Retrieves the name for the .xps files
    Get-ChildItem $secure_pdf_dir -Filter *.pdf -Recurse | Foreach-Object 
        #For each .pdf file in that directory, continue
        same_time $xps_dir $_.FullName
    

## The following function keeps checking for a new window called "Save Print Output As"
## When the window shows up, it enters the name of the file and press ENTER
function enter_my_names
    param ($xps_dir, $fullname)
    $wshell = New-Object -ComObject wscript.shell;
    while($wshell.AppActivate('Save Print Output As') -ne $true)
        $wshell.AppActivate('Save Print Output As')
    
    $basename = [io.path]::GetFileNameWithoutExtension($fullname)
    #This is where the name is actually entered
    $wshell.SendKeys("$xps_dir\$basename")
    $wshell.SendKeys("ENTER")

## The following function launches simultaneously a print job on the input file 
## and a function waiting for the print job to show up to name the file
workflow same_time
    Param(
        $xps_dir, $fullname
    )
    parallel
        Start-Process -FilePath $fullname –Verb Print -PassThru
        enter_my_names $xps_dir $fullname
    

#MAIN PROGRAM
#Here the script saves your current printer as default
$defprinter = Get-WmiObject -Query "Select * from Win32_Printer Where Default=$true"
#Queries for a XPS printer
$printer = Get-WmiObject -Query "Select * from Win32_Printer Where Name='Microsoft XPS Document Writer'"
#Sets the XPS printer as Default
$printer.SetDefaultPrinter()
#Starts the main job
print_files $xps_dir $secure_pdf_dir
#Sets the old default printer back as default again
$defprinter.SetDefaultPrinter()
#This is a small delay to be sure everything is completed before closing Adobe Reader. You can probably shorten it a bit
sleep 2
#Finally, close Adobe Reader
Get-Process "acrord32" | Stop-Process

【讨论】:

【参考方案3】:

文件对话框将接受文件名字段中的路径,因此不要发送文件名file.pdf,而是发送文件的完整路径C:\folder\folder\file.pdf


编辑:

您可以像这样发送文件夹路径:

$wshell.SendKeys($xps_dir)
$wshell.SendKeys("ENTER")
$wshell.SendKeys($basename)
$wshell.SendKeys("ENTER")

【讨论】:

感谢您的意见。我添加了上面的代码。我试图将包含所需目录的变量传递给函数,但到目前为止没有运气。该脚本按预期工作,函数中没有 $xps_dir 变量。 我已经编辑了答案,您需要分别发送目录和文件名。 即使这样,信息也没有从 $xps_dir 传递,我得到一个错误。我在原始帖子中添加了它。 我对 PS 的有限知识给我带来了麻烦。我没有通过被调用的一系列函数传递变量。一旦我将它传递给每个函数,我就可以将变量用作$wshell.SendKeys($xps_dir\$basename)

以上是关于如何使用 powershell 设置文件的保存位置?的主要内容,如果未能解决你的问题,请参考以下文章

我们如何使用Windows Powershell脚本替换文本文件中的日期?

如何使用 Powershell Compress-Archive 仅压缩文件夹中的 pdf?

使用 PowerShell 创建 ISO 映像:如何将 IStream 保存到文件?

如何使用 PowerShell 或 C# 将网页保存到 HTML 文件中?

如何更改多个 .txt 文件中的字符并保存/覆盖 Powershell 中的现有文件

如何将打印机设置保存为文本文件