Loop Through Parameters until True

Hello,

I want to loop through the parameters until conditions are true. In the statement below, the $path variable needs to be a valid entry and is being checked with a function called Invoke-Task.

function Invoke-Task {
#[CmdletBinding()]
param(
[parameter(ValueFromPipeline)]
[ValidateScript({
If ((Split-Path $_ -Leaf).IndexOfAny([io.path]::GetInvalidFileNameChars()) -ge 0) {
Throw "$(Split-Path $_ -Leaf) contains invalid characters!"
} Else {$True}
})]
[string[]]$path
) #end param
} #end function Invoke-Task

function Get-UserInput {
#[CmdletBinding()]
param(
[string]$adGroup = (Read-Host -Prompt "Enter an Active Directory group"),
[string]$dirName = (Read-Host -Prompt "Enter a directory"),
[string]$fileName = (Read-Host -Prompt "Enter a file name"),
[string]$path = (Invoke-Task -path (Join-Path $dirName $fileName))
) #end param

} #end function Get-UserInput

How can I loop through the Get-UserInput function until all conditions are met?

Thanks,

Frank

You mean, keep on asking for dirname and filename until Invoke-Task passes for its join ?

if so, You can put a while loop inside the Invoke-Task function and loop through and ask dirname and filename till you get proper values. But better to come out of ValidateScript and put that as the function body with a while loop.

This is what I have so far, but nothing seems to work in order:

function Invoke-Task {

#[CmdletBinding()]

param(

[parameter(ValueFromPipeline)]

[ValidateScript({

If ((Split-Path $_ -Leaf).IndexOfAny([io.path]::GetInvalidFileNameChars()) -ge 0) {

Throw "$(Split-Path $_ -Leaf) contains invalid characters!"

 } Else {$True}

 })]

[string[]]$path

 ) #end param

} #end function Invoke-Task

function Get-UserInput {

#[CmdletBinding()]

param(

[string]$adGroup = (Read-Host -Prompt "Enter an Active Directory group"),

[string]$dirName = (Read-Host -Prompt "Enter a directory"),

[string]$fileName = (Read-Host -Prompt "Enter a file name"),

[string]$path = (Invoke-Task -path (Join-Path $dirName $fileName))

 ) #end param

} #end function Get-UserInput

get-userinput

$bool = Read-Host "Is $path correct (y/n)?"

If ($bool -eq 'N') {

Write-Host "Please enter correct path"

 } else {

Write-Host "Y"

}

The output is:

r an Active Directory group: pmtg

Enter a directory: c:\temp

Enter a file name: pmtg.csv

Is correct (y/n)?: n

Please enter correct path

PS C:\Users>

If I input ‘n’, it goes to prompt instead of asking for the correct path.

Thanks,

Frank

You may carefully (re)-read the help About Functions Advanced Parameters (including the examples). Powershell does a lot for implicitly without forcing you to script it yourself. :wink: If you make a parameter mandatory it must be provided. And there are a lot of other possible ways to get valid input from users of your function.

First thing is in order to validate the directory name in pipeline, you’ll need to have output from the original function (Get-UserInput) and then pipe it to the validation function (Invoke-Task). Since you are only verifying the directory, you’ll first need to return the $dirName.

function Get-UserInput {

#[CmdletBinding()]

param(

[string]$adGroup = (Read-Host -Prompt "Enter an Active Directory group"),

[string]$dirName = (Read-Host -Prompt "Enter a directory"),

[string]$fileName = (Read-Host -Prompt "Enter a file name"),

[string]$path = (Invoke-Task -path (Join-Path $dirName $fileName))

) #end param

return $dirName

} #end function Get-UserInput

Then you’ll need to pipe the function call to Invoke-Task for validation

function Invoke-Task {

#[CmdletBinding()]

param(

[parameter(ValueFromPipeline)]

[ValidateScript({

If ((Split-Path $_ -Leaf).IndexOfAny([io.path]::GetInvalidFileNameChars()) -ge 0) {

Throw "$(Split-Path $_ -Leaf) contains invalid characters!"

} Else {$True}

})]

[string[]]$path

) #end param

return $path

} #end function Invoke-Task

Using Get-UserInput will now return the path of the directory and in order to validate it, pipe it to Invoke-Task (which also returns a path if valid). Be sure to set that to the variable you wish to use in the output ($path),

$path = get-userinput | Invoke-Task

Finally since you want it to loop first set your value to keep the loop and then while loop it until you choose ‘y’.

$bool = 'N'

while($bool -eq 'N'){

$path = get-userinput | Invoke-Task

$bool = Read-Host "Is $path correct (y/n)?"

}

This should give you expected results.

However, I agree with Olaf and want to mention there are better ways of managing parameters. The article he mentioned would give you a better idea on how to make this code a little cleaner.

Thx, I’ll give it a try! I’ll also read the article and see if I can change anything.

You should also be aware of the limitations of scope. By default, variables assigned in a function are only available in that function, and not for the script that calls the function. For instance, you assign $fileName in Get-UserInput, but if you tried to access that variable in your script it wouldn’t be assigned. However, if you assigned that variable as $script:fileName, its value would be accessible for the script and any other functions called by the script.

Also, [string]$path shouldn’t be in your param() block because it doesn’t accept user input. By definition, a parameter is for user input. In fact, it might make more sense to remove $path from your Get-UserInput function entirely, and just assign that value in the script.