简体   繁体   中英

How to handle foreach loop Powershell two times?

I have foreach loop inside foreach loop. I do some string process and mapping a file with specific string. I use messagebox to let user know which file is match or not. I tried this, it works, but the messsagebox show 6 times but It supposed to be 3 times. Anyone can help me please. Thank you.

Add-Type -AssemblyName PresentationFramework
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()

$Process = "D:\Pro"
$AllFiles = Get-ChildItem -Path $Process\*.pro -File | ForEach-Object {$_.BaseName.Substring(45)}
$Selected = @("XY11WWOLAT601A1ABA", "XY11WWOLAT601APABA", "XY11WWOLAT601ZHABA") | ForEach-Object {$_.Substring(2,13)}

foreach ($job in $AllFiles)
{
    
     $JobSplit = $job -split "_"
     $Name =  [string]::Concat($JobSplit)

     foreach ($SW in $Selected)
     {
          if ($SW -like "*$Name")
          {
               [System.Windows.Forms.MessageBox]::Show("This SW: $SW`nNOT available.","[Error]" , "OK", "Error")
          
          }
          else {

               [System.Windows.Forms.MessageBox]::Show("This SW: $SW`nAvailable.","[Info]" , "OK", "Info")     
          }
     }         
}

This is the AllFiles sample: 123456789A_A2E9D28DA533_20200702045123_XX_ABC11WWOLAT601_A1.pro 123456789A_A2E9D28DA533_20200702011155_XX_ABC11WWOLAT601_ZH.pro

You are misunderstanding how nested loops work. ForEach data object in the outloop, process the data object in then inner loop.

Example:

1..3 | 
ForEach {
"`n *** Processing outloop $PSItem *** `n"
    'a','b','c' | 
    ForEach {
        "Processing innerloop $PSItem"
    }
}
# Results
<#
*** Processing outloop 1 *** 

Processing innerloop a
Processing innerloop b
Processing innerloop c

*** Processing outloop 2 *** 

Processing innerloop a
Processing innerloop b
Processing innerloop c

*** Processing outloop 3 *** 

Processing innerloop a
Processing innerloop b
Processing innerloop c
#>

So... as for your code...

Add-Type -AssemblyName PresentationFramework
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()

$Process  = "D:\Pro"

# ForEach #1
$AllFiles = Get-ChildItem -Path $Process\*.pro -File | 
ForEach-Object {$_.BaseName.Substring(45)}

# ForEach #2
$Selected = @("XY11WWOLAT601A1ABA", "XY11WWOLAT601APABA", "XY11WWOLAT601ZHABA") | 
ForEach-Object {$_.Substring(2,13)}


<#
ForEach #3 that use the results of ForEach #1
This is the outer ForLoop
This will process for each data object
So, whatever the count of $Allfiles is each must be process X times
#>
foreach ($job in $AllFiles)
{
     "Processing job $job in the outer loop"
     $JobSplit = $job -split "_"
     $Name =  [string]::Concat($JobSplit)

    <#
    ForEach #4 that use the results of ForEach #2
    This is the inner ForLoop
    This will process 3 times for each data object in the outerloop
    Each much be processed for each data object in $AllFiles.
    #>
     foreach ($SW in $Selected)
     {
        "Processing SW $SW in the inner loop"
          if ($SW -like "*$Name")
          {
               [System.Windows.Forms.MessageBox]::Show("This SW: $SW`nNOT available.","[Error]" , "OK", "Error")
          
          }
          else {

               [System.Windows.Forms.MessageBox]::Show("This SW: $SW`nAvailable.","[Info]" , "OK", "Info")     
          }
     }         
}

You don't need a second loop here.

There are some inconsistencies in your question though.

You say:

I use messagebox to let user know which file is match or not

Then

it works, but the messsagebox show 6 times but It supposed to be 3 times

And provide a 2 filename sample as reference

123456789A_A2E9D28DA533_20200702045123_XX_ABC11WWOLAT601_A1.pro 123456789A_A2E9D28DA533_20200702011155_XX_ABC11WWOLAT601_ZH.pro

If you want 1 message box per file to state whether or not it match the string, then you'll end up with 2 message box. Not 3, not 6.

Now, to your actual problem. You only need to loop through all the files one by one and validate whether or not they are part of $Selected . That second part does not require a second loop. Rather, we'll determine if the filename is a match using the .where method.

foreach ($Job in $AllFiles) {
    $Selection = $Selected.Where( { $_ -like "*$Job" },'first')
    
    if ($Selection.count -gt 0) {
        [void][System.Windows.Forms.MessageBox]::Show("This SW: $($Selection[0])`nNOT available.", "[Error]" , "OK", "Error")
    }
    else {
        [void][System.Windows.Forms.MessageBox]::Show("This SW: $Job`nAvailable.", "[Info]" , "OK", "Info")     
    }
}

If I got this the wrong way around and your really wanted 3 message box, thus 1 message box per item in $Selected rather than 1 message box per file, then you just need to change the foreach loop for this one:


foreach ($SW in $Selected) {
    $Selection = $AllFiles.Where( { $SW -like "*$_" }, 'first')

    if ($Selection.Count -eq 1) {
        [void][System.Windows.Forms.MessageBox]::Show("This SW: $SW`nNOT available.", "[Error]" , "OK", "Error")
    }
    else {
        [void][System.Windows.Forms.MessageBox]::Show("This SW: $SW`nAvailable.", "[Info]" , "OK", "Info")     
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM