none
How do I add multiple array rows to a DataGridView -- Powershell RRS feed

  • Question

  • I have a button that calls a function:

    $ButtonUpdateGrid3 = New-Object Windows.Forms.Button
    $ButtonUpdateGrid3.Location = New-Object Drawing.Point 224,15
    $ButtonUpdateGrid3.size = New-Object Drawing.Point 90,23
    $ButtonUpdateGrid3.Text = "Other Groups"
    $ButtonUpdateGrid3.add_click({
        if ($radiobutton5.Checked -eq $True -and $lines3 -gt 1)
        {
             Get-info1 ({$notBoth}, {$notBothDesc})
          
        }

    The Function is supposed to populate the columns based on the variables $u and $v (which are = Import-csv cmdlets):

    Function Get-info1($u, $v){
    
    If($datagridview1.columncount -gt 0)
    {
        $datagridview1.DataSource = $null
        $datagridview1.Columns.RemoveAt(0)
        #$datagridview1.Columns.RemoveAt(1) 
    }
    
    if($ClickCheck -eq 1)
    {
        $ButtonStartExport.Enabled = $False
    } Else
    {
        $ButtonStartExport.Enabled = $True
    }
    
    $Column1 = New-Object System.Windows.Forms.DataGridViewCheckBoxColumn
    $Column1.width = 50
    $Column1.name = 'Check'
    $DataGridView1.Columns.Add($Column1) 
    $array = New-Object System.Collections.ArrayList
    $array.AddRange($u)
    $array2 = New-Object System.Collections.ArrayList
    $array2.AddRange($v)
    $dataGridview1.DataSource = $array, $array2
    #$datagridview1.DataSource = $array2
    $datagridview1.AutoResizeColumns()

    I had it working before so that it was just adding one array range from the imported csv file, but I want to add another column of information for each click-able row. I'm just not sure exactly how to get that done.

    Wednesday, May 20, 2015 6:45 PM

Answers

All replies

  • That is not going to work.

    Just tell us what you want to add and I will show you how to do it in two lines.  You cannot do it with arrays oor sets of arrays.


    \_(ツ)_/


    • Edited by jrv Wednesday, May 20, 2015 10:34 PM
    Wednesday, May 20, 2015 10:33 PM
  • If I had it working with 1 set of array, why can't I do it with 2?

    Thursday, May 21, 2015 1:07 PM
  • If I had it working with 1 set of array, why can't I do it with 2?

    Forget about arrays for now.  What is it you want to display in the grid?  A grid is not designed to display arrays.  It is designed to display object collections that have an IList interface.  This includes data tables and dataset as well as adapted object collections.  We can  use a cast of a non ILIst enable collection of objects to an ArrayList which just adds an IList interface to the collection.

    If you can tell us what you are trying too display we can tell you if it can be adapted or if you have to do a manual conversion and load.

    As an example output from GWMI, Get-Process, Get-Service, Get-ChildItem and many of the standard CmdLets can be directly loaded into a gridview.  Multidimensional arrays cannot be directly loaded.  A directly loadable collection can usually be loaded in one line of code.  Arrays can take dozens of lines of code to prepare and load.

    What is it that you are trying to load into a grid?


    \_(ツ)_/

    Thursday, May 21, 2015 1:22 PM
  • So, my script is using Get-ADPrincipalGroupMembership of 2 user objects, then it uses Compare-Object so I can show what member $a has that member $b does not. This is basically what my script is doing:

    $a = Get-ADPrincipalGroupMembership -Identity $x
    $b = Get-ADPrincipalGroupMembership -Identity $y
    
    $distNameANDname = Compare-Object -ReferenceObject $a -DifferenceObject $b -IncludeEqual -Property distinguishedName, name | Where-Object { $_.SideIndicator -eq "<=" }
    
    $firstRowGroupsA = "Member Of:" | Out-File -FilePath "C:\_ADCompare\KUgroups.txt" -Force
    
    foreach($item in $distNameANDname.distinguishedName.GetEnumerator()) {
    
        if ($item.Contains('OU=Admin') -eq $false -And $item.Contains('OU=groups') -eq $false )
        {
            Echo $item | Out-File -FilePath "C:\_ADCompare\notBoth.txt" -Append -Force
        } 
    
    $notBoth = Import-Csv C:\_ADCompare\notBoth.txt
    
    GenerateForm
    
    Function GenerateForm {
    [void][reflection.assembly]::Load("System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
    [void][reflection.assembly]::Load("System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
    [void][reflection.assembly]::Load("mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
    [void][System.Windows.Forms.Application]::EnableVisualStyles()
    
    $ButtonUpdateGrid3 = New-Object Windows.Forms.Button
    $ButtonUpdateGrid3.Location = New-Object Drawing.Point 224,15
    $ButtonUpdateGrid3.size = New-Object Drawing.Point 90,23
    $ButtonUpdateGrid3.Text = "Other Groups"
    $ButtonUpdateGrid3.add_click({
    
    $notBoth | Measure-Object -Line
    $lines3 = $notBoth.Count
    $notBothB | Measure-Object -Line
    $lines3B = $notBothB.Count
    $notBothC | Measure-Object -Line
    $lines3C = $notBothC.Count
    
    $ClickCheck = 1
    
    if ($radiobutton5.Checked -eq $True -and $lines3 -gt 1)
    {
        Get-info1($notBoth)
    } Elseif ($radiobutton4.Checked -eq $True -and $lines3B -gt 0)
    {
        Get-info1($notBothB)
    } Elseif ($radiobutton3.Checked -eq $True -and $lines3C -gt 1)
    {
        Get-info1($notBothC)
    } Else
    {
        $DataGridView1.DataSource = $null
        $DataGridView1.ColumnCount = 0
    }
                                })
    
    $Button1 = New-Object Windows.Forms.Button
    $Button1.Location = New-Object Drawing.Point 522,15
    $Button1.size = New-Object Drawing.Point 45,23
    $Button1.Text = "Exit"
    $button1.add_Click({$form.Close()})
    
    $ButtonStartExport = New-Object Windows.Forms.Button
    $ButtonStartExport.Location = New-Object Drawing.Point 319,15
    $ButtonStartExport.size = New-Object Drawing.Point 90,23
    $ButtonStartExport.Text = "Add Selected"
    $ButtonStartExport.add_click({Do-Grid})
    
    }
    
    Function Get-info1($u){
    
    If($datagridview1.columncount -gt 0)
    {
        $datagridview1.DataSource = $null
        $datagridview1.Columns.RemoveAt(0) 
    }
    
    if($ClickCheck -eq 1)
    {
        $ButtonStartExport.Enabled = $False
    } Else
    {
        $ButtonStartExport.Enabled = $True
    }
    
    $Column1 = New-Object System.Windows.Forms.DataGridViewCheckBoxColumn
    $Column1.width = 50
    $Column1.name = 'Check'
    $DataGridView1.Columns.Add($Column1) 
    $array = New-Object System.Collections.ArrayList
    $array.AddRange($u)
    $dataGridview1.DataSource = $array
    $datagridview1.AutoResizeColumns()
    $form.refresh()
    
    $ClickCheck = 0
    
    }
    

    This isn't the full script, but this is basically what it was doing before when it worked with the 1 array range.

    Thursday, May 21, 2015 1:41 PM
  • Here is how to load that into a DGV:

    $a = Get-ADPrincipalGroupMembership -Identity $x
    $b = Get-ADPrincipalGroupMembership -Identity $y
    $c = Compare-Object $a $b -Property distinguishedName, name -PassThru |
        Where-Object { $_.SideIndicator -eq "<=" }
    # trim properties
    $d=select name,distinguishedName # other props if needed 
    $datagridView.DataSource = [System.Collections.ArrayList]$d
    
    


    \_(ツ)_/

    Thursday, May 21, 2015 1:52 PM
  • Your GenerateForm has to be moved to the end.

    \_(ツ)_/

    Thursday, May 21, 2015 1:53 PM
  • I'm not sure what you mean by moving GenerateForm to the end, but I think

    $d=select name,distinguishedName # other props if needed 
    $datagridView.DataSource = [System.Collections.ArrayList]$d

    Is what I'm looking for, I'm going to try implementing it and check back.

    Thursday, May 21, 2015 2:31 PM
  • GenerateForm is calling a function that hasn't been defined yet.  It will fail.  You are also missing all of your control assignments.


    \_(ツ)_/

    Thursday, May 21, 2015 2:39 PM
  • I'm not sure what you mean by moving GenerateForm to the end, but I think

    $d=select name,distinguishedName # other props if needed 
    $datagridView.DataSource = [System.Collections.ArrayList]$d

    Is what I'm looking for, I'm going to try implementing it and check back.

    Do not predefine columns.  They will be auto-generated when you load the datasource.


    \_(ツ)_/

    Thursday, May 21, 2015 2:40 PM
  • Also, I'll add that what I posted earlier was what my old script was doing (when it worked). When I attempted to add another column to my DGV, this is what I changed (more or less):

    Function GenerateForm { [void][reflection.assembly]::Load("System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089") [void][reflection.assembly]::Load("System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a") [void][reflection.assembly]::Load("mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089") [void][System.Windows.Forms.Application]::EnableVisualStyles() foreach ($_ in Get-Content -Path C:\_ADCompare\notBoth.txt){ if($_ -ne "Member Of:"){ $_ = $_.Replace("CN=", "") Get-ADGroup -Filter {name -eq $_} -properties Description | Out-File -FilePath C:\_ADCompare\notBothDesc.txt -Append -Force } } $ButtonUpdateGrid3 = New-Object Windows.Forms.Button $ButtonUpdateGrid3.Location = New-Object Drawing.Point 224,15 $ButtonUpdateGrid3.size = New-Object Drawing.Point 90,23 $ButtonUpdateGrid3.Text = "Other Groups" $ButtonUpdateGrid3.add_click({ $notBoth | Measure-Object -Line $lines3 = $notBoth.Count $notBothB | Measure-Object -Line $lines3B = $notBothB.Count $notBothC | Measure-Object -Line $lines3C = $notBothC.Count $notBothDesc = Import-Csv C:\_ADCompare\notBothDesc.txt $ClickCheck = 1 if ($radiobutton5.Checked -eq $True -and $lines3 -gt 1) { Get-info1 ({$notBoth}, {$notBothDesc}) } Elseif ($radiobutton4.Checked -eq $True -and $lines3B -gt 0) { Get-info1($notBothB) } Elseif ($radiobutton3.Checked -eq $True -and $lines3C -gt 1) { Get-info1($notBothC) } Else { $DataGridView1.DataSource = $null $DataGridView1.ColumnCount = 0 } }) Function Get-info1($u, $v){ If($datagridview1.columncount -gt 0) { $datagridview1.DataSource = $null $datagridview1.Columns.RemoveAt(0) } if($ClickCheck -eq 1) { $ButtonStartExport.Enabled = $False } Else { $ButtonStartExport.Enabled = $True } $Column1 = New-Object System.Windows.Forms.DataGridViewCheckBoxColumn $Column1.width = 50 $Column1.name = 'Check' $DataGridView1.Columns.Add($Column1) $array = New-Object System.Collections.ArrayList $array.AddRange($u) $array2 = New-Object System.Collections.ArrayList $array2.AddRange($v) $dataGridview1.DataSource = $array, $array2 $datagridview1.AutoResizeColumns() $form.refresh() $ClickCheck = 0 }

    So, I added the lines that does a Get-Content from my notBoth.txt and it then does a Get-ADGroup for each line item so it can extract the Description property. The Description property is what I want to be in my added column "array."
    Thursday, May 21, 2015 2:46 PM
  • So, I added the lines that does a Get-Content from my notBoth.txt and it then does a Get-ADGroup for each line item so it can extract the Description property. The Description property is what I want to be in my added column "array."

    Your form still does not work. You should not run code in the body of the form. Run it in the load or in an event.

    The form will not display correctly as it is missing many required pieces.

    To add items to the gride just add them to you selections.  The -PassThru will keep the objects and you will be able to display them directly.  Saving everything to a text file defeats the whole purpose of a grid and of objects in PowerShell;.

    Again. You cannot assign arrays to a datasource.  The datasource requires an IList capable object.


    \_(ツ)_/

    Thursday, May 21, 2015 2:57 PM
  • Suggestion:

    Make your form open and display without the grid loading.  Just place evberything in load or buttone and get it to display.  I will then show you how to make the grid load directly from a compare including the description and any other items you want in the grid.,


    \_(ツ)_/

    Thursday, May 21, 2015 2:58 PM
  • So, PassThru is new to me and I'm just reading up on it, but it makes sense to start using that instead of storing information into .txt's. I'm very new to Powershell, so I'm learning a lot as I go. I'm going to mess around with what you've mentioned so far and the PassThru parameter. Thank you for your pointers so far!
    Thursday, May 21, 2015 3:16 PM
  • Good plan.  Always try new code in the  PS CLI environment until you understand it.

    Don't forget this resource: https://technet.microsoft.com/en-us/scriptcenter/dd793612.aspx?f=255&MSPPError=-2147217396


    \_(ツ)_/

    Thursday, May 21, 2015 3:31 PM
  • Here is how to start a form:

    Function GenerateForm {
    
        Add-Type -Assembly System.Windows.Forms
        [void][System.Windows.Forms.Application]::EnableVisualStyles()
        
        $form1=New-Object System.Windows.Forms.Form
        $form1.StartPosition='CenterScreen'
        $form1.Size = '600,400'
        $from1_load={
            $notBoth | Measure-Object -Line
            $lines3 = $notBoth.Count
            $notBothB | Measure-Object -Line
            $lines3B = $notBothB.Count
            $notBothC | Measure-Object -Line
            $lines3C = $notBothC.Count
        }
        $form1.add_Load($form1_load)
        
        $ButtonUpdateGrid3 = New-Object Windows.Forms.Button
        $form1.Controls.Add($ButtonUpdateGrid3)
        $ButtonUpdateGrid3.Location='224, 15'
        $ButtonUpdateGrid3.size ='90, 23'
        $ButtonUpdateGrid3.Text = "Other Groups"
        $ButtonUpdateGrid3_click={               
            if($radiobutton5.Checked -and $lines3 -gt 1){
                Get-info1($notBoth)
            }elseif($radiobutton4.Checked -and $lines3B -gt 0){
                Get-info1($notBothB)
            }elseif($radiobutton3.Checked -and $lines3C -gt 1){
                Get-info1($notBothC)
            }else{
                $DataGridView1.DataSource=$null
            }
        }
        $ButtonUpdateGrid3.add_click($ButtonUpdateGrid3_click)
        
        $Button1 = New-Object Windows.Forms.Button
        $form1.Controls.Add($Button1)
        $Button1.Location = '522, 15'
        $Button1.size = '45, 23'
        $Button1.Text = 'Exit'
        $Button1.DialogResult='Ok'
        
        # Datagridview1
        $datagridview1=New-Object System.Windows.Forms.DataGridView
        $form1.Controls.Add($datagridview1)
        $datagridview1.Location='15,40'
        $datagridview1.Size='550,315'
        $ButtonStartExport = New-Object Windows.Forms.Button
        $form1.Controls.Add($ButtonStartExport)
        $ButtonStartExport.Location = New-Object Drawing.Point 319, 15
        $ButtonStartExport.size = New-Object Drawing.Point 90, 23
        $ButtonStartExport.Text = "Add Selected"
        $ButtonStartExport_click = {
            $x='user1'
            $y='user2'
            $a = Get-ADPrincipalGroupMembership -Identity $x
            $a = $a | Get-AdGroup -Properties description
            $b = Get-ADPrincipalGroupMembership -Identity $y
            $b = $b | Get-AdGroup -Properties description
            $c = Compare-Object $a $b -Property distinguishedName -PassThru |
                Where-Object{ $_.SideIndicator -eq '<=' }
            # trim properties
            $d = select name, description. distinguishedName # other props if needed 
            $datagridView.DataSource = [System.Collections.ArrayList]$d
        }
        $ButtonStartExport.add_click($ButtonStartExport_click)
        $form1.ShowDialog()
    }
    GenerateForm
    
    


    \_(ツ)_/

    Thursday, May 21, 2015 4:09 PM
  • I just thought defining functions can be placed anywhere in the script... Is this not accurate in some languages?
    Thursday, May 21, 2015 4:41 PM
  • I just thought defining functions can be placed anywhere in the script... Is this not accurate in some languages?

    It is not in PowerShell.  Functions must be defined before being called.

    In C and C++ this is also true but we do an end run around the rule by defining a function template in a heade5r file.  This satisfies the need for the definition.  so a file can be compiled without first compiling every function.


    \_(ツ)_/

    Thursday, May 21, 2015 4:53 PM