Tom Chickory
Tom Chickory

Reputation: 25

Powershell search directory for code files with text matching input a txt file

Data mapping project, in house system to new vendor system. First step is find all the occurrences of current database field names (or column names to be precise) in the C# .cs source files. Trying to use Powershell. Have recently created PS searches with Get-ChildItem and Select-String that work well but the search string array was small and easily hard coded inline. But the application being ported has a couple hundred column names and significant amounts of code. So armed with a text file of all the column names Pipleline would seem like a god tool to create a the basic cross ref for further analysis. However, I was not able to get the Pipeline to work with an external variable anyplace other than first step. Trying using -PipelineVariable, $_. and global variable. Did not find anything specific after lots of searching. P.S. This is my first question to StackoOverflow, be kind please.

Here is what I hoped would work but do dice so far.

$inputFile = "C:\DataColumnsNames.txt"
$outputFile = "C:\DataColumnsUsages.txt"
$arr = [string[]](Get-Content $inputfile)
foreach ($s in $arr) {
  Get-ChildItem -Path "C:ProjectFolder\*"  -Filter *.cs  -Recurse -ErrorAction SilentlyContinue -Force |
  Select-String $s | Select-Object  Path, LineNumber, line | Export-csv $outputfile
}

Did find that this will print the list one time but not twice. In fact it seems using the variable in this way results in processing simply skipping any further pipeline steps.

foreach ($s in $arr) {Write-Host $s | Write $s}

If it isn't possible to do this in Powershell easily my fallback is to do with C# although would much rather get the level up with PowerShell if anyone can point me to the correct understanding of how to do things in the Pipepline, or alternatively construct an equivalent function. Seems like such a natural fit for Powershell.

Thanks.

Upvotes: 1

Views: 244

Answers (2)

mklement0
mklement0

Reputation: 438378

You're calling Export-csv $outputfile in a loop, which rewrites the whole file in every iteration, so that only the last iteration's output will end up in the file.

While you could use -Append to iteratively append to the output file, it is worth aking a step back: Select-String can accept an array of patterns, causing a line that matches any of them to be considered a match.

Therefore, your code can be simplified as follows:

$inputFile = 'C:\DataColumnsNames.txt'
$outputFile = 'C:\DataColumnsUsages.txt'

Get-ChildItem C:\ProjectFolder -Filter *.cs -Recurse -Force -ea SilentlyContinue |
  Select-String -Pattern (Get-Content $inputFile) | 
    Select-Object Path, LineNumber, line | 
      Export-csv $outputfile

-Pattern (Get-Content $inputFile) passes the lines of input file $inputFile as an array of patterns to match.

By default, these lines are interpreted as regexes (regular expressions); to ensure that they're treated as literals, add -SimpleMatch to the Select-String call.


This answer to a follow-up question shows how to include the specific pattern among the multiple ones passed to -Pattern that matched on each line in the output.

Upvotes: 0

wasif
wasif

Reputation: 15488

I think you want to append each occurrence to the csv file. And you need to get the content of the file. Try this:

$inputFile = "C:\DataColumnsNames.txt"
$outputFile = "C:\DataColumnsUsages.txt"
$arr [string[]](Get-Content $inputfile)
foreach ($s in $arr) {
    Get-ChildItem -Path "C:ProjectFolder\*"  -Filter *.cs  -Recurse -ErrorAction SilentlyContinue -Force | Foreach {
    Get-Content "$_.Fullname" | Select-String $s | Select-Object  Path, LineNumber, line | Export-csv -Append -Path "$outputfile"
  }
}

-Append was not introduced before powershell v3.0 (Windows 8) then try this:

$inputFile = "C:\DataColumnsNames.txt"
$outputFile = "C:\DataColumnsUsages.txt"
$arr [string[]](Get-Content $inputfile)
foreach ($s in $arr) {
    Get-ChildItem -Path "C:ProjectFolder\*"  -Filter *.cs  -Recurse -ErrorAction SilentlyContinue -Force | Foreach {
    Get-Content "$_.Fullname" | Select-String $s | Select-Object  Path, LineNumber, line | ConvertTo-CSV -NoTypeInformation | Select-Object -Skip 1 | Out-File -Append -Path "$outputfile"
  }
}

Upvotes: 0

Related Questions