Home > Software design >  Nesting ForEach within If statement (PowerShell)
Nesting ForEach within If statement (PowerShell)

Time:10-06

I am trying to loop through a list of Windows services and if any of them match a certain criteria, I would like to return exit code 1.

If there is no match, I would like to return exit code 0.

I am struggling to put this within an If statement, I think I'm putting the code in the wrong place!

Could anyone lend me a hand? Script below.

Thanks in advance.

Adrian

try
{   
    #Pull list of services from registry
$svclist = Get-ChildItem HKLM:\SYSTEM\CurrentControlSet\services | ForEach-Object {Get-ItemProperty $_.PsPath}
#Ignore anything after .exe, filter for vulnerable services
ForEach ($svc in $svclist) {
    $svcpath = $svc.ImagePath -split ".exe"
    if(($svcpath[0] -like "* *") -and ($svcpath[0] -notlike '"*') -and ($svcpath[0] -notlike "\*")) {
        $svc | fl -Property DisplayName,ImagePath,PsPath
    }
}
    if (($svc -ne $null)){
        Write-Host "Match"
        Return $svc.count
        exit 1
    }
    else{
        Write-Host "No_Match"
        exit 0
    }    
}
catch{
    $errMsg = $_.Exception.Message
    Write-Error $errMsg
    exit 1
}

CodePudding user response:

You can either return early or use a variable with a single [bool] value to keep track of whether anything was matched:

return early

foreach($svc in $svcList)
{
    $svcpath = $svc.ImagePath -split ".exe"
    if(($svcpath[0] -like "* *") -and ($svcpath[0] -notlike '"*') -and ($svcpath[0] -notlike "\*")) {
        return 1
    }
}

# if we've reached this point then no matches occurred
return 0

Using a [bool]

$matchFound = $false

foreach($svc in $svcList)
{
    $svcpath = $svc.ImagePath -split ".exe"
    if(($svcpath[0] -like "* *") -and ($svcpath[0] -notlike '"*') -and ($svcpath[0] -notlike "\*")) {
        $matchFound = $true
    }
}

return [int]$matchFound  # $false = 0, $true = 1

CodePudding user response:

I always try to use the most powershell-correct methods to achieve what I want. Especially when going through data I prefer to try filtering with the x-object cmdlets.

In your case my suggestion would be to simply loop over the original list with the Where-Object command, this allows you to retrieve a list of items that conform to your search, kind of like an SQL query:

$resultList = $svclist | Where-Object {
    ($_.ImagePath -like "* *") -and ($_.ImagePath -notlike '"*') -and ($_.ImagePath -notlike "\*")
}

In this case I skipped over the -split ".exe" part, as I didn't quite understand it's purpose, but you could also put that in your filter using regular expressions with the -match operator instead of the -like and -notlike values you make one regex match

Then you can check if that list is populated or not:

if ($resultList) {
    return 1
}
else {
    return 0
}

It is also considered best practice to only use the aliases for commands (e.g. fl should be Format-List). This will increase readability for future maintenance, of course if it's a one-time script is would be more appropriate. I just try to avoid it as much as I can these days.

  • Related