我有一个脚本,它可以检索与给定文件夹路径中的文件相关的信息,然后通过SQLPS模块和SQLINSERT INTO
命令传递这些值来填充我的数据库表。
除了文件或文件夹路径包含一个离代的少数情况外,这都可以正常工作。
相关代码块为
$PathArowCount=0
$filelist = Get-ChildItem -Path $localPath -Recurse | Where-Object {!($_.PSIsContainer)} | Select DirectoryName, Name, Length, LastWriteTime
ForEach ($file in $filelist)
{
# Retrieve all values into variables. Value passed to the insert statement needs to be within single quotes, so escaping them out here so they're included later.
$insFolder = "`'$($file.DirectoryName)`'"
$insFile = "`'$($file.Name)`'"
$insLength = "`'$($file.Length)`'"
$insLastWrite = "`'$($file.LastWriteTime)`'"
write-host "$insFolder`n$insFile`n$insLength`n$insLastWrite`n---"
# Generate the SQL insert statement using the values above
$sqlCommand.CommandText = "INSERT INTO [$dbCompare].[dbo].[PathA] (FilePath,FileName,FileLength,LastWriteTime) VALUES ($insFolder,$insFile,$insLength,$insLastWrite)"
# Execute the SQL command while also incrementing the row count for use later
$PathArowCount = $PathArowCount + $sqlCommand.ExecuteNonQuery()
}
write-output "$(Get-Date) - $PathArowCount rows (eg files found) inserted into table PathA"
正如你所看到的,我已经设置了输入值$insFolder
,$insFile
,$insLength
和$insLastWrite
,这些值传递给SQL命令,因为这是SQL所期望的。
我的问题是文件/文件夹名称包含撇号/单引号,例如:
c:\Myfiles\Keith's Document.docx
我从$sqlCommand.ExecuteNonQuery()
行得到以下错误:
Exception calling "ExecuteNonQuery" with "0" argument(s): Incorrect syntax near 's'.
Unclosed quotation mark after the character string')'."
Write-Host
行向我展示了在这一点上$insFile
确实正确地包含了整个字符串,每一端都有单引号,例如:
'Keith's Document.docx'
但是从错误SQL可能会看到传递给它的值为
'Keith'
然后用意外的参数出错:
s Document.docx'
我显然需要找到并逃离出的字符在相关的地方,我已经尝试了各种组合例如
$insFile = "`'$($file.Name).Replace("`'","\`'")`'"
我用反勾转义比较值中的单引号,并尝试在反勾上添加一个\
以在字符到达SQL时转义该字符,但我尝试过的每个组合都会抛出一个PowerShell错误,所以我不确定神奇组合是什么。
2条答案
按热度按时间dxpyg8gm1#
tl;dr
最好使用parameterized query而不是 * 字符串插值,这既可以避免引用问题,更重要的是,可以消除SQL injection攻击的任何可能性。
SqlCommand.ExecuteNonQuery()
的示例。'
转义为''
:报价注意事项:
PowerShell对 string literals 的透视图:
"..."
内部-可扩展(插值)字符串-'
字符。不需要转义,可以按原样使用。'...'
内部-逐字字符串-嵌入的'
字符,必须转义为''
-然而,这里 * 不 * 涉及这样的字符串;见下文。T-SQL透视图(其中字符串字面量称为 * 字符串常量 *):
'...'
嵌入在查询字符串中的字符串碰巧 * 也 * 需要将string-internal'
转义为''
。"..."
文字,并且这两种形式都不是插值)1sbrub3j2#
非常感谢@SantiagoSquarzon为我指出了我当时甚至没有意识到的正确方向。让我的脚本使用参数化查询(一旦我学会了如何),认为这将提高安全性,并惊喜地意识到(事后看来,这是一种明显的),它也否定了转义字符的问题。
对于任何感兴趣的人,我最终得到的工作代码是
.Add(
方法已被弃用,因此它可能无法在新版本中工作。已确认在Windows Server 2012(SQL 2012)和Windows Server 2012 R2(SQL 2016)上使用Powershell 5.1。*有趣的是,在我达到这一点之前,当我还在争论转义字符时,我发现
给出了一个Powershell错误,将其分为两行,如下所示
工作得很好,做了我以前的事情(在知道更好之前!)寻找。