Parth Maniar
Parth Maniar

Reputation: 147

File sorting based on file content (string)

I want to build a modular script that sorts files based on content (strings/Get-Content in PowerShell).

Requirement:

  1. Defining a directory. ($directory)

    start a foreach loop: foreach

  2. list items in the directory & full path in memory

    $FilePath in Get-ChildItem $directory | Select-Object -ExpandPropert FullName
    
  3. Load content of one file at a time in the memory

    $content = Get-Content $FilePath
    
  4. Search for the keyword and copy the file once a particular keyword is found.

    if ($content -match 'keyword1') { Copy-Item $FilePath $OutputPath }
    

While I am able to do this in a static manner using the below mentioned code, I wanted to modularise it for reuse.

[string] $Directory = "parth to source directory";
[string] $outpath1  = "outpath for keyword1";
[string] $OutputPath2 = "outpath for keyword2";
[string] $OutputPath3 = "outpath for keyword3";

foreach ($FilePath = Get-ChildItem $Directory | Select-Object -ExpandProperty FullName) {
    [string] $content = Get-Content $FilePath

    if ($content -match 'keyword1') {
        Copy-Item $FilePath $OutputPath
    } elseif ($content -match 'keyword2') {
        Copy-Item $FilePath $OutputPath2
    } else {
        Copy-Item $FilePath $keyword3
    }
}

My questions:

  1. Is it possible to define keywords in a single array? If so how do that in PowerShell? (keyword1, keyword2, keyword3)
  2. Run keywords sequentially in the files and whenever one keyword is detected, the file is copied to it's designated folder. Can I have this done in modular fashion or will I have to define directory for each keyword?

The reason I am doing this is because while the script is being used for 2 or 3 keywords as of now, it will be used for over 50 keywords and allowing reuse should help.

Upvotes: 1

Views: 257

Answers (1)

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200233

What you describe could be achieved with a hashtable and a nested loop:

$outpath = @{
    'keyword1' = 'outpath for keyword1'
    'keyword2' = 'outpath for keyword2'
    'keyword3' = 'outpath for keyword3'
}

foreach ($FilePath in Get-ChildItem $Directory | Select-Object -Expand FullName) {
    $content = Get-Content $FilePath

    foreach ($keyword in $outpath.Keys) {
        if ($content -match $keyword) {
            Copy-Item $FilePath $outpath[$keyword]
            break
        }
    }
}

Alternatively you could use a switch statement:

$outpath = @{
    'keyword1' = 'outpath for keyword1'
    'keyword2' = 'outpath for keyword2'
    'keyword3' = 'outpath for keyword3'
}

$pattern = ($outpath.Keys | ForEach-Object { [regex]::Escape($_) }) -join '|'

foreach ($FilePath in Get-ChildItem $Directory | Select-Object -Expand FullName) {
    $content = Get-Content $FilePath

    switch -regex ($content) {
        $pattern {
            Copy-Item $FilePath $outpath[$keyword]
            break
        }
    }
}

The latter would also give you a simple way of specifying a fallback destination path if you also want to handle files with no matching keyword.

$fallbackpath = '...'

foreach ($FilePath in Get-ChildItem $Directory | Select-Object -Expand FullName) {
    $content = Get-Content $FilePath

    switch -regex ($content) {
        $pattern {
            Copy-Item $FilePath $outpath[$keyword]
            break
        }
        default {
            Copy-Item $FilePath $fallbackpath
            break
        }
    }
}

Upvotes: 2

Related Questions