Mu;tiple selection search in files

I would like to change this code to be able to search files in a folder on multiple strings. I would like to have 3 parms for the EU to select for the search. Then once it finds matches on any one of the 3 lookups copy the file found to a archive folder.

Get-ChildItem -Path "C:\ftp_in\archive" -Filter "*.bak" -recurse |
Select-String -pattern “CS21021663” | Select-Object -Property Path,LineNumber,Line |
Export-CSV “C:\ftp_in\archive\ResultFile.csv”

I’m actually unsure what’s the actual question is. If you want to look for different strings you could use another search pattern. You may elaborate a little more detailed what you’re looking for. Can you share some examples?

Regardless of that: … when you post code, error messages, sample data or console output format it as code, please.

Here you can read how that works: Guide to Posting Code.

Thanks in advance

I’m looking to first prompt the user for 3 parms, The 1st would be ordernbr,date(yymmdd-format) and ordertype. THen I want to use whichever parm(s) where supplied to search .bak for those
supplied strings. If found in a file then copy that file to an archive directory. The search files have no delimiters to parse the records.

I usually consider it risky to prompt user for “free text” input. Will this be “regular users” or “helpdesk people” or “admin colleagues”? How should they input these information?

Will these search patterns always accor in the same order in the same line? It might be an option to read the files as -Raw and search for the patterns with a multiline regex.

2 Likes

The users of the prompts(very limited) will understand parm values and the search will also occur on the first line of lines.
Thanks.

So you may create a function with 3 mandatory parameters. It will prompt for values if they are not provided right away. And it may be faster to use Get-Content with the paramter -TotalCount 1 to limit the amount of data to process.

Thats where I stuck not sure how to code that.
Thx,

Did you read the help?

1 Like

okay will look thru

Thx…

okay I found this as my parms:
param (
[parameter(mandatory = $true, ValueFromPipelineByPropertyName = $true)][AllowEmptyString()][string]$Sender,
[parameter(mandatory = $true, ValueFromPipelineByPropertyName = $true)][AllowEmptyString()][string]$FileDate,
[parameter(mandatory = $true, ValueFromPipelineByPropertyName = $true)][AllowEmptyString()][string]$RecordType
)
Now how do I use that in my lookup multi lookup
Thx.

Well … it depends. :wink: I asked you in my first reply if you can show some examples. How would a log file look like? (at least the first line as you said that the text you’re looking for will occur there) And what exactly are you looking for? Please don’t describe it - show it.

And please - when you post code format it as code. Thanks.

1 Like

sample data row:
MRK 00 00 01 RBCMARATHONP 12 XXX4000 200325 2116 U 00401 000410414 0 SH

I highlited the 3 rows to be searched they are in col 36,71,104 which parms will be used. User could one, two or all 3 of parms so script needs to be flexible.
Thx.

The reliability of the results depends on the input of your users.

Let’s assume they provided all three values correctly. So you have all three variables filled in.

$Sender, $FileDate, $RecordType = 'RBCMARATHONP', '200325', 'SH'

You use this to build your regex pattern … maybe like this:

$Pattern = '({0}).*({1}).*({2})' -f $Sender, $FileDate, $RecordType

And now you use the -match operator to test the first line of the file for a match like this:

'MRK 00 00 01 RBCMARATHONP 12 XXX4000 200325 2116 U 00401 000410414 0 SH' -match $Pattern 

This returns $true if all three partial strings are found.

It still works when you provide an empty string on one or two variables but the chances to get a false positive rise.

A N D … you should take care of the case when all three variables are empty. Then the pattern matches ANY string and therefor EVERY file. :wink:

1 Like

I can code for no parms, but how do you put all of the pieces to script together.

Check for at least one parameter selected

if ($Sender -eq “” -and $FileDate -eq “” -and $RecordType -eq “”) {
Write-Host -ForegroundColor Yellow “At least one parameter must be selected. Please try again.”;
Exit;
}

Not me … you do it! :wink: Start with one piece and if that works, add the next piece. If both pieces work together, add the next piece. And so on. That’s how we all do it.

And please: format your code as code. It’s really not that hard. Simply click on that </> symbol on the edit bar and paste your code between the format tags.

2 Likes

Disclaimer

The PowerShell code in this educational post is a framework intended only for the demonstration of PowerShell functionalities. The creator does not consider this work to be of production quality.

@andyh - A function’s metadata and parameter attributes can provide much of the feedback you indicated. The following example is only a starting point for your exploration into PowerShell’s built-in capabilities. As @Olaf states, building understanding and skills in PowerShell is an iterative process --and, there should be much reading. However, long ago, someone gave me a programmatic scaffold on which I could develop.

Example

search files in a folder on multiple strings… (OP)
matches on any one of the 3 lookups copy the file found to a archive folder… (OP)

Remarks

  • Uses Move-Item due to the archival nature in the process (replaces Copy-Item).
  • return safely exits the function, but does not close the PowerShell session (replaces Exit).
    • The function completes as soon as a match is made.
  • Parameter validation provides detailed information to the user (replaces Write-Host or Write-Warning).
  • Optional parameters are provided for source and target directories. Their pattern validation allows for child directories, but not files (-ish. I’m pretty sure this regex could be cheated).
  • The keyword search is not finely tuned. The match is more literal, but unexpected results will occur.
    • Follow @Olaf’s suggestions. The use of the Keywords array can be expanded on prior to the search.
<#
.Synopsis
   Move a file when a keyword is found in the contents.
.DESCRIPTION
   This function moves a file to a new location when at least one of three keywords is found within the file contents.
.EXAMPLE
   Move-FileToArchive -Keywords "Alice","210328" -SourcePath "A:\SourceDirectory" -TargetPath "A:\TargetDirectory";
.EXAMPLE
   Move-FileToArchive -Keywords "Alice";
.EXAMPLE
   Move-FileToArchive -Keywords "Alice","210328","Bob";
.INPUTS
   Keywords (an array of 1 to 3 members)
   Searched file directory (SourcePath)
   Destination file directory (TargetPath)
.NOTES
   File is moved is any one keyword is found in the content.
   Use Filedate format yymmdd in datetime searches.
#>
function Move-FileToArchive
{
    [CmdletBinding(PositionalBinding=$true,
        HelpUri = "Keywords should include: Sender, FileDate, or RecordType",
        ConfirmImpact='low')]
    Param
    (
        [Parameter(Mandatory=$true,Position=0)]
        [ValidateCount(1,3)]
        [array]$Keywords,
        
        [Parameter(Mandatory=$false,Position=1)]
        [ValidatePattern("^(?:[\w]\:|\\)(\\[a-z_\-\s0-9\.]+)+$")]
        [string]$SourcePath,

        [Parameter(Mandatory=$false,Position=2)]
        [ValidatePattern("^(?:[\w]\:|\\)(\\[a-z_\-\s0-9\.]+)+$")]
        [string]$TargetPath
    )
    Begin
    {
        if([string]::IsNullOrWhiteSpace($SourcePath)){$SourcePath = "A:\Backups"}
        if([string]::IsNullOrWhiteSpace($TargetPath)){$TargetPath = "A:\Backups\TargetArchive"}
    }
    Process
    {
        foreach($file in Get-ChildItem -Path $SourcePath -Filter "*.bak")
        {
            [string]$searchFile = "{0}\{1}"-f $SourcePath,$file.Name;
            [string]$content = Get-Content -Path $searchFile;

            foreach($term in $Keywords)
            {
                if($content -match $term)
                {
                    return Move-Item -Path $searchFile -Destination $TargetPath;
                }
            }           
        }
    }
}

Thanks for the template to start building from…

1 Like

I tested on a directory with a few files, and it didn’t find any files matching my search…

It’s hard to help troubleshoot if you don’t provide your code.

I ran the code Dicey provided just to see functionality and check performance…