使用 Invoke-Expression 调用时将路径脚本变量传递给 sqlcmd
Passing path scripting variable to sqlcmd when called using Invoke-Expression
我正在尝试创建一个用于创建数据库的 powershell 脚本。 createDb.ps1 的相关部分是:
param([string] $server,
[string] $dbName)
$scriptpath = "C:\script\path"
$cDb = "master"
$line = "script.sql"
$outfile = "\log.txt"
$dbDir = "C:\database path\"
$command = @"
sqlcmd -b -S $server -d $cDb -i '$scriptpath$line' -o '.$outfile' -v dbLocation='$dbDir' dbName=$dbName
"@
Invoke-Expression $command
我使用以下参数调用脚本:
createDb.ps1 -server localhost -dbName TestDb
但是,当我 运行 这样做时,出现以下错误:
sqlcmd: 'dbDir=C:\database path\" dbName=TestDb': Invalid argument. Enter '-?' for help.
当我从命令行执行以下命令时,一切正常:
sqlcmd -b -S localhost -d master -i "C:\script\path\script.sql" -o ".\log.txt" -v dbLocation="C:\database path\" dbName=TestDb
当 运行 sqlcmd:
时,请使用双引号将您的属性值括起来
$command = @"
sqlcmd -b -S $server -d $cDb -i "$scriptpath$line" -o ".$outfile" -v dbLocation="$dbDir" dbName=$dbName
"@
不要先将命令行构建为 string 然后再将其传递给 Invoke-Expression
- 不仅如此不必要,它会导致参数分区问题。
直接调用命令:
sqlcmd -b -S $server -d $cDb -i $scriptpath$line -o ".$outfile" -v dbLocation=`"$dbDir`" `
dbName=$dbName
请注意 ".$outfile"
和 dbLocation=`"$dbDir`"
如何需要特殊处理:
由于 PowerShell parsing quirk(自 PSv5.1 起),.$
在未加引号的标记的开头导致它被分解为 2 个参数。在 "..."
中包含 .$outfile
可以防止这个问题。
在 PowerShell 解析了您的命令后,它基本上 重建 命令行 选择性 double-quoting 参数 在将其传递给系统执行之前。虽然这通常按预期工作,但也有一些极端情况,例如 dbLocation=$dbDir
:
由于 $dbDir
- C:\database path\
的值包含 空格 ,PowerShell 将包含 [=17= 的扩展结果] 在 "..."
中以确保它被识别为 单个 参数,从而产生 "dbLocation=C:\database path\"
- 和 sqlcmd
may 对此犹豫不决。
通过在令牌中显式嵌入双引号 - 使用`"
,转义"
个字符。 - PowerShell 单独保留 dbLocation=`"$dbDir`"
的扩展结果,产生:dbLocation="C:\database path\"
警告:
大多数目标程序将 \"
解释为不具有 句法 函数(在这种情况下:不是作为一个结束"
,恰好前面有一个\
),而是作为一个转义,嵌入 "
导致 损坏的参数解析 - 根据目标程序,您可能必须转义最终 \
- 或者可能所有 \
个实例 - 作为 \
.
重要的是要理解,在 Windows 上,最终总是由目标程序来解释命令行 ;有关详细信息,请参阅 this answer。
一般:
当变量引用作为参数传递给外部实用程序时,不需要double-quoting ,即使引用变量的值包含空格(或其他元字符)。
- 也就是说,通常 double-quoting 将 变量引用与文字/其他变量引用相结合的记号是养成的好习惯(例如,
"$scriptpath$line"
和".$outfile"
),因为当这些标记被视为 多个 参数时的精确规则不容易记住 - 请参阅底部的 link。
但是,您需要注意 PowerShell 自己的元字符的未引用实例 - 例如 ,
通常,@
在令牌的开头 - 并且 `
- 转义它们 以将它们用作文字(在手头的情况下不是问题)。
引用风格仅对 PowerShell 重要 - 一旦 PowerShell 执行了自己的解析并可能扩展了变量引用, then-literal 标记被重新组合成一个命令行,该命令行根据需要在幕后使用 双引号 以保留参数边界,即使原始命令行包含 single-quoted令牌。
- 例如,PowerShell 命令行
foo.exe 'bar baz' $env:ProgramFiles $env:OS
在调用 foo.exe
时将转换为 foo.exe "bar baz" "C:\Program Files" Windows_NT
。
请注意 double-quoting 如何根据需要使用嵌入空格的值,而不管原始命令行中使用了什么引号。
有关 PowerShell 如何解析参数的全面讨论,请参阅我的 。
我正在尝试创建一个用于创建数据库的 powershell 脚本。 createDb.ps1 的相关部分是:
param([string] $server,
[string] $dbName)
$scriptpath = "C:\script\path"
$cDb = "master"
$line = "script.sql"
$outfile = "\log.txt"
$dbDir = "C:\database path\"
$command = @"
sqlcmd -b -S $server -d $cDb -i '$scriptpath$line' -o '.$outfile' -v dbLocation='$dbDir' dbName=$dbName
"@
Invoke-Expression $command
我使用以下参数调用脚本:
createDb.ps1 -server localhost -dbName TestDb
但是,当我 运行 这样做时,出现以下错误:
sqlcmd: 'dbDir=C:\database path\" dbName=TestDb': Invalid argument. Enter '-?' for help.
当我从命令行执行以下命令时,一切正常:
sqlcmd -b -S localhost -d master -i "C:\script\path\script.sql" -o ".\log.txt" -v dbLocation="C:\database path\" dbName=TestDb
当 运行 sqlcmd:
时,请使用双引号将您的属性值括起来$command = @"
sqlcmd -b -S $server -d $cDb -i "$scriptpath$line" -o ".$outfile" -v dbLocation="$dbDir" dbName=$dbName
"@
不要先将命令行构建为 string 然后再将其传递给 Invoke-Expression
- 不仅如此不必要,它会导致参数分区问题。
直接调用命令:
sqlcmd -b -S $server -d $cDb -i $scriptpath$line -o ".$outfile" -v dbLocation=`"$dbDir`" `
dbName=$dbName
请注意 ".$outfile"
和 dbLocation=`"$dbDir`"
如何需要特殊处理:
由于 PowerShell parsing quirk(自 PSv5.1 起),
.$
在未加引号的标记的开头导致它被分解为 2 个参数。在"..."
中包含.$outfile
可以防止这个问题。在 PowerShell 解析了您的命令后,它基本上 重建 命令行 选择性 double-quoting 参数 在将其传递给系统执行之前。虽然这通常按预期工作,但也有一些极端情况,例如
dbLocation=$dbDir
:由于
$dbDir
-C:\database path\
的值包含 空格 ,PowerShell 将包含 [=17= 的扩展结果] 在"..."
中以确保它被识别为 单个 参数,从而产生"dbLocation=C:\database path\"
- 和sqlcmd
may 对此犹豫不决。通过在令牌中显式嵌入双引号 - 使用
`"
,转义"
个字符。 - PowerShell 单独保留dbLocation=`"$dbDir`"
的扩展结果,产生:dbLocation="C:\database path\"
警告:
大多数目标程序将
\"
解释为不具有 句法 函数(在这种情况下:不是作为一个结束"
,恰好前面有一个\
),而是作为一个转义,嵌入"
导致 损坏的参数解析 - 根据目标程序,您可能必须转义最终\
- 或者可能所有\
个实例 - 作为\
.重要的是要理解,在 Windows 上,最终总是由目标程序来解释命令行 ;有关详细信息,请参阅 this answer。
一般:
当变量引用作为参数传递给外部实用程序时,不需要double-quoting ,即使引用变量的值包含空格(或其他元字符)。
- 也就是说,通常 double-quoting 将 变量引用与文字/其他变量引用相结合的记号是养成的好习惯(例如,
"$scriptpath$line"
和".$outfile"
),因为当这些标记被视为 多个 参数时的精确规则不容易记住 - 请参阅底部的 link。
- 也就是说,通常 double-quoting 将 变量引用与文字/其他变量引用相结合的记号是养成的好习惯(例如,
但是,您需要注意 PowerShell 自己的元字符的未引用实例 - 例如
,
通常,@
在令牌的开头 - 并且`
- 转义它们 以将它们用作文字(在手头的情况下不是问题)。引用风格仅对 PowerShell 重要 - 一旦 PowerShell 执行了自己的解析并可能扩展了变量引用, then-literal 标记被重新组合成一个命令行,该命令行根据需要在幕后使用 双引号 以保留参数边界,即使原始命令行包含 single-quoted令牌。
- 例如,PowerShell 命令行
foo.exe 'bar baz' $env:ProgramFiles $env:OS
在调用foo.exe
时将转换为foo.exe "bar baz" "C:\Program Files" Windows_NT
。
请注意 double-quoting 如何根据需要使用嵌入空格的值,而不管原始命令行中使用了什么引号。
- 例如,PowerShell 命令行
有关 PowerShell 如何解析参数的全面讨论,请参阅我的