Martyn Jeffrey
Martyn Jeffrey

Reputation: 11

Putting a for each loop inside a foreach loop

I have the need to search all servers in our domain for specific folders, I already have a script here

function Find-ComputersWithFolder {
    # Get all computers in the Active Directory domain
    $computers = Get-ADComputer -Filter {name -like 'servernamehere' }

    # Initialize an empty array to store the result
    $result = @()
 
    # Iterate through each computer
    foreach ($computer in $computers) {
        $computerName = $computer.Name
 
        # Check if the folder C:\ASNEXT exists on the computer
        $folderExists = Test-Path "\\$computerName\C$\Windows\WinSxS\foldernamehere"
 
        # If the folder exists, add the computer name to the result list
        if ($folderExists) {
            $result += $computerName
        }
    }
 
    # Return the result array
    return $result
}
 
# Usage example for the Find-ComputersWithFolder function
 
# Find all computers with the folder
$computersWithFolder = Find-ComputersWithFolder
 
# Output the result
Write-Output "Computers with folder"
$computersWithFolder

what this does is searches all servers in the domain and looks for the folder that is specified in the line

$folderExists = Test-Path "\\$computerName\C$\Windows\WinSxS\foldernamehere"

However i have a long list of folders i would like to supply to this script so that it went through them instead of me having to manually specify the folder on the specific line

$folderExists = Test-Path "\\$computerName\C$\Windows\WinSxS\foldernamehere"

I tried the following amendment to the script, i put all the folder names in a text file and created a variable $Paths to which i used the get-content.

$paths = get-content C:\scripts\paths.txt

This works in that it fills the variable with the list of folders but when i change the line that actually searches to this

$folderExists = Test-Path "\\$computerName\C$\Windows\WinSxS\$paths"

I dont get any output, I suspect its is something to do with having to somehow get it to do a for-each through the list but i dont know how to get to that point.

Any help would be much appreciated

Upvotes: 0

Views: 236

Answers (2)

Martyn Jeffrey
Martyn Jeffrey

Reputation: 11

I managed to get it with

function Search-ComputersForFolders {
    param (
        [Parameter(Mandatory=$true)]
        [string]$FilePath
    )

    # Read the folder names from the text file
    $folderNames = Get-Content C:\scripts\paths.txt

    # Get all computers in the network
    $computers = Get-ADComputer -Filter {name -like 'servernames'} | Select-Object -ExpandProperty Name

    # Initialize an empty array to store the found folders
    $foundFolders = @()

    # Loop through each computer and search for the folders
    foreach ($computer in $computers) {
        # Construct the UNC path to the computer's C drive
        $uncPath = "\\$computer\C$"

        # Check if the UNC path is accessible
        if (Test-Path -Path $uncPath) {
            # Loop through each folder name and search for it
            foreach ($folderName in $folderNames) {
                # Construct the full path to the folder
                $folderPath = Join-Path -Path $uncPath -ChildPath $folderName

                # Check if the folder exists
                if (Test-Path -Path $folderPath -PathType Container) {
                    # Add the found folder to the array
                    $foundFolders += Get-Item -Path $folderPath
                }
            }
        }
    }
     
    # Output the found folders
    return $foundFolders
}
    
# Usage example for the Search-ComputersForFolders.ps1 script
    
# Example: Search for folders on all computers in the network
# ----------------------------------------------------------------------------
$folderFilePath = "C:\scripts\paths.txt"
$foundFolders = Search-ComputersForFolders -FilePath $folderFilePath
    
# Output the found folders
foreach ($folder in $foundFolders) {
    Write-Output "Found folder: $($folder.FullName)"
}

Upvotes: 0

Santiago Squarzon
Santiago Squarzon

Reputation: 60848

"I suspect its is something to do with having to somehow get it to do a for-each through the list..."

This is correct, you're missing an inner loop to test each path in $paths for each computer in $computers, however, what I would recommend you to do is to remove complexity from your function, the query for Active Directory computers should be outside of your function, then you can leverage the pipeline by taking ValueFromPipelineByPropertyName:

function Test-NetworkPath {
    param(
        [Parameter(ValueFromPipelineByPropertyName, Mandatory)]
        [Alias('Name')]
        [string] $ComputerName,

        [Parameter(Mandatory, Position = 0)]
        [string[]] $Path
    )

    process {
        foreach ($p in $Path) {
            $pathToTest = '\\{0}\C$\Windows\WinSxS\{1}' -f $ComputerName, $p
            if (Test-Path $pathToTest) {
                $pathToTest
            }
        }
    }
}

$paths = Get-Content C:\scripts\paths.txt
Get-ADComputer -Filter "name -like 'servernamehere'" |
    Test-NetworkPath -Path $paths

In this example the .Name property from each ADComputer object is bound thru the pipeline to the $ComputerName parameter.

Upvotes: 1

Related Questions