locked
Match not functioning for hashtable keys RRS feed

  • Question

  • Updated

    Hello,

    I'm seeing unexpected behavior and am hoping for a little help.

    My PS ver is:

    Major  Minor  Build  Revision
    -----  -----  -----  --------
    3      8      0      129 

    Here is a snip that illustrates the issue (reproducible)

    $aRecords = $null;	$aRecords = @{}
    
    $aRecords.add('tblARecords_1_txtHost','1.1.1.2')
    $aRecords.add('tblARecords_0_txtHost','1.1.1.1')
    $aRecords.add('tblARecords_1_txtPointsto','1.1.1.2')
    $aRecords.add('tblARecords_0_txtPointsto','1.1.1.1')
    
    $gdRecords = $null;	$gdRecords = @{}
    $gdRecords['typeA'] = $aRecords
    
    $records = $null;$records = @()
    $records = 'tblARecords_0'
    
    
    foreach($g in $gdRecords.Keys) {
    	foreach($d in $gdRecords[$g]) {
    		if($d.Keys -match $records) {
    		 	write $d
    		}
    	}
    }



    $records = tblARecords_0

    But the results i get back are 

    tblARecords_1_txtHost
    tblARecords_0_txtHost
    tblARecords_1_txtPointsto
    tblARecords_0_txtPointsto

    Even if i substitute the the variablw $wr with the string itself ('tblARecords_0'). It still produces the same same results

    Any help would be appreciated



    • Edited by GeoffGin Friday, January 23, 2015 12:49 AM
    Thursday, January 22, 2015 10:37 PM

Answers

  • The -match operator behaves differently depending on whether the left operand is a collection or a single value.  Here's two very different pieces of code:

    if($d.Keys -match $records) {
        Write-Output $d
    }

    $filtered = @{}
    
    foreach ($key in $d.Keys -match $records)
    {
        $filtered[$key] = $d[$key]
    }
    
    Write-Output $filtered


    $d.Keys is a collection in both bits of code.  The first bit of code says "If this hashtable contains ANY keys that match this pattern, output the entire hashtable.  (Including keys that didn't match the pattern.)"  The second example builds a new hashtable that only contains the keys which do match the pattern; all others are discarded.


    • Edited by David Wyatt Friday, January 23, 2015 2:08 PM
    • Marked as answer by GeoffGin Friday, January 23, 2015 2:36 PM
    Friday, January 23, 2015 2:06 PM

All replies

  • See #7 and #8 from this list:

    How to Write a Bad Forum Post

    Obviously we don't have your data, so we can't reproduce. You need to follow the Short, Self Contained, Correct, Example principle (http://sscce.org/).

    In other words: Write a short script that 1) contains the relevant data and 2) contains only the absolute minimum amount of code needed to reproduce the problem. In the process of doing this you may find that you are able to answer your own question.


    -- Bill Stewart [Bill_Stewart]

    Thursday, January 22, 2015 10:44 PM
  • First let me say thank you so much for such a warm welcome to this corporately owned blog. Who needs customers right.

    It'll take me a bit to repro, I will post as soon as I can


    Thursday, January 22, 2015 11:16 PM
  • First let me say thank you so much for such a warm welcome to this corporately owned blog. Who needs customers right.

    Just so you're aware, we're not MSFT employees. We're just regular folks like you.

    Bill is definitely right though, there's no way we can really help you without having something to test with.


    Don't retire TechNet! - (Don't give up yet - 13,085+ strong and growing)

    Friday, January 23, 2015 12:03 AM
  • I understand that he is devoting his own time and effort, and that he is not a MSFT employee. For that i am appreciative. My issue is that an approved moderator should be a bit more thoughtful with his language. Normally i wouldn't care but am having one of those days. Problem is someone may be put off from that approach and may not come back. Perhaps also move on to something else as a result.

    I also agree with his request, I probably should have made a reproducible script prior to posting and am updating my question.

    Friday, January 23, 2015 12:10 AM
  • I understand that he is devoting his own time and effort, and that he is not a MSFT employee. For that i am appreciative. My issue is that an approved moderator should be a bit more thoughtful with his language. Normally i wouldn't care but am having one of those days. Problem is someone may be put off from that approach and may not come back. Perhaps also move on to something else as a result.

    I also agree with his request, I probably should have made a reproducible script prior to posting and am updating my question.

    Sorry but I disagree.  I know you believe your post is useful and explains everything.  It doesn't.  None of us can decode your variables or comments because we do not have your environment or the full script.

    Bill was trying to point put that you need to put in more effort to ensure those who are trying to help you do not have to play guessing games.

    Items 7 and 8 are exactly to the point.  Addres those issues and you will likley get a quick and correct answer.

    Here are items 7 and 8:

    7. Let someone else devise a repro case. When the button click handler isn't called in your sample, by no means should you try to create a smaller repro case. All you know is that your sample doesn't run.

    • 8. Post a sample that depends on a resource you don't describe. Be sure your sample reads from your production database. Don't worry, people will figure out your schema.


    ¯\_(ツ)_/¯

    Friday, January 23, 2015 12:16 AM
  • Like i mentioned,

    "I also agree with his request, I probably should have made a reproducible script prior to posting and am updating my question."

    Which is why i updated my 100% reproducible above.

    My issue wasn't with what he was asking, it was how. Also your reply does little to help and more to exacerbate my sentiment 

    Maybe just havin a bad day! :)

    Friday, January 23, 2015 12:34 AM
  • Just to add, below works. So it seems its as if its only when another dimension is in play.

    $aRecords = $null;	$aRecords = @{}
    
    $aRecords.add('tblARecords_1_txtHost','1.1.1.2')
    $aRecords.add('tblARecords_0_txtHost','1.1.1.1')
    $aRecords.add('tblARecords_1_txtPointsto','1.1.1.2')
    $aRecords.add('tblARecords_0_txtPointsto','1.1.1.1')
    
    $records = $null;$records = @()
    $records = 'tblARecords_0'
    
    foreach($a in $aRecords.Keys){
    	if($a -match $records){write $a}
    }
    I'm probably missing something stupid, any help would be appreciated.

    • Proposed as answer by mjolinor Friday, January 23, 2015 1:37 AM
    • Unproposed as answer by mjolinor Friday, January 23, 2015 1:54 AM
    Friday, January 23, 2015 1:00 AM
  • Well it is pretty clear the nione of us will ever guess this conundrum so good luck.


    ¯\_(ツ)_/¯

    Friday, January 23, 2015 1:05 AM
  • Thats fine I guess I will move on to another forum. Its a shame this is the type of experience you get when coming to a ms help forum. I wonder why MS gets the stigma it has.

    Anyway thanks for all the help

    Friday, January 23, 2015 1:11 AM
  • This seems to do what you're after:

    $aRecords = $null;	$aRecords = @{}
    
    $aRecords.add('tblARecords_1_txtHost','1.1.1.2')
    $aRecords.add('tblARecords_0_txtHost','1.1.1.1')
    $aRecords.add('tblARecords_1_txtPointsto','1.1.1.2')
    $aRecords.add('tblARecords_0_txtPointsto','1.1.1.1')
    
    $gdRecords = $null;	$gdRecords = @{}
    $gdRecords['typeA'] = $aRecords
    
    $records = $null;$records = @()
    $records = 'tblARecords_0'
    
    
    foreach($g in $gdRecords.Keys) {
    	foreach($d in $gdRecords[$g]) {
            $d.Keys | ForEach { 
                If ($_ -match $records) {
                    Write-Output $_
                }
            }
        }
    }


    Don't retire TechNet! - (Don't give up yet - 13,085+ strong and growing)

    Friday, January 23, 2015 1:19 AM
  • Thanks for the reply Mike,

    Odd that does seem to work for my example, I guess its a dif between foreach and foreach-object?

    Doesn't help in my situation though, that snippit was just to illustrate the issue. I need to be able to get the key/value pair and assign to var.

    Do you think this is a bug?

    Friday, January 23, 2015 1:41 AM
  • Thought maybe this would do it, but doesn't

    $tmp = $null;$tmp = @{} foreach($g in $gdRecords.Keys) { foreach($d in $gdRecords[$g]) { $d | ?{$_.keys -match $records } | %{$_ += $tmp} } }

    write $tmp


    So i think there goes that theory

    Friday, January 23, 2015 2:01 AM
  • I haven't been following that closely, but it looks like you're trying to do a -match using two arrays here:

    $_.keys -match $records 


    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "

    Friday, January 23, 2015 2:09 AM
  • in my actual script i am, but i loop through it at well. for this instance, both of the below  have the same affect.

    [string]$records = $null
    $records = 'tblARecords_0'
    
    foreach($g in $gdRecords.Keys) {
    	foreach($d in $gdRecords[$g]) {
    		if($d.keys -match $records) {
    			 	write $d
    		}
    	}
    }
     

    or explicitly

    foreach($g in $gdRecords.Keys) {
    	foreach($d in $gdRecords[$g]) {
    		if($d.keys -match 'tblARecords_0') {
    			 	write $d
    		}
    	}
    }

    Friday, January 23, 2015 2:26 AM
  • I'd have to sit down with it awhile to sort out, but just for reference the -match operator requires a single string argument (regex) on the the RH side.  An array will not work.

    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "

    Friday, January 23, 2015 3:04 AM
  • My intent wasn't to offend but rather to instruct.


    -- Bill Stewart [Bill_Stewart]

    Friday, January 23, 2015 3:36 AM
  • For the differences between the foreach statement and the ForEach-Object cmdlet, see here:

    Windows IT Pro: Windows PowerShell Constructs


    -- Bill Stewart [Bill_Stewart]

    Friday, January 23, 2015 3:41 AM
  • No worries, i'm sure i was being over sensitive.
    Friday, January 23, 2015 11:51 AM
  • The problem is even if I put the string explicitly (see above - 'tblARecords_0'), it still doesn't work. I'm guessing there is a gotcha with layered foreach's or multidimensional hash's...or both.

    If this isn't a gotcha or a syntactical error but instead a bug how would i go about reporting it?

    Friday, January 23, 2015 11:59 AM
  • The -match operator behaves differently depending on whether the left operand is a collection or a single value.  Here's two very different pieces of code:

    if($d.Keys -match $records) {
        Write-Output $d
    }

    $filtered = @{}
    
    foreach ($key in $d.Keys -match $records)
    {
        $filtered[$key] = $d[$key]
    }
    
    Write-Output $filtered


    $d.Keys is a collection in both bits of code.  The first bit of code says "If this hashtable contains ANY keys that match this pattern, output the entire hashtable.  (Including keys that didn't match the pattern.)"  The second example builds a new hashtable that only contains the keys which do match the pattern; all others are discarded.


    • Edited by David Wyatt Friday, January 23, 2015 2:08 PM
    • Marked as answer by GeoffGin Friday, January 23, 2015 2:36 PM
    Friday, January 23, 2015 2:06 PM
  • Awesome, thanks David,

    After looking at it it makes complete sense.

    Thanks to all that helped

    Friday, January 23, 2015 2:36 PM