Powershell SQLCMD 无法识别输入文件 - 通过路径将通过 Get-ChildItem 获取的文件传递给外部程序
Powershell SQLCMD not recognizing inputfile - passing files obtained via Get-ChildItem to external programs by path
我有这段代码,它获取当前目录中的所有 *.sql 文件以及每个子目录 运行 将它们放在指定的 $server
和 $database
:
$dirs = Get-ChildItem | ?{ $_.PSIsContainer }
foreach ($d in $dirs)
{
$Result = Get-ChildItem ./ -Filter *.sql
Foreach($item in $Result)
{
echo $item.Name
sqlcmd /S $server /d $database -E -i $item
}
}
这段代码工作得很好,但它只是通往脚本的垫脚石,该脚本应该获取 子目录 和 [= 中的所有 *.sql 文件39=] 他们在服务器上。
这段代码是一样的,区别是./
被$d
替换了,不生效:
$dirs = Get-ChildItem | ?{ $_.PSIsContainer }
foreach ($d in $dirs)
{
$Result = Get-ChildItem $d -Filter *.sql
Foreach($item in $Result)
{
echo $item.Name
sqlcmd /S $server /d $database -E -i $item
}
}
相反,我得到了错误:
SQLCMD.EXE : Sqlcmd: 'INSERT Script1.sql': Invalid filename.
At E:\dir\Run all SQL in dir.ps1:23 char:12
+ sqlcmd <<<< /S $server /d $database -E -i $item
+ CategoryInfo : NotSpecified: (Sqlcmd: 'INSERT...valid filename.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
据我从测试中可以看出,$item
在这两种情况下都是相同的,$Result
看起来也一样。
我不知道为什么第二个版本不起作用。我希望脚本遍历它所在的当前目录的所有子目录,获取每个文件中的所有 *.sql 文件,打印文件名并 运行 它针对集合 $server
和 $database
.
$item
是一个 [FileInfo]
对象。
更改为 $item.FullName
,其中将包含完整的文件路径。
我假设第一个版本有效,因为该文件位于同一目录中。
添加到:
[System.IO.FileInfo]
和 [System.IO.DirectoryInfo]
由 Get-ChildItem
/ Get-Item
输出的实例通常 字符串化到 仅文件名 (.Name
) 而不是 完整路径 (.FullName
),其中,结合 PowerShell 的参数绑定,可能会导致细微的错误:
注意:我在这里松散地使用文件名来指代文件名和目录名;换句话说:file-system 项的名称。
将这样的实例传递给外部程序,就像您的情况一样,然后仅传递文件名 , 因为 外部程序的所有参数都 隐式字符串化 .
- 在这种情况下使用
.FullName
确实是正确的解决方案。
然而,更令人惊讶的是,该问题还影响 cmdlet / 函数调用:
在您的代码中,Get-ChildItem $d
中的 $d
也 作为 字符串 [=82] 传递=] 因此仅作为文件名,因为 - 不幸的是 - -Path
参数将其 direct 参数绑定为 strings 而不是识别 [System.IO.FileInfo]
/ [System.IO.DirectoryInfo]
实例;相比之下,通过 管道 传递此类实例可以正常工作。
因此,即使 $d
明确标识了一个给定的目录,也只有它的 name 被传递,最多 发生 工作,最坏情况下 指向不同的目录 ,否则 失败 .
- 这里使用
.FullName
也可以绕过问题:Get-ChildItem $d.FullName
这个问题已经 reported on GitHub,我鼓励任何对修复感兴趣的人在那里发表他们的意见。
关于向后兼容性的说明:更改 [System.IO.FileInfo]
和 [System.IO.DirectoryInfo]
字符串化的方式(字符串化为它们的 .FullName
属性 值)可能太破坏了更改,但是按照描述更改参数绑定在链接的 GitHub 问题中非常值得考虑,因为当前的行为基本上被破坏了。
我有这段代码,它获取当前目录中的所有 *.sql 文件以及每个子目录 运行 将它们放在指定的 $server
和 $database
:
$dirs = Get-ChildItem | ?{ $_.PSIsContainer }
foreach ($d in $dirs)
{
$Result = Get-ChildItem ./ -Filter *.sql
Foreach($item in $Result)
{
echo $item.Name
sqlcmd /S $server /d $database -E -i $item
}
}
这段代码工作得很好,但它只是通往脚本的垫脚石,该脚本应该获取 子目录 和 [= 中的所有 *.sql 文件39=] 他们在服务器上。
这段代码是一样的,区别是./
被$d
替换了,不生效:
$dirs = Get-ChildItem | ?{ $_.PSIsContainer }
foreach ($d in $dirs)
{
$Result = Get-ChildItem $d -Filter *.sql
Foreach($item in $Result)
{
echo $item.Name
sqlcmd /S $server /d $database -E -i $item
}
}
相反,我得到了错误:
SQLCMD.EXE : Sqlcmd: 'INSERT Script1.sql': Invalid filename.
At E:\dir\Run all SQL in dir.ps1:23 char:12
+ sqlcmd <<<< /S $server /d $database -E -i $item
+ CategoryInfo : NotSpecified: (Sqlcmd: 'INSERT...valid filename.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
据我从测试中可以看出,$item
在这两种情况下都是相同的,$Result
看起来也一样。
我不知道为什么第二个版本不起作用。我希望脚本遍历它所在的当前目录的所有子目录,获取每个文件中的所有 *.sql 文件,打印文件名并 运行 它针对集合 $server
和 $database
.
$item
是一个 [FileInfo]
对象。
更改为 $item.FullName
,其中将包含完整的文件路径。
我假设第一个版本有效,因为该文件位于同一目录中。
添加到
[System.IO.FileInfo]
和 [System.IO.DirectoryInfo]
由 Get-ChildItem
/ Get-Item
输出的实例通常 字符串化到 仅文件名 (.Name
) 而不是 完整路径 (.FullName
),其中,结合 PowerShell 的参数绑定,可能会导致细微的错误:
注意:我在这里松散地使用文件名来指代文件名和目录名;换句话说:file-system 项的名称。
将这样的实例传递给外部程序,就像您的情况一样,然后仅传递文件名 , 因为 外部程序的所有参数都 隐式字符串化 .
- 在这种情况下使用
.FullName
确实是正确的解决方案。
- 在这种情况下使用
然而,更令人惊讶的是,该问题还影响 cmdlet / 函数调用:
在您的代码中,
Get-ChildItem $d
中的$d
也 作为 字符串 [=82] 传递=] 因此仅作为文件名,因为 - 不幸的是 --Path
参数将其 direct 参数绑定为 strings 而不是识别[System.IO.FileInfo]
/[System.IO.DirectoryInfo]
实例;相比之下,通过 管道 传递此类实例可以正常工作。因此,即使
$d
明确标识了一个给定的目录,也只有它的 name 被传递,最多 发生 工作,最坏情况下 指向不同的目录 ,否则 失败 .- 这里使用
.FullName
也可以绕过问题:Get-ChildItem $d.FullName
- 这里使用
这个问题已经 reported on GitHub,我鼓励任何对修复感兴趣的人在那里发表他们的意见。
关于向后兼容性的说明:更改[System.IO.FileInfo]
和[System.IO.DirectoryInfo]
字符串化的方式(字符串化为它们的.FullName
属性 值)可能太破坏了更改,但是按照描述更改参数绑定在链接的 GitHub 问题中非常值得考虑,因为当前的行为基本上被破坏了。