0
votes

I need to read a file (e.g. file.txt) which has file names as its content. File names are separated by unique character (e.g. '@'). So my file.txt looks something like:

ABC.txt@
CDE.csv@
XYZ.txt@

I need to read its content line by line based on its extension. I have 1 source folder and 1 destination folder. Below is my scenario that I need to achieve:

If extension = txt then 
    check if that file name exists in destination_folder1 or destination_folder2
        if that file exists then
            copy that file from source_folder1 to destination_folder1
        else delete that file from destination_folder1
Else display msg as "Invalid file"

I am new to powershell scripting. can someone pls help? Thanks in advance.

1
Adding your effort,even though it may be wrong,might get upvotes on this questionTheGameiswar
Get-ChildItem C:\somepath | %{ if($_.Extension -eq ""){ ## test-path ##copy } else { ##do something } } some skeleton codeTheGameiswar
It's fine to be new, but that means you need to get up to speed. Youtube is your friend. Beginning PowerShell and PowerShell file and folder management All of what you are after is in the PowerShell Help files and help file examples. Get-ChildItem, and Move-Item and conditional matching. YOu have your pseudo-code, work thru it one step at a time.postanote

1 Answers

0
votes

It will make my job easier if we assume the following pseudocode. Then you can take the elements I demonstrate and change them to fit your needs.

  1. If the string from "file.txt" contains the file extension "txt" then continue.
  2. If the file does not exist in the destination folder then copy the file from the source folder to the destination folder.

Use Get-Content to read a text file.

Get-Content .\file.txt 

Get-Content processes files line by line. This has a few consequences:

  • Each line in our input text file will trigger our code.
  • Each time our code triggers, it will have input that looks like this: ABC.txt@
  • We can focus on solving the problem for one line.

If we need to evaluate strings, I suggest using regular expressions.

Remember, we are operating on a single line from the text file:

ABC.txt@

We need to detect the file extension.

A good place to start would be the end of the string.

In regular expressions, the end of a string is represented by $

So let's start there.

Here is our regular expression so far:

$

The next thing that would be useful is if we accounted for that @ symbol. We can do that by adding it before $

@$

If there was a different character, we would add that instead: ;$ Keep in mind that there are reserved characters in regular expressions. So we might need to escape certain characters with a backslash: \$$


Now we have to account for the file extension.

We have three letters, we don't know what they are.

Regular expressions have a special escape sequence (called a character class) that can match any letter: \w

Let's add three of those.

\w\w\w@$

Now, while crafting regular expressions, it is a good idea to limit the text we're looking for.

As humans, we know we're looking for .txt@ But, so far, the computer only knows about txt@ with no dot. So it would accept .txt@, .xlsx@, and anythingGoes@ as matches. We limited the right side of our string. Now let's limit the left side.

We're only interested in three characters. And the left side is bounded by a . So let's add that to our regular expression. I'll also mention that a period is a reserved character in regular expressions. So, we will have to escape it.

\.\w\w\w@$

So if we're looking at text like this

ABC.txt@

then our regular expression will output text like this

.txt@

Now, .txt@ is a pretty good result. But we can make our job a little easier by limiting the result to just the file extension.

There are several ways of doing this. But I suggest using regular expression groups.

We create a group by surrounding our target with parentheses.

\.(\w\w\w)@$

This now produces output like:

txt

From here, we can just make intuitive comparisons like if txt = txt.


Another piece of the puzzle is testing whether a file already exists. For this we can use the Test-Path and Join-Path cmdlets.

$destination = ".\destination 01" 

$exampleFile = "ABC.txt"

$destinationFilePath = Join-Path -Path $destination -ChildPath $exampleFile

Test-Path -Path $destinationFilePath


With these concepts, it is possible to write a working example.

# Folder locations. 
$source = ".\source"
$destination = ".\destination 01" 

# Load input file. 
Get-Content .\file.txt | 
  Where-Object {
    # Enter our regular expression. 
    # I've added an extra group to capture the file name. 
    # The $matches automatic variable is created when the -match comparison operator is used. 
    if ($_ -match '([\w ]+\.(\w\w\w))@$')
    {
        # Which file extensions are we interested in processing? 
        # Here $matches[2] represents the file extension: ex "txt". 
        # We use a switch statement to handle each type of file extension. 
        # Accept new file types by creating new switch cases. 
        switch ($matches[2])
        {
          "txt"   {$true; Break}
         #"csv"   {$true; Break}
         #"pdf"   {$true; Break}
          default {$false}
        }
    }
    else { $false }
  } | 
  ForEach-Object {
    # Here $matches[1] is the file name captured from the input file. 
    $sourceFilePath      = Join-Path -Path $source      -ChildPath $matches[1]
    $destinationFilePath = Join-Path -Path $destination -ChildPath $matches[1]
    $fileExists          = Test-Path -Path $destinationFilePath

    # Copy the source file to the destination if the destination doesn't exist. 
    if (!$fileExists)
    {  Copy-Item -Path $sourceFilePath -Destination $destinationFilePath  } 
  }


Note on Copy-Item

Copy-Item has known issues.

You can substitute robocopy which is more reliable.

The robocopy syntax is:

robocopy <source> <destination> [<file>[ ...]] [<options>]

where <source> and <destination> can be folders only.

So, if you want to copy a file, you have to write it like this:

robocopy .\source ".\destination 01" ABC.txt 

We can invoke robocopy using Start-Process and the variables we already have.

    # Copy the source file to the destination if the destination doesn't exist. 
    if (!$fileExists)
    {  
      Start-Process -FilePath "robocopy.exe" -ArgumentList "`"$source`" `"$destination`" `"$($matches[1])`" /unilog+:.\robolog.txt" -WorkingDirectory (Get-Location) -NoNewWindow 
    } 

Using Get-ChildItem

You use file.txt as input. If you wanted to gather a list of files on disc, you can use Get-ChildItem.


Multiple Conditions

You wrote "destination_folder1 or destination_folder2". If you need multiple conditions you can construct this with three things.

Use the if statement. Inside the test condition, you can add multiple conditions with logical -or And you can group statements together to make them easier to read.


Functions

If you need to move a piece of code around, you can use a function. Just remember to create parameters for the inputs to the function. Then call a PowerShell function without parentheses or commas:

# Calling a PowerShell function. 
myFunction parameterOne parameterTwo parameterThree 

Writing Output

You can use Write-Output to send text to the console.

Write-Output "Invalid File" 

Further Reading

Here are some references which you might find useful.