Testing for a known value that may or may not exist among other unknown values in an array.

I have 4 possible scenarios listed below (a-d) for my arrary that I must test for and take action. The values in this array are an object. The only value in my arrary that is a known value is number 2 which might not exist. This is the part where I am failing and its scenario b, the rest I have working. In other words values 1,3,4,5 could be anything including null and value 2 either exists or it's null. So when running scenario b. my end result should look like this:
delete 1
delete 3
delete 4
delete 5
create 2

------------------------------
a. $objects = 1,2,3,4,5
b. $objects = 1,3,4,5
c. $objects = ""
d. $objects = ,2

if scenario a. then "delete 1,3,4,5 and leave 2 alone"
if scenario b. then "delete 1,3,4,5 and create 2"
if scenario c. then "nothing exists, create 2"
if scenario d. then "2 exists 1,3,4,5 do not exist, do nothing"
foreach ($foo in $objects)
{
if ($foo -ne 2 -and $foo -ne "") {Write-Host delete $foo}
elseif ($foo -eq 2) {Write-Host "$foo exists do nothing"}
elseif ($objects -eq "") {Write-Host "nothing exists, create 2"}
}

Open in new window

LVL 1
illtbaguAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Michel PlungjanIT ExpertCommented:
Just test 2 after the loop
Cant you remove the items from the list and if there is no 2 at the end, create it
0
Chris DentPowerShell DeveloperCommented:

> my end result should look like this:

But that's not what you've asked it to do. No condition will fire if 2 is simply not there unless your variable ($objects) is an empty string ($objects -eq "").

Consider that you're testing each element in the loop. To test for a value that is not there you would have to set a flag of some kind:

$Create2 = $True
foreach ($foo in $objects)
{
  if ($foo -ne 2 -and $foo -ne "") {Write-Host delete $foo}
  elseif ($foo -eq 2) {Write-Host "$foo exists do nothing"; $Create2 = $False}
  elseif ($objects -eq "") {Write-Host "nothing exists, create 2"}
}
if ($Create2) { Write-Hosts "nothing exists, create 2" }

There are ways around that including:

1. Convert the array into a string and test the string for the value
2. Load the array into an ArrayList (which has a Contains method)
3. Load the array into a Hash (which has a Contains method)

Chris
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Michel PlungjanIT ExpertCommented:
I do not do Powerscripting but I think you mean


$Create2 = $True
foreach ($foo in $objects)
{
  if ($foo  -ne 2 -and $foo -ne "") {Write-Host delete $foo}
  elseif ($foo -eq  2) {Write-Host "2 exists do nothing"; $Create2 = $False}
}
if  ($Create2) { Write-Hosts "nothing exists, create 2" }

0
Has Powershell sent you back into the Stone Age?

If managing Active Directory using Windows Powershell® is making you feel like you stepped back in time, you are not alone.  For nearly 20 years, AD admins around the world have used one tool for day-to-day AD management: Hyena. Discover why.

Chris DentPowerShell DeveloperCommented:

Sure, that would do, the last elseif statement is a bit odd anyway :)

Chris
0
illtbaguAuthor Commented:
Chris-Dent,
You say that that is not what I asked it (my script) to do and you are correct, the
elseif ($objects -eq "") {Write-Host "nothing exists, create 2"}
statement is for scenario c. not b., I did not created any rules for b when the number 2 is missing.
However if I use your flag suggestin then yes I will need to take this out.
I have also looked at hash tables as you suggested but failed to find the contains method, can you give me an example? The below code works and uses a flag however the first foreach that sets the flag sets it each time a non 2 is encountered. How can I using a loop search each value for the number 2 and only set the flag once. So for scenario a. the first foreach sets the flag to true because the last record it finds is the number 5, then in the last foreach loop you change the flag to false if the number 2 is found. There has got to be a cleaner way to do this.

foreach ($foo2 in $objects)
{
if ($foo2 -ne 2 -or $foo2 -eq "") {$Create2 = $True; Write-Host flag to create 2}
}
$Create2

foreach ($foo in $objects)
{
  if ($foo -ne 2 -and $foo -ne "") {Write-Host delete $foo}
  elseif ($foo -eq 2) {Write-Host "$foo exists do nothing"; $Create2 = $False}
  #elseif ($objects -eq "") {Write-Host "nothing exists, create 2"}
}
if ($Create2) { Write-Host "create 2" }
0
Michel PlungjanIT ExpertCommented:
Erm


$Create2 = $True <<<<< 2 not encountered yet
foreach ($foo in $objects)
{
   if ($foo  -ne 2 -and $foo -ne "") {Write-Host delete $foo} <<<<<<  delete any non-2
  elseif  ($foo -eq  2) {Write-Host "2 exists do nothing"; $Create2 = $False} <<<< only set if 2 is encountered
}
if   ($Create2) { Write-Hosts "nothing exists OR 2 did not exist, create 2" } <<<<<<<<<<< we need to create 2 if it was not there either because the object were empty or because 2 did not exist in objects
0
Chris DentPowerShell DeveloperCommented:

The Hash example, this may not be the cleanest (because a hash consists of key/value pairs):

$Hash = @{1 = ""; 3 = ""; 4 = ""}
If (!$Hash.Contains(2)) { "2 did not exist, create 2" }

This is the ArrayList example, might be the better choice:

$ArrayList = New-Object Collections.ArrayList
$ArrayList.AddRange(@(1, 3, 4, 5))
If (!$ArrayList.Contains(2)) { "2 did not exist, create 2" }

> a. the first foreach sets the flag

Why would you repeat the ForEach loop?

You must set something that can exist outside of the loop to determine if a value exists. That something must be reset if it is stored as a persistent variable (as I did in my original example) and you intend to call the loop again.

You cannot perform the reset within the loop because you are trying to determine if a value exists within the array as a whole. Inside the loop you can only examine the current element. Take a quick look at this loop from your post above:

$Create2 = $False  # This is the start condition for Create2 before enumerating the array
foreach ($foo2 in $objects)
{
  # Here we have a single value in the array
  if ($foo2 -ne 2 -or $foo2 -eq "") {
    # If the *current* value is not 2 *or* is equal to a space
    $Create2 = $True; Write-Host flag to create 2
  }
}
$Create2

First $foo2 -eq "" is pointless in this context. If the value is a space then it is already not equal to 2.

If $objects contains anything other than 2 anywhere in the array then you set $Create2 to True, regardless of whether or not it finds 2 elsewhere in the array. Test it with $objects = 1, 2.

If resetting the flag each time is undesirable then you can wrap the whole thing up in a function:

Function DoesArrayContain2 ([Array]$Array)
{
  ForEach ($Value in $Array)
  {
    If ($Value -eq 2) { Return $True }
  }
  Return $False
}

And you might use that to test your array:

$objects = 1,2,3,4,5
DoesArrayContain2 $objects
$objects = 1,3,4,5
DoesArrayContain2 $objects

It achieves the same as my original use of the flag, except this time the default value is False and is forced if the loop exits without finding 2 first.

Chris
0
Chris DentPowerShell DeveloperCommented:
I have another for you.

PowerShell is a .NET language. The types we're dealing with are .NET types. Object[] is System.Object[] and has a base type of System.Array. It means a mass of static methods from System.Array can be applied here:

http://msdn.microsoft.com/en-us/library/system.array_members%28v=VS.100%29.aspx

And means you can do this:

$objects = 1, 2
If ([Array]::IndexOf($objects, 2) -eq -1) { "2 did not exist, create 2" }
$objects = 1, 3
If ([Array]::IndexOf($objects, 2) -eq -1) { "2 did not exist, create 2" }

If the value does exist it will return the element number in the array (0 or higher).

> There has got to be a cleaner way to do this.

And I wanted to catch up on this one.

Can you give us context for the loop you're trying to use?

It's not unusual to come up with one method of doing something in PowerShell only to find something far easier later on.

In the unlikely event you can't deal with it using PowerShell CmdLets you can start hunting through the .NET framework for a way. The static method I used above is an example of this ([Array]::IndexOf).

For us to help you find a better way you'll have to tell us how you're creating $objects and what your goals are.

Don't get me wrong, I won't stop this discussion if you wish to continue. I'll quite happily spend days discussing the loops above with you and mplungjan, it's fun (well, for me at least) if you want to learn it :)

Chris
0
illtbaguAuthor Commented:
Great thanks Chris-Dent. I think I like the array list method. You have been very helpful!!
Also thanks to mplungjan and mplungjan
Someone slap me for making this harder than it needed to be : )
0
Chris DentPowerShell DeveloperCommented:

You're most welcome.

But I don't think slapping is called for, if you never learnt the hard way how would you ever know the easy way was easy? :)

Chris
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Powershell

From novice to tech pro — start learning today.