How to break Foreach loop in Powershell? - loops

I'm looking for a way to break my Foreach loop.
This is my code
$MyArray = #("desktopstudio","controller","storefront","desktopdirector","licenseserver")
$component = "toto,blabla"
$component = $component.Split(",")
foreach ($value in $component)
{
if ($MyArray -notcontains $value)
{
Write-host "Your parameter doesn't match"
Write-host "Please use one of this parameter $MyArray"
Break
}
}
write-host "I'm here"
I don't understand why it's not breaking my code, because this is the result when I execute it :
Your parameter doesn't match
Please use one of this parameter desktopstudio controller storefront desktopdirector licenseserver
I'm here
You can see that my Write-Host "I'm here" is executed while it should not.

The break statement is used to exit from a loop or switch block which is what it is doing in your case. Instead, you probably want to use the exit command to stop execution of your script when an invalid parameter is found.
$MyArray = #("desktopstudio","controller","storefront","desktopdirector","licenseserver")
$component = "toto,blabla"
$component = $component.Split(",")
foreach ($value in $component)
{
if ($MyArray -notcontains $value)
{
Write-host "Your parameter doesn't match"
Write-host "Please use one of this parameter $MyArray"
exit # <--- change is here
}
}
write-host "I'm here"
See also Get-Help about_Break, Get-Help exit, Get-Help return for more information.

Related

How to continue a loop using PowerShell?

I want to continue my looping. But it does not continue once the first process not found.
This is my code.
function Capture
{
##some process##
Write-Host "Capture"
Start-Sleep -s 1
}
function error
{
##some process##
write-host "error function"
write-host "error function2"
write-host "error function3"
Capture
Exit
}
String = #('The Student Name is','Data Member')
try
{
foreach ($str in $String )
{
$Bio = Get-Content ".\DUMP1.log" -ErrorAction Stop | Where-Object {$_ -like "*$str*"}
if ($null -eq $Bio)
{
Write-Host "not found"
error
continue
}
return $Bio
}
}
catch
{
$msg = "Bio Not Found`n" + $_
$ExitCode = "133"
Exit $ExitCode
}
If the first array not exist in the DUMP.log file, then it stop the process, it does not continue to check the second array.
My expectation is, once the first array can not found, then check the second array, after all the array checking not found, then the process will continue to error function. But The process will not go to error function as long as the process still not checking all the array.
Anyone can help please. Thank you

How to show only Read-Host value from a text file array?

I have a text file array JobTitle.txt which looks like this:
Sales Co-Worker, TSALES, TSALSK
Business Navigator, BNOM, BNOMD
And I wanted to write a code that would read the user's input and present the second and the third value from the same line. Here's what I wrote:
$jobtitledb = Get-Content C:\Users\Username\Desktop\Scripts\JobTitle.txt
$jobtitleinput = Read-Host 'Input the job title'
foreach ($data in $jobtitledb) {
$jobtitleinput, $basic, $extended = $data -split ','
Write-Host "Basic template is: "$basic
Write-Host "Extended template is: "$extended
}
I can't seem to figure out how to make it return desired line only. For clarification, when I input Sales Co-Worker I want the program to return:
Basic template is: TSALES
Extended template is: TSALSK
You just need an if statement that checks to make sure your input was the same as the jobtitle its reading in on each line.
$jobtitledb = Get-Content C:\Users\Username\Desktop\Scripts\JobTitle.txt
$jobtitleinput = Read-Host 'Input the job title'
foreach($data in $jobtitledb) {
$jobtitle, $basic, $extended = $data -split ','
If ($jobtitle -eq $jobtitleinput) {
Write-host "Basic template is: "$basic
Write-host "Extended template is: "$extended
}
}
Also I think when you were reading each line you were assigning the jobtitle to the same variable as the user input, so you should change that as well. Above code should work.
Here's an annotated script that should fix your problem. It's mostly the same as the original except where I changed it to store the job tile from the record in $jobtitle instead of $jobtitleinput and added an if statement. Also added a $jobnotfound variable and code to print the appropriate message
$jobtitledb = Get-Content C:\Users\Username\Desktop\Scripts\JobTitle.txt
$jobtitleinput = Read-Host 'Input the job title'
$jobnotfound = $ftrue
foreach($data in $jobtitledb)
{
# Store the job title from the record in $jobtitle instead of
# overwriting $inputjobtitle
$jobtitle, $basic, $extended = $data -split ','
# check the $jobtitle from record against the $jobtitleinput
if ($jobtitle -match $jobinputtitle)
{
Write-host "Basic template is: "$basic
Write-host "Extended template is: "$extended
$jobnotfound = $false
break
}
}
if ($jobnotfound)
{
Write-Host "No job matching '$jobinputtitle' was found."
}
I added an "else" statement, else { Write-Host 'Given job title does
not exist' } But it runs once for each line. How to make it return
only 1 line of "Given job title does not exist"?
I can't post comments yet, however you should just be able to use break within your else statement to exit the foreach loop.
---------- Edit ----------
The following should provide the desired output.
$jobtitledb = Get-Content C:\Users\Username\Desktop\Scripts\JobTitle.txt
$jobtitleinput = Read-Host 'Input the job title'
$found = $false
foreach($data in $jobtitledb)
{
$jobtitle, $basic, $extended = $data -split ','
If ($jobtitle -eq $jobtitleinput) {
Write-host "Basic template is: "$basic
Write-host "Extended template is: "$extended
$found = $true
break
}
}
if(!$found)
{
Write-Host "Given job title does not exist"
}

If-else inside a foreach doesn't return what I think it should

I have an array of servers that I need to loop through, and have an attribute assigned only to specific servers (this happens later in the script).
Here's the array:
$test = #('test_dc','test_fp','test_ts','test_ap')
In the array, I have a domain controller, file/print, terminal server, and application servers (in that order).
The only servers that should get the attribute are the fp, ts, and ap servers.
Here's what I've tried thus far:
foreach ($item in $test) {
Write-Host $item "`n"
Write-Host "Start IF here `n"
if ($item.Name -like '*fp*') {
Write-Host "Found $item"
} else {
Write-Host "ELSE `n"
Write-Host '-=-=-=-=-'
}
}
Here's the output from that:
PS C:\Users\me\Desktop> .\scratch.ps1
test_dc
Start IF here
ELSE
-=-=-=-=-
test_fp
Start IF here
ELSE
-=-=-=-=-
test_ts
Start IF here
ELSE
-=-=-=-=-
test_ap
Start IF here
ELSE
-=-=-=-=-
PS C:\Users\me\Desktop>
According to the way I think it should work, I should see this:
...
test_fp
Found test_fp
...
I've also tried this:
if ($test -contains '*fp') {
Write-Host "Found $_"
} else {
Write-Host 'end'
}
and I just get an empty line.
You're seeing extra info being written to host as you have indefinite writes for each item, regardless if it matches. Since you're including the else statement as well, you're going to see extra stuff written for the non-matched items. Your foreach loop also specifies the name attribute for the object, while your $test array only contains strings.
Here's what I updated it to to limit to only write the host name in your loop if it matches *fp*, otherwise writing your divider:
$test = #('test_dc','test_fp','test_ts','test_ap')
foreach ($item in $test) {
if ($item -like '*fp*') {
Write-Host "Found $item"
} else {
Write-Host '-=-=-=-=-'
}
}
Running that will output this:
-=-=-=-=-
Found test_fp
-=-=-=-=-
-=-=-=-=-

Do..Until on a never ending loop

I have written a Do..Until statement to check whether a file exists. If the file is not there, it waits a couple seconds and checks again.
It is supposed to end when the file appears. I have tested by running the script without the file and then adding it in the folder as the script is running.
Instead of ending, it continues to loop endlessly. Can anyone see what I have missed?
$path = test-path "C:\Temp\test.txt"
do {
if (!($path)) {
Write-Host "Not here yet..."
Start-Sleep -s 3
}
} until($path)
Write-Host "Files here now"
Write-Host "Press any key to continue ..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
The Test-Path statement is evaluated in the line
$path = Test-Path "C:\Temp\test.txt"
After that the variable $path contains the boolean result of the evaluation. Put the actual check in your conditions:
$path = "C:\Temp\test.txt"
do {
if (-not (Test-Path $path)) {
Write-Host "Not here yet..."
Start-Sleep -s 3
}
} until (Test-Path $path)
or define it as a function that you call in your conditions:
function Test-File {
Test-Path "C:\Temp\test.txt"
}
do {
if (-not (Test-File)) {
Write-Host "Not here yet..."
Start-Sleep -s 3
}
} until (Test-File)
OK, figured it out 3 minutes after posting this (and an hour before that of frustration!).
I needed to put the variable INSIDE the Do..Until statement. Like so:
do{
$path = test-path "C:\Temp\test.txt"
if (!($path))
{Write-Host "Not here yet..."
start-sleep -s 3}
}
until($path)
Write-Host "Files here now"
Write-Host "Press any key to continue ..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

Powershell Only Add to Array if it doesn't exist

In PowerShell v2, I'm trying to add only unique values to an array. I've tried using an if statement that says, roughly, If (-not $Array -contains 'SomeValue'), then add the value, but this only ever works the first time. I've put a simple code snippet that shows what I'm doing that doesn't work and what I've done as a workaround that does work. Can someone please let me know where my issue is?
Clear-Host
$Words = #('Hello', 'World', 'Hello')
# This will not work
$IncorrectArray = #()
ForEach ($Word in $Words)
{
If (-not $IncorrectArray -contains $Word)
{
$IncorrectArray += $Word
}
}
Write-Host ('IncorrectArray Count: ' + $IncorrectArray.Length)
# This works as expected
$CorrectArray = #()
ForEach ($Word in $Words)
{
If ($CorrectArray -contains $Word)
{
}
Else
{
$CorrectArray += $Word
}
}
Write-Host ('CorrectArray Count: ' + $CorrectArray.Length)
The Result of the first method is an array containing only one value: "Hello". The second Method contains two values: "Hello" & "World". Any help is greatly appreciated.
To fix your code, try -notcontains or at least WRAP your contains-test in parantheses. Atm. your test reads:
If "NOT array"(if array doens't exist) contains word.
This makes no sense. What you want is:
If array does not contain word..
That's written like this:
If (-not ($IncorrectArray -contains $Word))
-notcontains is even better, as #dugas suggested.
The first time around, you evaluate -not against an empty array, which returns true, which evaluates to: ($true -contains 'AnyNonEmptyString') which is true, so it adds to the array. The second time around, you evaluate -not against a non-empty array, which returns false, which evaluates to: ($false -contains 'AnyNonEmptyString') which is false, so it doesn't add to the array.
Try breaking your conditions down to see the problem:
$IncorrectArray = #()
$x = (-not $IncorrectArray) # Returns true
Write-Host "X is $x"
$x -contains 'hello' # Returns true
then add an element to the array:
$IncorrectArray += 'hello'
$x = (-not $IncorrectArray) # Returns false
Write-Host "X is $x"
$x -contains 'hello' # Returns false
See the problem? Your current syntax does not express the logic you desire.
You can use the notcontains operator:
Clear-Host
$Words = #('Hello', 'World', 'Hello')
# This will work
$IncorrectArray = #()
ForEach ($Word in $Words)
{
If ($IncorrectArray -notcontains $Word)
{
$IncorrectArray += $Word
}
}

Resources