Search code examples
sql-serverpowershellsqlcmdinvoke-sqlcmd

run query against multiple databases on different server


I'm working on a PowerShell script to run a query against multiple servers and databases were the idea is to dynamically add server and databases to an array and execute them.

Currently I'm stuck at the last part where everything is combined. I can add the servers but not the databases.

What I am trying to achieve: PowerShell script with MFP GUI to run a query against multiple MSSQL servers which all contain identical database (with different data) but the databases have different names like Sql_Data-Node1, SqlData-Node2, etc.

Problem I encounter: I managed to add the servers dynamically to an array and when I run a query I get the proper response. In this case I used the master database an I made it static (-database 'master'). When I try to do the same with the databases (add them to an array) I get an error:

Invoke-Sqlcmd : Cannot validate argument on parameter 'Database'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At C:\Users\master\Documents\MULTSCRIPT\MultiQueryV0.6.ps1:368 char:109
+ ... ame -Password $PassWord -ServerInstance $_[0] -Database $_[1] -Query  ...
+                                                             ~~~~~
+ CategoryInfo          : InvalidData: (:) [Invoke-Sqlcmd], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.SqlServer.Management.PowerShell.GetScriptCommand

My code:

#Create EMPTY ARRAY for Databases
$script:DBSet = New-Object System.Collections.ArrayList 

    #==========================================================================

    $window.Master.add_Checked({
        $script:Master = 'master' #Add IP to Variable
        $script:DBSet.Add("$script:Master") #Add Variable to Array
        [System.Object]$sender = $args[0]
        [System.Windows.RoutedEventArgs]$e = $args[1]
    })

    $window.Master.add_Unchecked({
        $script:Master = $null
        $script:DBSet.Remove("$script:Master")
        [System.Object]$sender = $args[0]
        [System.Windows.RoutedEventArgs]$e = $args[1]
    })

    #==========================================================================

    $window.DataNodes.add_Checked({
        $script:DB01 = 'Database01'                                                  
        $script:DBSet.Add("$script:DB01")
        [System.Object]$sender = $args[0]
        [System.Windows.RoutedEventArgs]$e = $args[1]
    })

    $window.DataNodes.add_Unchecked({
        $script:DB01 = $null
        $script:DBSet.Remove("$script:DB01")
        [System.Object]$sender = $args[0]
        [System.Windows.RoutedEventArgs]$e = $args[1]
    })

    #Create EMPTY ARRAY For Servers
    $script:ServerAddress = New-Object System.Collections.ArrayList

    #Add action to Checkbox====================================================

    $window.DB00.add_Checked({
        $script:SRV00 = '190.168.1.8' #Add IP to Variable
        $script:ServerAddress.Add("$script:SRV00") #Add Variable to Array
        [System.Object]$sender = $args[0]
        [System.Windows.RoutedEventArgs]$e = $args[1]
    })

    $window.DB00.add_Unchecked({
        $script:SRV00 = $null
        $script:ServerAddress.Remove("$script:SRV00") #Remove Variable to Array 
        [System.Object]$sender = $args[0]
        [System.Windows.RoutedEventArgs]$e = $args[1]
    })

    #==========================================================================

    $window.DB01.add_Checked({
        $script:SRV01 = '192.168.1.9'
        $script:ServerAddress.Add("$script:SRV01")
        [System.Object]$sender = $args[0]
        [System.Windows.RoutedEventArgs]$e = $args[1]
    })

    $window.DB01.add_Unchecked({
        $script:SRV01 = $null
        $script:ServerAddress.Remove("$script:SRV01")
        [System.Object]$sender = $args[0]
        [System.Windows.RoutedEventArgs]$e = $args[1]
    })

    #Collect Credentials#======================================================

    $credential = Get-Credential 
    $UserName = $credential.UserName.Replace('\','')
    $PassWord = $credential.GetNetworkCredential().password


    #Collect From Input Fields#================================================

    $window.Button.add_Click({
        $SQLQuery = $window.Query.Text.ToString()
        $Server = $script:ServerAddress
        $DatabaseSet = $script:DBSet
        $instances = @( @($Server, $DatabaseSet) )
        $instances | ForEach{
            Invoke-Sqlcmd -AbortOnError `
                -Username $UserName`
                -Password $PassWord`
                -ServerInstance $_[0]`
                -Database $_[1]`
                -Query $SQLQuery`
                -QueryTimeout 30 |
                Out-GridView -Title $_[0]
        }
        [System.Object]$sender = $args[0]
        [System.Windows.RoutedEventArgs]$e = $args[1]
    })

Solution

  • It seems that the following solution works. Credit goes to:Mutiple Variables in Foreach Loop [Powershell]

    $window.Button.add_Click(
    {   $DataBase = $window.DataBase.Text.ToString()
        $SQLQuery = $window.Query.Text.ToString()
        $Server = $ServerAddress.getenumerator()
        $Database = $DBSet.getenumerator()
        while($Server.MoveNext() -and $Database.MoveNext()){
        Invoke-Sqlcmd -AbortOnError -Username $UserName -Password $PassWord -ServerInstance $Server.Current -Database $Database.Current -Query $SQLQuery -QueryTimeout 30 | Out-GridView -Title $Server.Current}