Array Returning an extra element when running in winforms project

Ask questions about creating Graphical User Interfaces (GUI) in PowerShell and using WinForms controls.
Forum rules
Do not post any licensing information in this forum.

Any code longer than three lines should be added as code using the 'Select Code' dropdown menu or attached as a file.
User avatar
gkhairallah
Posts: 44
Last visit: Fri Jun 11, 2021 1:36 pm
Has voted: 2 times

Array Returning an extra element when running in winforms project

Post by gkhairallah »

I have a function inside Globals.ps1. It should enumerate the value in keys that exist in that registry path. In this example, there are 2 keys in the registry..

When the function in Globals.ps1 runs, the correct number of entries is populated in the array.
  1. function GetGridProfiles()
  2. {
  3.     Write-Verbose "------ Fn: Get Grid Profiles ------"
  4.     $arrayProfiles = @()
  5.     (Get-ChildItem -Path HKCU:\Software\gotomyerp\Configurator\Profiles) | ForEach-Object {
  6.         $RegPath = $($_.Name).Replace("HKEY_CURRENT_USER", "HKCU:")
  7.         $Company = Get-ItemPropertyValue -Path $RegPath -Name Company
  8.         $FeedURL = Get-ItemPropertyValue -Path $RegPath -Name FeedURL
  9.         $Username = Get-ItemPropertyValue -Path $RegPath -Name Username
  10.         $arrayProfiles += "$_.Name|$Company|$FeedURL|$Username"
  11.         Return $arrayProfiles
  12.     }
  13.     Write-Verbose "Array Profiles after GetGridProfiles is done: $($arrayProfiles)"
  14.     Write-Verbose "Array Size after GetGridProfiles is done: $($arrayProfiles.GetUpperBound(0))"
  15. }
Now in the next block of code (Load_Profile.psf)
  1. # Build the Grid PS Object
  2. Write-Verbose "Building the Grid PS Object"
  3.  
  4. $arrayObjProfiles = @()
  5. Write-Verbose "Type : $($arrayObjProfiles.GetType().BaseType.Name)"
  6. $aProfileList = GetGridProfiles
  7. Write-Verbose "aProfileList Index: $($aProfileList.GetUpperBound(0))"
  8. Write-Verbose "aProfileList: $($aProfileList))"
  9. foreach ($Profile in $aProfileList)
  10. {  
  11.     $FeedID = ($Profile.Split("|"))[0]
  12.     $Company = ($Profile.Split("|"))[1]
  13.     $FeedURL = ($Profile.Split("|"))[2]
  14.     $DisplayURL = (($FeedURL).split("/"))[0] + "//" + (($FeedURL).Split("/"))[2]
  15.     $Username = ($Profile.Split("|"))[3]
  16.     $CurrentObject = [PSCustomObject]@{
  17.         Company    = $Company
  18.         DisplayURL = $DisplayURL
  19.         Username   = $Username
  20.     }
  21.     $arrayObjProfiles += $CurrentObject
  22.     Write-Verbose "Type inside: $($arrayObjProfiles.gettype().BaseType.Name)"
  23. }
  24. Write-Verbose "arrayObjProfiles outside the loop: $($arrayObjProfiles.GetType().BaseType.Name)"
The return of $aProfileList array returns 3 elements instead of 2: a duplicate of one of the keys listed in the "GetGridProfiles" function.

Here is an output of the script when those 2 blocks of code run:
>> Running (gotomyerp Configurator.psproj) Project Script...
>> Platform: V5 32Bit (STA) (Forced)
VERBOSE: ------ Startup: Getting Workspace Feeds ------
VERBOSE: ------ Startup: Loading cmdkeys - Getting username ------
VERBOSE: ------ Startup: Getting Company from registry ------
VERBOSE: ------ Fn: Check and Set Registry  Base ------
VERBOSE: ------ Btn: LoadProfiles Click ------
VERBOSE: Building the Grid PS Object
VERBOSE: Type : Array
VERBOSE: ------ Fn: Get Grid Profiles ------
VERBOSE: Array Profiles after GetGridProfiles is done: HKEY_CURRENT_USER\Software\gotomyerp\Configurator\Profiles\E44DDD5C-BD2E-4B54-8802-8874A7CED0A0.Name|client2|https://client2.example2.com/rdweb/feed ... d.aspx|cpt HKEY_CURRENT_USER\Software\gotomyerp\Configurator\Profiles\E5E475EA-E135-4EE4-B81B-D1E107B50302.Name|client1|https://client1.example1.com/rdweb/feed ... px|qbdemo1
VERBOSE: Array Size after GetGridProfiles is done: 1
VERBOSE: aProfileList Index: 2
VERBOSE: aProfileList: HKEY_CURRENT_USER\Software\gotomyerp\Configurator\Profiles\E44DDD5C-BD2E-4B54-8802-8874A7CED0A0.Name|client2|https://client2.example2.com/rdweb/feed ... d.aspx|cpt HKEY_CURRENT_USER\Software\gotomyerp\Configurator\Profiles\E44DDD5C-BD2E-4B54-8802-8874A7CED0A0.Name|client2|https://client2.example2.com/rdweb/feed ... d.aspx|cpt HKEY_CURRENT_USER\Software\gotomyerp\Configurator\Profiles\E5E475EA-E135-4EE4-B81B-D1E107B50302.Name|client1|https://client1.example1.com/rdweb/feed ... px|qbdemo1)
VERBOSE: Type inside: Array
VERBOSE: Type inside: Array
VERBOSE: Type inside: Array
VERBOSE: arrayObjProfiles outside the loop: Array
VERBOSE: ------ Form: Load Profile ------
VERBOSE: arrayObjProfiles after the loop:
Note the 2 highlighted lines in the output. These are consecutive lines, but yet returning different array lengths.
I have checked that there are no other "OnLoad" events or similar in my forms that could trigger the array to be mis-populated.

Another interesting tidbit, is that before I moved this code to my current project (with multiple forms), I had both the function and the event code running in a single psf file (For testing), and it worked as expected. So I'm inclined to think that the issue might be somewhere between the forms being loaded/called.
Along the same lines, the $arrayObjProfiles array is also not populating in the multi-form project, but is working ok on my testing psf.

I have spent over 3 hours trying to figure it out, and I'm really stuck. This is my first forms project, so, please go easy on me :)
Would appreciate any guidance that could get me back on track.

Cheers!

jvierra
Posts: 14836
Last visit: Sat Jun 19, 2021 7:13 am
Answers: 10
Has voted: 3 times
Been upvoted: 10 times

Re: Array Returning an extra element when running in winforms project

Post by jvierra »

Your code doesn't make much sense. Perhaps you should remove all of the write statements and just step through with the debugger. I think you may just be confusing yourself because you have been concentrating on this too hard and too long.

User avatar
gkhairallah
Posts: 44
Last visit: Fri Jun 11, 2021 1:36 pm
Has voted: 2 times

Re: Array Returning an extra element when running in winforms project

Post by gkhairallah »

After stating that I spent over 3 hours on it, I figured it was clear that I tried to go through the debugger. In any case, thanks. will do.
Posting here isn't usually my first resort, but my last one.

User avatar
Alexander Riedel
Posts: 7700
Last visit: Fri Jun 18, 2021 10:15 am
Answers: 4
Been upvoted: 10 times

Re: Array Returning an extra element when running in winforms project

Post by Alexander Riedel »

Ah, three hours is nothing, I remember once carrying a box of punch cards through the snow, uphill ... But never mind :D

In general if an array or list in PowerShell does contain more items or not the items expected, these are the reasons:

- Your function to fill the array/list is called more than once. Set a breakpoint at the entry to the function, launch the debugger and check the call stack when it stops.
- Your function to fill the array/list does not empty the array first. Unless it is meant to append, defensive programming dictates that your function should always make sure to delete any pre-existing array content.
- You have two arrays with the same name at different scopes. This can happen in PowerShell. Make sure you add global modifiers to all instances where the array is used to avoid that.

Last but not least, if you cannot see the bug because of all the code, have a hot beverage, call it a day and look again tomorrow. Usually that will make things more clear.
Alexander Riedel
SAPIEN Technologies, Inc.

User avatar
gkhairallah
Posts: 44
Last visit: Fri Jun 11, 2021 1:36 pm
Has voted: 2 times

Re: Array Returning an extra element when running in winforms project

Post by gkhairallah »

Thanks for the input Alexander. That will give me a few things to look for.

My goal from this is to simply take some values from a datagrid, and bring them back to the main form for processing.
I have been studying the following : https://www.sapien.com/blog/2013/10/01/ ... ing-forms/ but this example deals with single variable values, which are easy to understand, but now adding the datagrid returning data, makes it a bit more challenging. (at least for me)

I'm aware that my method is not best practice and not the best way of writing this. But if you have any examples that I can learn from related to bringing a row of data in a datagridview from a child form back into the parent form, that would be the best. I just can't seem to find examples.

In any case, thanks again, going to have coffee now ;)

jvierra
Posts: 14836
Last visit: Sat Jun 19, 2021 7:13 am
Answers: 10
Has voted: 3 times
Been upvoted: 10 times

Re: Array Returning an extra element when running in winforms project

Post by jvierra »

The problem that happens most often when building complex forms or code structures is that we get extended beyond our current skill level. FOr me this is always a hint that I need to slow down, take a break and rethink my approach.

Unfortunately what you posted gives no clue as to how the code is called or what you are hoping to accomplish. THe counts using index against upper limit may be misleading.

To get a row of data just get the row and send it back. The returned row will persist even after the subform is closed.

Without a clearer understanding of what you are doing in the code you haven't posted then there is no easy ways to guess at the cause of what you are seeing.

I suggested simplification as a place to start. This makes the code easier to read, understand and debug. FIrst best proicatice in coding is to not write any lines that serve no purpose. After teh code works then y9ou can go back and decorate as you like but first make the code work in the simplest form available.

What I can see is that you are returning strings from the function and thinking they are an array at least how you are naming things.

Try this as it will help you see where your code may be off from what you expect. It is the same code without so many unnecessary decorations and bad syntax usage.
  1. function GetGridProfiles{
  2.     Get-ChildItem -Path HKCU:\Software\gotomyerp\Configurator\Profiles |
  3.         ForEach-Object{
  4.             $RegPath = $_.Name.Replace('HKEY_CURRENT_USER', 'HKCU:')
  5.             $Company = Get-ItemPropertyValue -Path $RegPath -Name Company
  6.             $FeedURL = Get-ItemPropertyValue -Path $RegPath -Name FeedURL
  7.             $Username = Get-ItemPropertyValue -Path $RegPath -Name Username
  8.             "$($_.Name)|$Company|$FeedURL|$Username"  # Why NOT return an array or object?
  9.     }
  10. }

jvierra
Posts: 14836
Last visit: Sat Jun 19, 2021 7:13 am
Answers: 10
Has voted: 3 times
Been upvoted: 10 times

Re: Array Returning an extra element when running in winforms project

Post by jvierra »

This would be the correct way to read registry key values and return an object instead of strings.
  1. function GetGridProfiles{
  2.     Get-ChildItem -Path HKCU:\Software\gotomyerp\Configurator\Profiles |
  3.         ForEach-Object{
  4.             [pscustomobject]{
  5.                 Name     = $_.Name
  6.                 Company  = $_.GetValue('Company')
  7.                 FeedURL  = $_.GetValue('FeedURL')
  8.                 Username = $_.GetValue('Username')
  9.             }
  10.         }
  11. }

jvierra
Posts: 14836
Last visit: Sat Jun 19, 2021 7:13 am
Answers: 10
Has voted: 3 times
Been upvoted: 10 times

Re: Array Returning an extra element when running in winforms project

Post by jvierra »

Now just add teh DisplayUrl into the function and you have everything broken out into a nice compact easy to use object.
  1. function GetGridProfiles{
  2.     Get-ChildItem -Path HKCU:\Software\gotomyerp\Configurator\Profiles |
  3.         ForEach-Object{
  4.             [pscustomobject]{
  5.                 Name     = $_.Name
  6.                 Company  = $_.GetValue('Company')
  7.                 FeedURL  = $_.GetValue('FeedURL')
  8.                 DisplayUrl =  $_.GetValue('FeedURL').split('/')[0] + '//' + $_.GetValue('FeedURL').Split('/')[2]
  9.                 Username = $_.GetValue('Username')
  10.             }
  11.         }
  12. }

jvierra
Posts: 14836
Last visit: Sat Jun 19, 2021 7:13 am
Answers: 10
Has voted: 3 times
Been upvoted: 10 times

Re: Array Returning an extra element when running in winforms project

Post by jvierra »

Alex. Never carried punch cards outside of Bell Labs. Soon we were using advanced paper tape and in a flash magnetic tape.

My old friend from high school had to carry cards for another 5 years. Old IBM machines never die.

User avatar
gkhairallah
Posts: 44
Last visit: Fri Jun 11, 2021 1:36 pm
Has voted: 2 times

Re: Array Returning an extra element when running in winforms project

Post by gkhairallah »

Thanks @jvierra!
This is very helpful, and I appreciate your guidance on how to best think about this.
You're right in that the more I got lost, the more I started injecting "info" at each step to try and figure out what's happening.

I have since taken out the code from my app and I have it limited to only the few lines in the function and am able to reproduce the problem even there. So I now know my issue is somewhere in the function.

I'm going to take what you gave me and try to figure it out (for my own education), and if I get stuck, if you don't mind, I'll post that snippet, which I trust will now be much more concise and will hopefully show the problem much more clearly for the trained eye.

Also, on your comment :
  1.  "$($_.Name)|$Company|$FeedURL|$Username"  # Why NOT return an array or object?'
My goal from this is to actually return an array of arrays (?) ... each one containing the 4 values. Due to my lack of knowing how to do it, I'm trying to pass that whole string with "separators", have each object in the loop return one array element (with 4 values in it and the "|" separator which I can process outside of the function). I absolutely realize it's a very clunky way of doing it. Trying to learn how to do it better though :)

Locked