Boolean 'if' statement in a loop.

This topic contains 7 replies, has 4 voices, and was last updated by Profile photo of Olaf Soyk Olaf Soyk 1 month ago.

  • Author
    Posts
  • #57310
    Profile photo of Mycaelis
    Mycaelis
    Participant

    This is a very cut down version of my actual script, but it essentially highlights my problem.
    I want to do a series of checks against some users, but after an initial run though, some of the criteria for a user may change, so I want to loop through the users again any number of times set in a parameter (for this example it is only 2).

    My issue is that the -contains parameter doesn't work and is always $false in the if statement.
    All my users are getting added in twice, I can't use -match or -like as they are not accurate enough, as it needs to be an exact match.

    If I add ($Batch -contains $objUser) after ($Batch += $objUser), it shows $true, but on the next loop, the if statement is still $false when it comes up to a user with the same name in the batch.

    How do I get this to work?

    Input CSV:
    UserName
    User1
    User2
    User3
    User4
    User5
    User5

    $Batch = @()
    $Loop=2
    $Users=Get-Content -Path $InputFile
    
    for($counter = 1; $counter -le $Loop; $counter++)
    {
        Write-Output `n "RUNNING LOOP #$counter" `n
    
        foreach ($User in $Users)
        {
            $objUser = New-Object System.Object
            $objUser |  Add-Member -type NoteProperty -name UserName -value $User.UserName
          
            if 
            ($Batch -contains $objUser)
            {
                Write-Output "$($objuser.UserName) already exists in current batch; Ignore user."
            }
            else
            {
                Write-Output "$($objuser.UserName) does not exist in current batch; Adding user."
                $Batch += $objUser                  
            }
        }
    }
    
  • #57313
    Profile photo of Olaf Soyk
    Olaf Soyk
    Participant

    If you use a csv you should use 'import-CSV'.

    $Batch = @()
    $Loop=2
    $Users=Import-Csv -Delimiter ',' -Path $InputFile
    
    for($counter = 1; $counter -le $Loop; $counter++)
    {
        Write-Output `n "RUNNING LOOP #$counter" `n
    
        foreach ($User in $Users)
        {
            $objUser = New-Object System.Object
            $objUser |  Add-Member -type NoteProperty -name UserName -value $User.UserName
            
            if 
            ($Batch.UserName -contains $objUser.UserName)
            {
                Write-Output "$($objuser.UserName) already exists in current batch; Ignore user."
            }
            else
            {
                Write-Output "'$($objuser.UserName)' does not exist in current batch; Adding user ."
                $Batch += $objUser    
            }
        }
    }
    • #57319
      Profile photo of Mycaelis
      Mycaelis
      Participant

      Hi Olaf,

      Sorry, this was due to me trying to simply things for this post, the input file I have to work from is not formatted correctly so I have to use:

      $Users=Get-Content -Path $InputFile | Select-Object -Skip 1 | Out-String | ConvertFrom-Csv | Where-Object {($_.'UserName' -ne '')}

      But thanks, yes, for this example I'll change it to:

      $Users=Import-Csv -Delimiter ',' -Path $InputFile
    • #57322
      Profile photo of Olaf Soyk
      Olaf Soyk
      Participant

      Did you try my code? Did it work then? I did change more than just the csv thing! Did you try Max's approach?

  • #57316
    Profile photo of Max Kozlov
    Max Kozlov
    Participant

    $Batch -contains does not work because $Batch contain object and not string. PS tries to find object reference, but not object with same properties.

    Olaf's solution not good because of using $Batch.UserName – on each loop powershell will extract UserName value from all $Batch objects, collect it to another internal array and conpare it with $objUser.UserName. it's sooo sloooooow...

    the simpliest way to solve your problem: use hashtables

    #Init empty collection
    $Batch = @{}
    .......
    #Fill collection (inside cycle)
    if ($Batch.ContainsKey($User.UserName)) {
      "Ignore user $($User.UserName)"
    }
    else {
      $Batch[$User.UserName] = $User
    }
    .........
    #Use the collection
    $Batch.GetEnumerator() | Foreach-Object {
      $User = $_.Value
      $User.UserName
    }
    
  • #57328
    Profile photo of Dan Potter
    Dan Potter
    Participant

    $users is already an array of objects. Why would you try to build another?

    • #57355
      Profile photo of Mycaelis
      Mycaelis
      Participant

      Maybe I was being lazy, the full script has multiple headings in the CSV, the values, some are integers, some boolean, some string.
      I created the new object to ensure that all the headings were stored in the correct format, rather than all as string from an Import-CSV / Get-Content.

    • #57358
      Profile photo of Olaf Soyk
      Olaf Soyk
      Participant

      You don't answer questions. Did you solve your problem? If not – what exactly is your problem?

You must be logged in to reply to this topic.