Powershell: мне нужна помощь для изменения длинного файла сценария SQL - PullRequest
0 голосов
/ 29 октября 2019

У меня есть длинный скрипт SQL, который содержит МНОЖЕСТВО / несколько разделов, подобных этому (среди других разделов скрипта):

USE [NAVDB]
GO

IF NOT EXISTS (SELECT name FROM sys.database_principals 
               WHERE name = '@@Placeholder@@')  
    CREATE USER [MyDomain\adcsuser] 
    FOR LOGIN [MyDomain\adcsuser] 
    WITH DEFAULT_SCHEMA = [MyDomain\adcsuser]
GO

GRANT CONNECT TO [MyDomain\adcsuser] AS [dbo]
GO

Мне нужно проанализировать этот фрагмент скрипта и изменить только строки IF NOT EXISTS...CREATE USER...такой сценарий, что "@@ Placeholder @@" заменяется текстом в квадратных скобках [] в той же строке, следующей сразу за строкой CREATE USER.

Таким образом, строка в приведенном выше фрагменте будет иметь вид:

IF NOT EXISTS (SELECT name FROM sys.database_principals 
               WHERE name = 'MyDomain\adcsuser')  
    CREATE USER [MyDomain\adcsuser] 
    FOR LOGIN [MyDomain\adcsuser] 
    WITH DEFAULT_SCHEMA = [MyDomain\adcsuser]

Файл состоит из многих сотен строк и содержит множество дюжин (как минимум) этих разделов.

NotePad ++ find-replace и макросы не могут его обработать из-за«\» в именах между [] и я не мог найти, как заставить NP ++ копировать текст между [] с.

Также я попытался просмотреть другие связанные ответы, такие как: Как можноЯ заменяю каждое вхождение String в файле на PowerShell? , но до сих пор остаюсь в тупике.

Из-за сложной природы структуры файла сценария, которую я опасаюсь, «прочитайте весь файл ипросто используйте ReПодходы gex находят / заменяют », поэтому я искал более ... подход RBAR (Row By Agonizing Row).

Динамический SQL или параметризованные подходы и аналогичные предложения НЕ СООТВЕТСТВУЮТ этой ситуации, так как СЦЕНАРИЙ БЫЛУЖЕ ДИНАМИЧЕСКИ ПРОИЗВЕДЕНО из существующей производственной системы (и у меня нет исходного кода для утилиты, которая сгенерировала это как вывод). Я буквально не могу сделать такие структурные изменения оптом.

Кроме того, после прочтения этого поста, я должен отметить, что вся команда «ЕСЛИ НЕ СУЩЕСТВУЕТ ... С DEFAULT_SCHEMA [*]» включенаОДНА ЛИНИЯ в файле скрипта (если это было недостаточно ясно).

Ответы [ 2 ]

0 голосов
/ 30 октября 2019

@ Tim Mylott,

Вся проблема возникла из-за скрипта, сгенерированного из моей производственной системы из команды Powershell DBATools 'Export-DbaLogin.

Выходной скрипт из этого инструмента был похож наВаш первый файл text.txt, в котором он запускает слепые команды CREATE USER без предварительного тестирования, чтобы проверить, существует ли пользователь.

Это было недостаточно для наших нужд (наша производственная БД и система работали на лет и теперь повсюду в нем есть старый, плохой «мусор», поэтому я взял вывод сценария в Notepad ++ и добавил логику проверки IF NOT EXIST ... (подробности см. в сценарии в исходном вопросе)) в качестве префикса к командам CREATE USER в сценарии с глобальным поиском и заменой. Только мне пришлось ввести @@ Placeholder @@ для имени пользователя в предложении SELECT WHERE для теста.

В результате у меня остался сценарий, в котором мне пришлось заменить текст @@ Placeholder @@ нафактические строки имени пользователя в существующем тексте CREATE USER в той же строке в файле скрипта.

В NP ++, к которому вы меня привели, было решение использовать Regex в поиске NP ++, чтобы выбрать строку идентификатора пользователя вта же строка. Оттуда было довольно легко и просто использовать запись макросов NP ++ для автоматизации поиска и замены.

Во-первых, я нашел в сети регулярное выражение для выбора текста между первой подходящей парой [] s, а именно: (? <= [). +? (? =]) Запись сценария NP ++ была в основномthis (начать запись макроса): </p>

Find: @@ PlaceHolder @@ (поиск без регулярных выражений) [NP ++ находит следующую строку для изменения] [Home] (чтобы найти начало строки) Find: (? <= [). +? (? =]) (поиск по регулярному выражению) [NP ++ выбирает строку UserID в части строки CREATE USER) [Ctrl + C] (копировать строку UserID в буфер обмена после закрытия диалога поиска) [Home] (чтобы снова найти начало строки) Find: @@ PlaceHolder @@ (поиск без регулярных выражений) [NP ++ находит текст @@ Placeholder @@ в текущей строке и выделяет его] [Ctrl + V] (вставитьв строке «Идентификатор пользователя из буфера обмена» (при этом курсор остается в том же месте, где исправленная команда может быть визуально подтверждена как правильная) </p>

В NP ++ Используйте кнопку «Воспроизвести макрос», чтобы вручную воспроизвести этот записанный макрос несколько разчтобы убедиться, что макрос имеет право ... Затем, используйте воспроизведение несколько раз (пока не достигнут конец файла) и вуаля! Файл скрипта полностью исправлен.

[Примечание: у DBATools GitHub теперь есть 2 сообщения об ошибках / запросы на добавление этой логики IF NOT EXISTS в строки CREATE USER в сгенерированном скрипте, поэтому эта проблема в конечном итоге исчезнетпрочь, но пока ... есть хотя бы одно разумное решение с использованием NotePad ++.]

Итак, спасибо, Тим, за то, что вы дали мне быстрый ответ.

Это сказало, хотя, ваша часть ответа Powershell была неправильной, так что никаких баллов нет! (он делал неправильно и вставлял в сценарий "@@ Placeholder @@", а не заменял существующую строку "@@ PlaceHolder @@" в сценарии фактическими строками UserID, уже находящимися в сценарии.

Повторюсь, проблема была (логически) в следующем:

-- FROM THIS:
IF NOT EXISTS (SELECT ... WHERE name = '@@PlaceHolder@@')  CREATE USER [MyDomain\AUser2]...
IF NOT EXISTS (SELECT ... WHERE name = '@@PlaceHolder@@')  CREATE USER [MyDomain\AUser3]...
IF NOT EXISTS (SELECT ... WHERE name = '@@PlaceHolder@@')  CREATE USER [MyDomain\AUser5]...
IF NOT EXISTS (SELECT ... WHERE name = '@@PlaceHolder@@')  CREATE USER [MyDomain\AUser1]...
IF NOT EXISTS (SELECT ... WHERE name = '@@PlaceHolder@@')  CREATE USER [MyDomain\AUser7]...
IF NOT EXISTS (SELECT ... WHERE name = '@@PlaceHolder@@')  CREATE USER [MyDomain\AUser8]...
IF NOT EXISTS (SELECT ... WHERE name = '@@PlaceHolder@@')  CREATE USER [MyDomain\AUserA]...
IF NOT EXISTS (SELECT ... WHERE name = '@@PlaceHolder@@')  CREATE USER [MyDomain\AUserB]...
IF NOT EXISTS (SELECT ... WHERE name = '@@PlaceHolder@@')  CREATE USER [MyDomain\AUserC]...


-- TO THIS:
IF NOT EXISTS (SELECT ... WHERE name = 'MyDomain\AUser2')  CREATE USER [MyDomain\AUser2]...
IF NOT EXISTS (SELECT ... WHERE name = 'MyDomain\AUser3')  CREATE USER [MyDomain\AUser3]...
IF NOT EXISTS (SELECT ... WHERE name = 'MyDomain\AUser5')  CREATE USER [MyDomain\AUser5]...
IF NOT EXISTS (SELECT ... WHERE name = 'MyDomain\AUser1')  CREATE USER [MyDomain\AUser1]...
IF NOT EXISTS (SELECT ... WHERE name = 'MyDomain\AUser7')  CREATE USER [MyDomain\AUser7]...
IF NOT EXISTS (SELECT ... WHERE name = 'MyDomain\AUser8')  CREATE USER [MyDomain\AUser8]...
IF NOT EXISTS (SELECT ... WHERE name = 'MyDomain\AUserA')  CREATE USER [MyDomain\AUserA]...
IF NOT EXISTS (SELECT ... WHERE name = 'MyDomain\AUserB')  CREATE USER [MyDomain\AUserB]...
IF NOT EXISTS (SELECT ... WHERE name = 'MyDomain\AUserC')  CREATE USER [MyDomain\AUserC]…

Пересмотренный сценарий из отличного начала Тима (версия 2): -)

    #create new output file
new-item "C:\temp\test2.sql" -Force
foreach ($line in (get-content "C:\temp\test.sql"))
{
    if ($line.Contains("@@Placeholder@@"))
    {
    #Find the the user between the brackets and remove the brackets.
    $user = ([regex]"\[.+?\]").Match($line).value.replace("[","").replace("]","")
    #Replace PlaceHolder with user pulled from the brackets and write to new file
    $line -replace '@@Placeholder@@', $user | out-file "C:\temp\test2.sql" -Append 
    }
    else
    {
        out-file  "C:\temp\test2.sql" -Append -InputObject $line
    }

}

... Пришлосьнастроить Regex (чтобы он был менее разрешительным) и вывести все остальные строки скрипта тоже.

0 голосов
/ 30 октября 2019

Для NotePad ++ регулярное выражение поддержки поиска и замены.

Пример того, как найти и заменить все строки, содержащие "CREATE USER [someusername]", на замену @@ Placeholder @@ будет:

enter image description here

. * - это подстановочный знак, скобки - это специальные символы в регулярном выражении, поэтому для включения их в поиск необходимо их избежать. Так что \ [. * \] Найдет что-нибудь, заключенное в скобки. Я просто добавил CREATE USER в качестве примера при поиске всех этих конкретных строк.

Убедитесь, что в режиме поиска выбрано «Регулярное выражение».

PowerShell, со всем на одной строке, вы можете прочитатьв каждой строке найдите соответствие, извлеките пользователя и затем замените;копирование этой строки обратно в новый файл.

Входной тестовый файл: enter image description here

Пример сценария PowerShell:

#create new output file
new-item "C:\temp\test2.txt" -Force
foreach ($line in (get-content "C:\temp\test.txt"))
{
    #Find the the user between the brackets and remove the brackets.
    $user = ([regex]"\[.*\]").Match($line).value.replace("[","").replace("]","")
    #Replace PlaceHolder with user pulled from the brackets and write to new file
    $line -replace '@@PlaceHolder@@', $user | out-file "C:\temp\test2.txt" -Append  
}

Затемсодержимое выходного файла:

enter image description here

...