Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   . (http://forum.oszone.net/showthread.php?t=349278)

valerarom2021 27-07-2021 15:31 2962938

.
 
Добрый день. С помощью Invoke-Sqlcmd пытаюсь сделать, чтобы скрипт выполнял запросы сразу на нескольких SQL базах. Вот пример кода. Скрипт сохраняет в переменные строки с двух текстовых файлов.
Код:

$SQLNames = Get-Content -Path C:\komp.txt
 $SQLBDs = Get-Content -Path C:\bd.txt

foreach($SQLName in $SQLNames)
  {
      foreach($SQLBD in $SQLBDs) {
  Invoke-Sqlcmd -ServerInstance $SQLName -Username $Username -Password $Password -Database $SQLBD  -Query $query  -Verbose | Out-GridView
      }
  }

Проблема заключается в том, что $SQLName сохраняет только первую строку из файла komp.txt и пытается на одном и том же компьютере подключиться к базе из переменной $SQLBD.

Elven 27-07-2021 22:45 2962979

Судя по приведенному коду на каждом из SQLName выполнятся ВСЕ запросы из bd.txt (или так и нужно было?)
Т.к. вывод идет в Out-GridView после выполнения запросов цикл должен остановиться и показать табличку с выводом. После закрытия таблички выполнится еще один кусок цикла. (насчет этого не уверен, не на чем протестировать).

valerarom2021 28-07-2021 12:12 2963012

Цитата:

Цитата Elven
Судя по приведенному коду на каждом из SQLName выполнятся ВСЕ запросы из bd.txt (или так и нужно было?) »

Да, но почему-то SQLName парсит komp.txt только первую строку из списка. Out-GridView я планирую, чтобы не останавливал цикл, но пока не получается.

DJ Mogarych 28-07-2021 13:05 2963016

Я бы для начала отладил выполнение запросов к нескольким базам на одной машине.

А чтобы хорошо и быстро работали запросы к нескольким серверам одновременно, рекомендую Invoke-Command.

Iska 28-07-2021 13:09 2963017

Цитата:

Цитата valerarom2021
Да, но почему-то SQLName парсит komp.txt только первую строку из списка. »

valerarom2021, упакуйте Ваши komp.txt и bd.txt в архив, каковой приложите к сообщению.

valerarom2021 28-07-2021 13:34 2963024

Цитата:

Цитата DJ Mogarych
Я бы для начала отладил выполнение запросов к нескольким базам на одной машине. »

Я сделал выполнение запросов на одной машине. С этим проблем нет. Для работы с SQL мне больше подходит Invoke-Sqlcmd. пробовал другие варианты, мне не понравились.

Цитата:

Цитата Iska
valerarom2021, упакуйте Ваши komp.txt и bd.txt в архив, каковой приложите к сообщению. »

В целях безопасности я не могу это сделать. Могут только дать пример строк. Имя RXX-XXXX-N, база BDXXXXX. Только это ничего не даст. Думаю проблема в том что у меня цикл в цикле.

Iska 28-07-2021 14:16 2963028

valerarom2021, нужен не пример строк, а кодировка текста, наличие/отсутствие BOM и вид конца строк.

valerarom2021 28-07-2021 14:37 2963029

Вложений: 1
Цитата:

Цитата Iska
нужен не пример строк, а кодировка текста, наличие/отсутствие BOM и вид конца строк. »

Файл 165012

valerarom2021 28-07-2021 14:39 2963030

Цитата:

Цитата valerarom2021
наличие/отсутствие BOM »

В какой кодировке лучше? сейчас UTF-8 без BOM

Первое соединение компьютер, база проходит правильно. Второй раз первая строка компьютер не меняется, только база.

DJ Mogarych 28-07-2021 14:49 2963032

Invoke-Command - это не замена Invoke-Sqlcmd, а параллельный запуск команд сразу на нескольких машинах. Ссылочку почитайте.

Iska 28-07-2021 15:03 2963035

Цитата:

Цитата valerarom2021
Новая папка.7z »

Там по одной строке ровно в обоих файлах.

valerarom2021 28-07-2021 15:19 2963036

Вложений: 1
  • 1.7z (0 bytes, скачиваний: 0)
Цитата:

Цитата Iska
Там по одной строке ровно в обоих файлах. »

Файл 165013

Iska 28-07-2021 15:45 2963040

valerarom2021, я прогнал этот код:
Скрытый текст
Код:

$SQLNames = Get-Content -Path 'C:\Мои проекты\0346\1\komp.txt'
$SQLBDs = Get-Content -Path 'C:\Мои проекты\0346\1\bd.txt'

foreach($SQLName in $SQLNames) {
    foreach($SQLBD in $SQLBDs) {
        #Invoke-Sqlcmd -ServerInstance $SQLName -Username $Username -Password $Password -Database $SQLBD  -Query $query  -Verbose | Out-GridView
        "[$SQLName]`t[$SQLBD]"
    }
    ''
}


и закономерно убедился, что с перебором там всё в порядке.

Вы выкладывали весь Ваш код?

valerarom2021 28-07-2021 16:04 2963043

Цитата:

Цитата Iska
Вы выкладывали весь Ваш код? »

Код:

$objbutton_Ok.Add_Click({
  if ($objCheckBox_comp.Checked){
       
    $SQLNames = Get-Content -Path C:\komp.txt
    $SQLBDs = Get-Content -Path C:\bd.txt
   
  foreach($SQLName in $SQLNames)
  {
      foreach($SQLBD in $SQLBDs)
      {
      Invoke-Sqlcmd -ServerInstance $SQLName -Username $Username -Password $Password -Database $SQLBD  -Query $query  -Verbose | Out-GridView
      Write-Host соединено с $SQLName, $SQLBD
      }
  } 
 }
})

Ставлю галочку на всех компьютерах и нажимаю кнопку выполнить.

соединено с R67-356786-N DB354657. Write-Host показывает что в $SQLName парсит только первую строку, после этого база меняется, а имя пк нет.

YuS_2 28-07-2021 18:01 2963052

Цитата:

Цитата valerarom2021
Write-Host показывает что в $SQLName парсит только первую строку, после этого база меняется, а имя пк нет. »

У Вас есть понимание того, как работает цикл foreach и что такое массивы?
Начните с составления словесного алгоритма того, что необходимо получить...

valerarom2021 30-07-2021 12:39 2963152

Цитата:

Цитата YuS_2
У Вас есть понимание того, как работает цикл foreach и что такое массивы? »

Да есть. Я первый раз встречаюсь с тем, что приходится делать два цикла. Вы сможете подсказать, пожалуйста ?
Цитата:

Цитата YuS_2
Начните с составления словесного алгоритма того, что необходимо получить... »

Выше я описал, что должно получиться.

YuS_2 30-07-2021 14:09 2963165

Цитата:

Цитата valerarom2021
Выше я описал, что должно получиться. »

Выше, Вам Iska показал:
Цитата:

Цитата Iska
и закономерно убедился, что с перебором там всё в порядке. »

что с циклами там всё в порядке... чем ещё можно помочь с той информацией, которую Вы показали?
Если есть необходимость получить помощь, не надо секретничать и выдавать информацию по чайной ложке в неделю. Конфиденциальную информацию можете заменить чем-нибудь или затереть...
Сделайте скриншоты результата работы Вашего скрипта, со всеми ошибками, в том числе. И сам скрипт покажите целиком, чтобы было понятно, что у вас там происходит.
Иначе никак.

YuS_2 31-07-2021 20:06 2963266

Цитата:

Цитата valerarom2021
Выложил весь код. »

Ну, собственно, изменим немного Ваш код, т.к. нет у меня реальных баз SQL, вот в этой части:
корректировка кода
Код:

...
$cnt = 0
$objbutton_Ok.Add_Click({
        if ($objCheckBox_opsone.Checked){SQLOLEDB}
        if ($objCheckBox_ops.Checked){
                $SQLNames = Get-Content -Path '.\komp.txt'
                $SQLBDs = Get-Content -Path '.\bd.txt'
                $query = $objText_query.Text
                $Username = " "
                $Password = " "
                foreach($SQLName in $SQLNames){
                        foreach($SQLBD in $SQLBDs){
                                # Имитация таблицы
                                $tmp = [pscustomobject]@{
                                        Комп = $SQLName
                                        База = $SQLBD
                                        ID = $cnt++
                                }
                                $tmp|ogv
                                # Т.к. реального парка компов нет, как и SQL баз, закомментируем:
                                #Invoke-Sqlcmd -ServerInstance $SQLName -Username $Username -Password $Password -Database $SQLBD -Query $query -Verbose | Out-GridView
                                Write-Host соединено с $SQLName, $SQLBD
                        }
                        write-host '----------'
                }       
        }
})
...



и запустим этот код:
скриншот

То бишь, на каждую итерацию родительского цикла, приходится по одному полному проходу вложенного цикла, что собственно, в коде и записано.

Вывод:
Если у Вас работает не так, значит проблема со строкой запуска командлета Invoke-Sqlcmd, проверяйте её.

DJ Mogarych 31-07-2021 21:48 2963270

Зачем этот графический интерфейс, занимающий миллион строк кода, когда можно было просто пару параметров сделать?

Iska 31-07-2021 22:13 2963272

DJ Mogarych, ну, например, не умеет/не любит человек в командную строку.

valerarom2021 01-08-2021 08:57 2963294

Цитата:

Цитата DJ Mogarych
Зачем этот графический интерфейс, занимающий миллион строк кода, когда можно было просто пару параметров сделать? »

Скриптом не только я буду пользоваться.

DJ Mogarych 01-08-2021 09:12 2963297

Можно организовать общение с пользователем через командную строку, задавая вопросы или предоставляя выбор из пунктов. Это сильно сэкономит объём кода и силы для его написания.

valerarom2021 02-08-2021 09:18 2963413

Цитата:

Цитата YuS_2
Если у Вас работает не так, значит проблема со строкой запуска командлета Invoke-Sqlcmd, проверяйте её. »

Вы ведете на скрине во второй строке цифры в имени компьютера и базы должны совпадать. У вас меняется только название базы. В этом проблема.

DJ Mogarych 02-08-2021 09:40 2963415

Сколько там баз?
Уберите вложенный foreach с базами и сделайте несколько строк Invoke-Sqlcmd, прописав там имена баз в явном виде.

Будет так работать?

YuS_2 02-08-2021 10:27 2963421

Цитата:

Цитата valerarom2021
Вы ведете на скрине во второй строке цифры в имени компьютера и базы должны совпадать. У вас меняется только название базы. В этом проблема. »

Следовательно, представления о том, как работают циклы, у Вас нет.
Именно, для такого случая, рекомендовал:
Цитата:

Цитата YuS_2
Начните с составления словесного алгоритма того, что необходимо получить... »

Ибо то, что находится в шапке топика, это не словесный алгоритм, а код (полного понимания которого у Вас нет, видимо кто-то вам его написал) с краткими комментариями, которые ничего не объясняют.
Напишите, что в итоге требуется получить. Составьте вручную результирующие строки, которые покажут, как именно должен осуществляться доступ к базам.

valerarom2021 02-08-2021 10:36 2963424

Цитата:

Цитата DJ Mogarych
Сколько там баз? »

50 баз
Цитата:

Цитата DJ Mogarych
Будет так работать? »

Так работает.

Цитата:

Цитата YuS_2
Ибо то, что находится в шапке топика, это не словесный алгоритм, а код (полного понимания которого у Вас нет, видимо кто-то вам его написал) с краткими комментариями, которые ничего не объясняют.
Напишите, что в итоге требуется получить. Составьте вручную результирующие строки, которые покажут, как именно должен осуществляться доступ к базам. »

Этот код я сам написал.

Цитата:

Цитата YuS_2
Следовательно, представления о том, как работают циклы, у Вас нет. »

Я написал много скриптов используя foreach. Все они работают. Здесь проблема в том, что оба цикла вместе не корректно работают.

DJ Mogarych 02-08-2021 11:39 2963430

Сами по себе вложенные циклы работают нормально.

Код:

$servers = 1..5 |% {"server$($_.ToString("00"))"}
$dbs = 1..3 |% {"db$($_.ToString("00"))"}

foreach ($server in $servers) {
    foreach ($db in $dbs) {
    "Invoke-Sqlcmd -server $server -database $db"
    }
}
Invoke-Sqlcmd -server server01 -database db01
Invoke-Sqlcmd -server server01 -database db02
Invoke-Sqlcmd -server server01 -database db03
Invoke-Sqlcmd -server server02 -database db01
Invoke-Sqlcmd -server server02 -database db02
Invoke-Sqlcmd -server server02 -database db03
Invoke-Sqlcmd -server server03 -database db01
Invoke-Sqlcmd -server server03 -database db02
Invoke-Sqlcmd -server server03 -database db03
Invoke-Sqlcmd -server server04 -database db01
Invoke-Sqlcmd -server server04 -database db02
Invoke-Sqlcmd -server server04 -database db03
Invoke-Sqlcmd -server server05 -database db01
Invoke-Sqlcmd -server server05 -database db02
Invoke-Sqlcmd -server server05 -database db03

Выведите команды с помощью echo на экран, чтобы проверить, правильно ли подставляются переменные.

Возможно, следовало бы базы перечислять в самом запросе и делать один запрос на хост, чем заниматься ковровой бомбардировкой хоста 50-ю запросами.

valerarom2021 02-08-2021 11:55 2963431

Цитата:

Цитата DJ Mogarych
Выведите команды с помощью echo на экран, чтобы проверить, правильно ли подставляются переменные. »

$SQLName парсит только первую строку из файла komp.txt, foreach($SQLName in $SQLNames) не отрабатывает.

YuS_2 02-08-2021 11:56 2963432

Цитата:

Цитата valerarom2021
Здесь проблема в том, что оба цикла вместе не корректно работают. »

О том и речь, что циклы работают именно так, как они и должны работать, т.е. как раз, корректно. Другое дело, что Вы их используете не так, как необходимо для достижения результата, который Вам требуется. А вот то, что именно требуется, непонятно тем, у кого Вы попросили помощь... либо объясните, либо подождите, возможно, у кого-то обострятся экстрасенсорные способности. :)
Вам же не отказывают в помощи, но любая задача решается быстрее, если правильно составить её условия...

Цитата:

Цитата valerarom2021
$SQLName парсит только первую строку из файла komp.txt »

Переменная ничего не парсит. В переменной содержится массив того, что считывает из файла командлет get-content, так записано в Вашем коде.
А вот в цикле происходит разбор того, что записано в массиве. Ещё раз: циклы отрабатывают ровно так, как и должны. Просто Вы недопонимаете, что содержат переменные в каждой итерации каждого цикла.

valerarom2021 02-08-2021 12:14 2963434

Цитата:

Цитата YuS_2
Переменная ничего не парсит. В переменной содержится массив того, что считывает из файла командлет get-content, так записано в Вашем коде.
А вот в цикле происходит разбор того, что записано в массиве. Ещё раз: циклы отрабатывают ровно так, как и должны. Просто Вы недопонимаете, что содержат переменные в каждой итерации каждого цикла. »

$SQLNames = Get-Content -Path C:\komp.txt
Get-Content сохраняет строки в массив $SQLNames. Дальше с коллекцией работает foreach. В данном случает в массиве только первая строка из файла komp.txt, а их там 50.
Получается имя компьютера не меняется, только обновляется переменная $SQLBDs. В итоге скрипт на одном компьютере пытается соединиться с базами со списка bd.txt Надеюсь сейчас понятно. Объяснил.

Как мне сделать чтобы массивы $SQLNames, $SQLBDs совпадали так ? например: R76-356785-N DB352785, следующее R76-356787-N DB352787
Либо используя один текстовый файл считывать сразу R76-356785-N DB352785

YuS_2 02-08-2021 12:48 2963437

Цитата:

Цитата valerarom2021
Получается имя компьютера не меняется, только обновляется переменная $SQLBDs. »

Не так. У родительского цикла свои итерации, у вложенного свои. На каждую итерацию родительского цикла приходится полный цикл итераций вложенного цикла. Таким образом, имя компьютера меняется, но на каждое имя компьютера будет приходиться весь массив наименований баз. Видимо, Вы хотели не этого...

Цитата:

Цитата valerarom2021
Как мне сделать чтобы массивы $SQLNames, $SQLBDs совпадали так ? »

Для этого, необходимо выполнение двух условий:
1. На каждый компьютер должна приходиться одна база
2. Порядок следования компьютеров должен полностью совпадать с порядком следования соответствующих компьютерам баз.
т.е. в файлах должно быть записано так:
Цитата:

Файл Компьютеры:

Comp1
Comp2
Comp3

Файл Базы:

Baza1
Baza2
Baza3
- если всё именно так, то разбор массивов будет возможен одним циклом:
Код:

for ($i=0;$i -lt $SQLNames.length;$i++){
 #Здесь Ваша строка запроса с соответствующими параметрами
 #переменные используются так: $SQLNames[$i] и $SQLBDs[$i]
 write-host $($SQLNames[$i] + ' - ' + $SQLBDs[$i])
}

Ну, или для надежности, создайте CSV файл:
Цитата:

Comp,Baza
Comp1,Baza1
Comp2,Baza2
Comp3,Baza3
и потом, всё в том же цикле for:
Код:

$array = Import-Csv list.csv
for ($i=0;$i -lt $array.length;$i++){
 #Здесь Ваша строка запроса с соответствующими параметрами
 #переменные используются так: $array.comp[$i] и $array.baza[$i]
 write-host $($array.comp[$i] + ' - ' + $array.baza[$i])
}

- как-то так.

Iska 02-08-2021 13:04 2963440

Цитата:

Цитата valerarom2021
Как мне сделать чтобы массивы $SQLNames, $SQLBDs совпадали так ? например: R76-356785-N DB352785, следующее R76-356787-N DB352787 »

:shot: :shot: :shot:.


YuS_2, снимаю шляпу за настойчивость!

valerarom2021 02-08-2021 13:06 2963441

Цитата:

Цитата YuS_2
YuS_2 »

Спасибо огромное. Именно это я и пытался сделать. Просто не сталкивался с подобным. Буду изучать дальше.

DJ Mogarych 02-08-2021 13:41 2963444

Цитата:

Цитата valerarom2021
Как мне сделать чтобы массивы $SQLNames, $SQLBDs совпадали так ? например: R76-356785-N DB352785, следующее R76-356787-N DB352787 »

Ну ёлы-палы... Уметь правильно объяснить - полдела.

valerarom2021 10-08-2021 13:39 2963961

Добрый день. Пытаюсь улучшить скрипт. Добавить в скрипт runspace.

Код:

function runspace {
 
  $SQLNames = Get-Content -Path "$env:userprofile\Desktop\SQL\komps.txt"
  $SQLBDs = Get-Content -Path "$env:userprofile\Desktop\SQL\bd.txt"
  $query = $objText_query.Text
  $Username = ""
  $Password = ""
 
  $runspace = [runspacefactory]::CreateRunspace()
  $runspace.Open()
  $powershell = [powershell]::Create()
  $powershell.Runspace = $runspace
  $powershell.AddScript({
                                               
    for ($i = 0; $i -lt $SQLNames.length; $i++){
      Invoke-Sqlcmd -ServerInstance $SQLNames[$i] -Database $SQLBDs[$i] -Query $query -Username $Username -Password $Password  -QueryTimeout 0 -Verbose
      Write-Host $($SQLNames[$i] + ' - ' + $SQLBDs[$i])
    }                       
  })
    $powershell.BeginInvoke()
}

$objbutton_Ok.Add_Click({

  if ($objCheckBox_ops.Checked){runspace}
})

Функция runspace при нажатии кнопки не запускается. Без runspace всё работает.

YuS_2 10-08-2021 17:31 2963982

Цитата:

Цитата valerarom2021
Пытаюсь улучшить скрипт. »

Улучшить что именно? для чего Вам там ранспейсы?

Цитата:

Цитата valerarom2021
Функция runspace при нажатии кнопки не запускается. »

там не функция не запускается... переменные-параметры внутрь ранспейсов необходимо передавать особым методом, там о них ничего не известно...
Почитайте несколько частей на предмет изучения ранспейсов

valerarom2021 10-08-2021 17:44 2963984

Цитата:

Цитата YuS_2
Улучшить что именно? для чего Вам там ранспейсы? »

Для того, чтобы параллельно запускать скрипты sql.

valerarom2021 17-08-2021 14:19 2964407

Цитата:

Цитата YuS_2
там не функция не запускается... переменные-параметры внутрь ранспейсов необходимо передавать особым методом, там о них ничего не известно...
Почитайте несколько частей на предмет изучения ранспейсов »

Спасибо. Прочитал статью. Сделал примерно также.
Код:

function SQLALLDB {
 
    $SQLNames = Get-Content -Path ""
    $SQLBDs = Get-Content -Path ""
    $query = $objText_query.Text
    $Username = ""
    $Password = ""
 
 
 
  $Code = {
     
$Parameters = @{

    Param1 = '$SQLNames'
    Param2 = '$SQLBDs'
    Param3 = '$query'
    Param4 = '$Username'
    Param5 = '$Password'
  }

    for ($i = 0; $i -lt $SQLNames.length; $i++){
      Invoke-Sqlcmd -ServerInstance $SQLNames[$i] -Database $SQLBDs[$i] -Query $query -Username $Username -Password $Password -MaxCharLength 100000  -
      QueryTimeout 0 -Verbose
      Write-Host $($SQLNames[$i] + ' - ' + $SQLBDs[$i])
        }       
  }
 
  [runspacefactory]::CreateRunspacePool()
  $SessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
  $RunspacePool = [runspacefactory]::CreateRunspacePool(1,100)
 
  $PowerShell = [powershell]::Create()
  $PowerShell.RunspacePool = $RunspacePool
  $RunspacePool.Open()
  [void]$PowerShell.AddScript($Code).AddArgument($Parameters)
  $PowerShell.BeginInvoke()
}

Всё равно не передаются переменные. Я добавил переменные в $Parameters и изменил строку void]$PowerShell.AddScript($Code).AddParameters($Parameters)

valerarom2021 17-08-2021 14:35 2964410

Код:

$Code = {
    param($SQLNames,$SQLBDs,$query,$Username,$Password)
    for ($i = 0; $i -lt $SQLNames.length; $i++){
      Invoke-Sqlcmd -ServerInstance $SQLNames[$i] -Database $SQLBDs[$i] -Query $query -Username $Username -Password $Password -MaxCharLength 100000  -
      QueryTimeout 0 -Verbose
      Write-Host $($SQLNames[$i] + ' - ' + $SQLBDs[$i])
        }       
  }
  [runspacefactory]::CreateRunspacePool()
  $SessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
  $RunspacePool = [runspacefactory]::CreateRunspacePool(1,100)
 
  $PowerShell = [powershell]::Create()
  $PowerShell.RunspacePool = $RunspacePool
  $RunspacePool.Open()
  [void]$PowerShell.AddScript($Code).AddArgument($SQLNames).AddArgument($SQLBDs).AddArgument($query).AddArgument($Username).AddArgument($Password)
  $PowerShell.BeginInvoke()

Такой вариант тоже не работает для меня.

YuS_2 21-08-2021 12:58 2964728

Цитата:

Цитата valerarom2021
Всё равно не передаются переменные. »

Цитата:

Цитата valerarom2021
Такой вариант тоже не работает для меня. »

Это говорит о том, что читать надо ещё... смысл того, как именно, параметры передаются, видимо, Вы не уловили...
Начните от простого к сложному... создайте небольшой пул ранспейсов с одним или двумя параметрами без циклов внутри, запустите их, протестируйте и потом уже усложняйте.
Здесь, у Вас я вижу, что пытаетесь запустить, в каждом пространстве из пула, полный цикл размерностью длины базы. А параметры пытаетесь передать изнутри скриптблока... естественно, так ничего не будет работать.
Например, попробуйте выполнить в консоли это:
Код:

if ($Parameters){rv -n Parameters}
$Code = {
        $Parameters = @{
                Param1 = '1'
                Param2 = '2'
                Param3 = '3'
        }
}
$Parameters

затем вот это:
Код:

if ($Parameters){rv -n Parameters}
$Parameters = @{
        Param1 = '1'
        Param2 = '2'
        Param3 = '3'
}
$Parameters

- там будет наглядно видна разница


Время: 23:43.

Время: 23:43.
© OSzone.net 2001-