首页 > 解决方案 > 从传递参数的 vbs 调用 power shell 脚本时出错

问题描述

我有一个非常简单的 VBScript,它执行 PowerShell 脚本并试图传递几个参数。

无论我尝试了什么,它都失败了并且不接受论点:

Dim WshShell
Dim cmdStr
Const ForReading = 1, ForWriting = 2 ,ForAppending = 8
curYear = Year(Date)
curMon  = Month(Date)
curDay  = Day(Date)
curHr   = Hour(Time)
curMin  = Minute(Time)
curSec  = Second(Time)

datestg = curYear & curMon & curDay & curHr & curMin & curSec

Set WshShell = WScript.CreateObject("WScript.Shell")
Dim inputDir
inputDir = InputBox("Input Directory ( can be full file path ) : ", "Message Box")

inputDirLen = Len(inputDir)

If inputDirLen > 0 Then
    lastchar = Mid(inputDir, inputDirLen-1, 1)
    If lastchar <> "\" Then
        inputDir = inputDir & "\"
    End If
End If

outFileMask = InputBox("Output file name mask ( files will be created in previously entered directory ) : ", "Message Box")
newDate = InputBox("Desired Date ( format of the date should be yyyy-mm-ddThh:mm:ss ) : ", "Message Box")

cmdStr = "%comspec% /c dir " & inputDir & "*.xml > dir.lst"
cmdrc = wshShell.Run(cmdStr, , True)

'create file system object
Set fs = CreateObject("Scripting.FileSystemObject")
Set fso = CreateObject("Scripting.FileSystemObject")

dirFileName = "dir.lst"

outFileName  = inputDir & outFileMask & "_" & datestg &".xml"
Set infile   = fs.OpenTextFile(dirFileName, ForReading)
Set fileOut  = fso.CreateTextFile(outFileName, True)
Set objShell = CreateObject("WScript.Shell")

objShell.Run("powershell -NoExit -File  .\psscript.ps1 " & infile)

infile.Close
fileOut.Close
WScript.Quit

这甚至失败了objshell.Run。如果我拿走任何 arg,那么它将运行,但由于参数中的 null 值,它将在 PowerShell 脚本中失败。

这是完整的 PowerShell 脚本:

$inputPath  = $args[0]
$newDate    = $args[1]
$outputPath = $args[2]

[xml]$xmlDoc = Get-Content $inputPath

foreach ($element in $xmlDoc.element1) {
    $element.DateTime = $newDate
}

$xmlDoc.Save($outputPath)

标签: powershellvbscript

解决方案


您的 VBScript 正在打开带有 XML 文件列表的文件,然后尝试将该句柄传递给 PowerShell 脚本。那是行不通的。

您可以在这里做几件事:

  • 读取 VBScript 中的 XML 文件列表并循环调用 PowerShell 脚本:

    Set sh  = CreateObject("WScript.Shell")
    Set fso = CreateObject("Scripting.FileSystemObject")
    
    outFileName = inputDir & outFileMask & "_" & datestg &".xml"
    
    Set infile = fs.OpenTextFile(dirFileName, ForReading)
    Do Until infile.AtEndOfStream
        line = infile.ReadLine
        sh.Run "powershell -File .\your.ps1 " & line & " " & newDate & " " & outFileName
    Loop
    infile.Close
    

    但是,这意味着您要为每次迭代生成一个新进程,这在性能方面很糟糕。

  • 将带有 XML 文件列表的文件传递给 PowerShell 脚本:

    Set sh = CreateObject("WScript.Shell")
    
    outFileName = inputDir & outFileMask & "_" & newDate &".xml"
    dirFileName = sh.CurrentDirectory & "\" & dirFileName
    
    sh.Run "powershell -File .\your.ps1 " & dirFileName & " " & newDate & " " & outFileName
    

    您希望传递dirFileName文件的完整路径,因为不能保证 VBScript 和 PowerShell 代码将具有相同的工作目录。传递列表而不是单个文件也需要更改您的 PowerShell 代码:

    $inputPath  = $args[0]
    $newDate    = $args[1]
    $outputPath = $args[2]
    
    Get-Content $inputPath | ForEach-Object {
        [xml]$xmlDoc = Get-Content $_.FullName
    
        foreach ($element in $xmlDoc.element1) {
            $element.DateTime = $newDate
        }
    
        $xmlDoc.Save($outputPath)
    }
    
  • 传递输入目录并让 PowerShell 列出:

    Set sh  = CreateObject("WScript.Shell")
    
    outFileName = inputDir & outFileMask & "_" & newDate &".xml"
    
    sh.Run "powershell -File .\your.ps1 " & inputDir & " " & newDate & " " & outFileName
    

    同样,这也需要更改您的 PowerShell 代码:

    $inputPath  = $args[0]
    $newDate    = $args[1]
    $outputPath = $args[2]
    
    Get-ChildItem $inputPath -Filter '*.xml' | ForEach-Object {
        [xml]$xmlDoc = Get-Content $_.FullName
    
        foreach ($element in $xmlDoc.element1) {
            $element.DateTime = $newDate
        }
    
        $xmlDoc.Save($outputPath)
    }
    
  • 您还可以在 PowerShell 中完成所有操作并完全放弃 VBScript(这可以说是最干净的方法):

    [CmdletBinding()]
    Param(
        [Parameter(Mandatory=$true)]
        [ValidateScript(Test-Path -LiteralPath $_)]
        [String]$inputPath,
    
        [Parameter(Mandatory=$true)]
        [ValidatePattern('^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$')]
        [String]$newDate,
    
        [Parameter(Mandatory=$true)]
        [String]$outFileMask
    )
    
    $datestg     = (Get-Date).ToString('yyyyMMddHHmmss')
    $outFileName = Join-Path $inputPath, "${outFileMask}_${datestg}.xml"
    
    Get-ChildItem $inputPath -Filter '*.xml' | ForEach-Object {
        [xml]$xmlDoc = Get-Content $_.FullName
    
        foreach ($element in $xmlDoc.element1) {
            $element.DateTime = $newDate
        }
    
        $xmlDoc.Save($outFileName)
    }
    

但是请注意,使用所有这些方法,PowerShell 将在每次迭代时覆盖输出文件。如果您要处理多个 XML 文件并希望将它们写入不同的输出文件,则需要在循环中创建单独的输出文件名。


推荐阅读