Active Directory,  Microsoft Exchange Server,  Windows Server

Grep, Search, Loops and Basename for Powershell Hotness

Simple request: Search for all files in a directory and the child directories for a specific pattern and then return the filename without the path to the file. There are a few commandlets we end up needing to use:

  • Get-ChildItem: Creates a recursive array of filenames and pipes that output into the For loop.
  • ForEach-Object: Starts a for loop, looping through the output of the command that has been piped into the loop (much easier than an IFS array IMHO).
  • If: This starts the if pattern that ends after the select-string in the below command, but only dumps the $_.PSPath if the pattern is true.
  • Select-String: Searches for the content in the file.
  • Split-Path: This is the Powershell equivalent of basename and dirname. You can use this commandlet to extract parts of the path to a file. In this case, we’ll use the -Leaf option which effectively runs the basename, or just the file name in the path to a file.

Get-ChildItem -include * -recurse | ForEach-Object { if( ( $(Get-Content $_) | select-string -pattern "Finished processing mailbox") ) { $_.PSPath }} | Split-Path -Leaf

You can also search for the files that specifically don’t have that given pattern included in them instead by adding a ! in front of the Get-Content:

Get-ChildItem -include * -recurse | ForEach-Object { if( !( $(Get-Content $_) | select-string -pattern "Finished processing mailbox") ) { $_.PSPath }} | Split-Path -Leaf

Note: This runs recursively from the existing working directory (and yes, you can use pwd to return a path, just like the bash built-in).

Finally, the > operator can then be placed into the end to dump our data to a file:

Get-ChildItem -include * -recurse | ForEach-Object { if( !( $(Get-Content $_) | select-string -pattern "Finished processing mailbox") ) { $_.PSPath }} | Split-Path -Leaf > Complete.txt