Как заменить апостроф, вызывающий ошибку синтаксиса SQL
Ожидаемое поведение:
- Имейте сценарий PS, который просматривает каталог файлов и собирает все детали каталога (работает)
- Запишите эти данные обратно в таблицу SQL (работает)
Скрипт работает, но не работает с такой ошибкой:
ForEach-Object: исключение, вызывающее "ExecuteNonQuery" с аргументом (ами) "0": "Неверный синтаксис рядом с 'EGIDIO'"
который, как я знаю, вызван апострофом. Папка, которую он читает при сбое, называется "D'EGIDIO, SHAH &TOWNSEND".
Проблема в том, что я не могу понять, как заменить этот текст в сценарии PS или вставку sql из сценария. Независимо от того, что я пробую, это все равно терпит неудачу.
#Invoke-sqlcmd Connection string parameters
$params = @{'server'='TESTServer';'Database'='_Maintenance'}
#Server to query WMI class win32_logicalDisks
$server = 'TESTServer'
#Prepare Insert Statement
$insert = @'
INSERT INTO [_PBS_Maintenance].[dbo].[Maint_DiskSpace](Path,SizeInMB,SizeInGB,FileLastModified,CreatedDate,CreatedBY)
VALUES (
'{0}',
'{1}',
'{2}',
'{3}',
GetDate(),
SYSTEM_USER
)
'@
write-host $insert
Try {
#Define connction string of target database
$connectionString = 'Data Source=PBSNV800IMG1\PBSNV800IMG1;Initial Catalog=_PBS_Maintenance;Integrated Security=SSPI'
# connection object initialization
$conn = New-Object System.Data.SqlClient.SqlConnection($connectionString)
#Open the Connection
$conn.Open()
# Prepare the SQL
$cmd = $conn.CreateCommand()
$array= @()
$folder = "\\fsvr\Public\Users\Valorie L\Valorie\ATTORNEY\EIC-ERMG\"
$Source = $folder
Get-ChildItem -Recurse $Source | Where-Object { $_.PSIsContainer } |
ForEach-Object {
$obj = New-Object PSObject
$SizeMB = [Math]::Round((Get-ChildItem -Recurse $_.FullName | Measure-Object Length -Sum -ErrorAction SilentlyContinue).Sum / 1MB, 2)
$SizeGB = [Math]::Round((Get-ChildItem -Recurse $_.FullName | Measure-Object Length -Sum -ErrorAction SilentlyContinue).Sum / 1GB, 2)
$obj |Add-Member -MemberType NoteProperty -Name "Path" $_.FullName
$obj |Add-Member -MemberType NoteProperty -Name "SizeMB" $SizeMB
$obj |Add-Member -MemberType NoteProperty -Name "SizeGB" $SizeGB
$obj |Add-Member -MemberType NoteProperty -Name "DateModified" $_.LastWritetime
$array +=$obj
select Path,SizeMB,DateModified
ForEach-Object{
$cmd.CommandText = $insert -f $obj.Path,$obj.SizeMB,$obj.SizeGB, $obj.DateModified
$cmd.ExecuteNonQuery()
}
}
#Close the connection
$conn.Close()
}
Catch {
Throw $_
}
Invoke-Sqlcmd @params -Query "SELECT * FROM Maint_DiskSpace" | format-table -AutoSize
1 ответ
Одинарные кавычки в SQL экранируются путем их удвоения (две одинарные кавычки '
'
, а не двойные кавычки "
). Что вы хотите сделать в случае пути в этой строке:
$obj |Add-Member -MemberType NoteProperty -Name "Path" $_.FullName
Немного измените его, заменив любые одинарные кавычки двумя одинарными кавычками, например:
$obj |Add-Member -MemberType NoteProperty -Name "Path" ( $_.FullName -replace "'", "''" )
Как это работает, мы подвыражаем $_.FullName
так что мы можем использовать -replace
для замены одинарных кавычек в пути двумя одинарными кавычками. Сначала оценивается подвыражение, а затем возвращаемое значение применяется к родительской области как значение дляPath
собственность на $obj
.
Обратите внимание, что было бы разумно убедиться, что вы экранируете все символы, разрешенные в пути к папке, которые должны быть экранированы как часть SQL-запроса, а также символы, которые должны быть экранированы, чтобы предотвратить атаки SQL-инъекций.