Как заменить апостроф, вызывающий ошибку синтаксиса SQL

Ожидаемое поведение:

  1. Имейте сценарий PS, который просматривает каталог файлов и собирает все детали каталога (работает)
  2. Запишите эти данные обратно в таблицу 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-инъекций.

Другие вопросы по тегам