Whenever I review PowerShell scripts, I usually consider loops (especially nested ones) to be a code smell.
It usually indicates to me that script is unnecessarily procedural and could benefit from being rewritten in a more functional manner.
Take this simple code snippet as an example. It searches sql files for a particular string (the poor man’s equivalent of ReSharper’s “Find Usages” in the sql world).
1: $files = (Get-ChildItem -path $rootPath -include *.sql -recurse | sort FullName);
2: foreach ($file in $files)
3: {
4: $SqlFileContents = Get-Content $file;
5: $SqlFileString = "";
6: foreach ($item in $SqlFileContents)
7: {
8: $SqlFileString = $SqlFileString + " " + $item.ToString();
9: }
10:
11: if($SqlFileString.Contains($searchText) -eq $True)
12: {
13: Write-Host "Reference found in : $file";
14: }
15: }
Now consider this revised version, which takes the more functional approach of utilizing the pipeline to carry out a series of operations on a collection of files.
1: Get-ChildItem -path $destinationPath -include *.sql -recurse | where{([string](Get-Content $_)).Contains($searchText) -eq $True} | sort FullName | select FullName;
I’m don’t use PowerShell frequently enough to feel confident that I can figure out the most elegant way to solve a problem, but the second approach seems like a huge improvement to me. It’s more concise and arguably even more readable.
So the next time you catch yourself writing loops in PowerShell (or C# for that matter), take a step back and try a more functional approach on for size.
UPDATE: Neil Barnwell reminded me in a comment about the Select-String cmdlet, which not only greatly simplifies the script but also adds the extra functionality of displaying line numbers and text excerpts in the results.
1: Get-ChildItem -path $destinationPath -filter *.sql -recurse | select-string $searchText
I feel stupid for having forgot about the cmdlet, but at the same time it was fortuitous because otherwise I probably would have had to spend a lot more time coming up with a better example to make the same point for this post…:-)
Popularity: 2% [?]