Find string, exclude folder; list results

Hello,

I have this working script:

$AllDCs = Get-Content .\AllDCs.txt
foreach($DC in $AllDCs){
Get-ChildItem -Path E:\, C:\ -Include *.ps1, *.xml, *.bat -Recurse -Name -Exclude E:\Scripts\IGNORE | Select-String -Pattern SomeFileName
}

…but my output doesn’t tell me which DC the result(s) was found. How can I modify the script to show that, please?

That’s because the DCs are just references you’re using FOR the foreach loop, and not actually IN the foreach loop.

You’ll need to assign the output of Get-ChildItem to a variable, then create a [pscustomobject] to include the DC as a property.

This example will output the DC name but the files output is probably not what you want:

foreach ($DC in $AllDCs) {

    $files = Get-ChildItem ...

    [pscustomobject]@{
        DC = $DC
        Files = $files
    }
}

To show DC names for each file, you’ll need to loop through all files as well, and then create a `[pscustomobject]`:

foreach ($DC in $AllDCs) {

    $files = Get-ChildItem ...

    foreach ($file in $files) {

        [pscustomobject]@{
           DC = $DC
           FilePath = $file.FullName
           # other properties
        }
    }
}

I forgot to throw this in:

If you want to group by DC, you can pipe the top foreach to Format-Table which will output things nicely in the console (if you don’t need a CSV):

$results = foreach ($DC in $DCs) { ... }

$results | Format-Table -GroupBy DC

What is DC here ? Where are you using $DC here ?

Aaron,

I tried your suggestion:

$AllDCs = Get-Content .\AllDCs.txt

 foreach ($DC in $DCs) {

    $files = Get-ChildItem -Path E:\, C:\ -Include *.ps1, *.xml, *.bat -Recurse -Name -Exclude E:\Scripts\IGNORE | Select-String -Pattern SomeFileName1

    foreach ($file in $files) {

        [pscustomobject]@{
           DC = $DC
           FilePath = $file.FullName
           # other properties
        }
    }
}

…but no output and no error.

Sorry Jeff, a little quick on the draw. Instead of foreach ($DC in $DCs), it should have been foreach ($DC in $AllDCs) as per your code. I’ve updated that post. Give it a shot.

Aaron,

It runs without error and simply outputs the Name of the DC and no values under Filepath. I tested it with a keyword (TestUser@myCompany.com) for which I know exists in a .ps1 file but the Get-ChildItem isn’t finding it.

Here’s my revised script:

 $AllDCs = Get-Content .\AllDCs.txt
 foreach ($DC in $AllDCs) {

    $files = Get-ChildItem -Path E:\ -Include *.ps1, *.xml, *.bat -Recurse | Select-String -Pattern TestUser@myCompany.com

    foreach ($file in $files) {

        [pscustomobject]@{
           DC = $DC
           FilePath = $file.FullName
        }
    }
}

Thanks Jeff, I realized more needed to be addressed here and I spaced on the pscustomobject.

If you use the -Include parameter, you do need an asterisk (*) at the end of -Path E:</code>, otherwise you’ll get nothing back. So, here is what should work:

foreach ($DC in $AllDCs) {

    $files = Get-ChildItem -Path E:\* -Include *.ps1, *.xml, *.bat -Recurse | Select-String -Pattern somePattern

    foreach ($file in $files) {

        [pscustomobject]@{
            DC       = $DC
            FilePath = $file.Path
        }
    }
}

Now, keep in mind that though this code would work for what it is, the reference to DCs is irrelevant. The code is just looping through DCs in a text file (assumingly Domain Controller names), and for each one found in the file, it outputs the DC name with a file path found against some pattern you specify.

If 150 files are found matching the pattern, those results will output for each DC in the text file. This means if you have 10 DCs in the text file, the output will render 1500 results, almost all of which are redundant.

Are you intending to run this against domain controller found in the .txt file? What is your plan for this script?

ah, I had no idea about the * in the -Include, so thank you.

They are indeed DC’s and I’m looking for that one script (either .ps1 or .xml) that has a username, generating lockouts etc. So wouldn’t expect it to be on all DCs but rather, one.

There is a glaring issue in the code as posted. You are not initiating a remote session to the DCs nor are you defining a UNC with the -LiteralPath parameter. As it appears now, its going to list the DCs and invoke GCI against your local E:\ for reach DC in AllDCs.

 

[pre]

Get-ChildItem -LiteralPath "\$dc\E$" -Include *.ps1, *.xml, *.bat -Recurse | Select-String -Pattern TestUser@myCompany.com

[/pre]

Another note, Select-String is using Regex, and “.” in Regex is wildcard. You will want to escape that with a "" example “TestUser@mycompany.com”

 

You are not initiating a remote session to the DCs nor are you defining a UNC

I think I was ok with that. Just run it locally.

You will want to escape that with a "\" example "TestUser@mycompany\.com"

I will try that too thanks. I’m getting the results at least now, associated with the DC and FilePath output. The “*” helped.

“I think I was ok with that. Just run it locally.”

I admit I am a little confused by your response, forgive me. If you intend to run the script locally, then what is the ForEach loop doing?

I don’t quite understand what the goal is just by looking the “working” script in the first post.

but, could this be the thing you are trying to achieve

[pre]

$computers = get-content “c:\temp\AllDCs.txt”

$scriptBlock = {
$paths = “C:\temp”,“C:\users”
$excludePath = “C:\users*\PS\functions”

Get-ChildItem -Path $paths -Include *.ps1, *.xml, *.bat -Recurse -ErrorAction SilentlyContinue |
where {$.DirectoryName -notlike $excludePath} |
Select-String computer |
Group-Object path |
select @{N=‘host’;E={$env:COMPUTERNAME}}, @{N=‘FullName’;E={$
.name}}

}

invoke-command -ComputerName $computers -ScriptBlock $scriptBlock

[/pre]

This worked very well. I just:

~added “*” to the end of those paths (i.e. “C:\users*”)
~ added -ErrorAction SilentlyContinue at the end of the Invoke-command, to ignore the access denied warnings to some folders

I also learned a lot from this, so thank you Aapeli.