我有这个代码,它获取当前目录中的所有* .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文件并在服务器上运行它们。
此代码与./
替换为$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
和{{1 }}
答案 0 :(得分:2)
$item
是[FileInfo]
个对象。
更改为$item.FullName
,其中包含完整的文件路径。
我认为第一个版本有效,因为该文件位于同一目录中。
答案 1 :(得分:1)
添加到gms0ulman's helpful answer:
[System.IO.FileInfo]
和[System.IO.DirectoryInfo]
实例按Get-ChildItem
/ Get-Item
输出通常仅字符串化为文件名(.Name
)而不是完整路径(.FullName
),与PowerShell的参数绑定结合使用,会导致微妙的错误强>:
注意:我在这里松散地使用文件名来引用文件的名称和目录的名称;换句话说:文件系统项目的名称。
将此类实例传递给外部程序,就像您的情况一样,然后仅传递文件名,因为外部程序的所有参数是隐式字符串化 。
.FullName
确实是正确的解决方案。然而,更令人惊讶的是,问题也会影响 cmdlet /函数调用:
在您的代码中,$d
中的Get-ChildItem $d
也作为字符串传递,因此仅作为文件名,因为 - 不幸的是 - -Path
参数将直接参数绑定为字符串 ,而不是识别[System.IO.FileInfo]
/ {{1这样的实例;相反,通过管道传递此类实例的工作正常。
因此,即使[System.IO.DirectoryInfo]
明确标识给定目录,也只传递其名称,最好发生才能工作,最差定位到不同的目录,否则失败。
$d
也会绕过问题:.FullName
这个问题一直是reported on GitHub,我鼓励任何对修复感兴趣的人都能在那里听到他们的声音。
关于向后兼容性的注释:更改Get-ChildItem $d.FullName
和[System.IO.FileInfo]
stringify的方式(字符串化为[System.IO.DirectoryInfo]
属性值)可能会破坏更改,但更改参数绑定,如链接的GitHub中所述鉴于目前的行为基本上已被打破,这个问题值得考虑。