Mike Mengell
Mike Mengell

Reputation: 2398

Powershell Get Parent Folder of a File

I'm writing a script which archives files for analysis. My issue is that the file names aren't unique over multiple folders so they are being over written.

For instance:

C:\StuffToCopy\Folder1\myFile1.txt
C:\StuffToCopy\Folder1\myFile2.txt
C:\StuffToCopy\Folder2\myFile1.txt
C:\StuffToCopy\Folder2\myFile2.txt

At the end of my copy process I'm only getting 2 files, but I want 4.

I'd like the output to be like this:

C:\ArchiveCopy\Folder1_myFile1.txt
C:\ArchiveCopy\Folder1_myFile2.txt
C:\ArchiveCopy\Folder2_myFile1.txt
C:\ArchiveCopy\Folder2_myFile2.txt

Here's my script so far.

$files = dir -r -path "C:\StuffToCopy\" -i *.*

foreach ($file in $files)
{
    if ($file.LastWriteTime -gt (get-date).AddDays(-1)) {
        copy -path $file C:\ArchiveCopy\
    }
}

I want to do something like copy -path $file.FolderName & '_' & $file C:\ArchiveCopy\

I'm just not sure how to do it.

Upvotes: 18

Views: 52680

Answers (3)

nimizen
nimizen

Reputation: 3419

Based on your script, here's another way to do this:

$files = dir -r -path "C:\StuffToCopy\" -i *.*
$destPath = "c:\ArchiveCopy\"

foreach ($file in $files)
{

   $folderPath =  Split-Path $file.fullname -parent
   $folder = Split-Path $folderPath -leaf
   $destFilename = $folder + "_" + $file.name
   $destFileFullPath = $destPath + $destFilename
   write-host $destFileFullPath
    if ($file.LastWriteTime -eq (get-date).AddDays(0)) {
        copy -path $file $destFileFullPath
    }
}

Upvotes: 8

Shay Levy
Shay Levy

Reputation: 126742

Try this:

dir -r -path C:\StuffToCopy | 
        where {!$_.psiscontainer} | 
        copy -dest { "C:\ArchiveCopy\$($_.Directory.Name)_$($_.Name)"}

Upvotes: 6

Richard
Richard

Reputation: 109005

If $file is really a file – an instance of System.IO.FileInfo (and not really a directory: System.IO.DirectoryInfo) then it has property Directory which is an instance of DirectoryInfo which has a Name:

$file |
  copy-item -destination { 
     Join-Path C:\ArchiveCopy\ -childpath ($_.Directory.Name + "_" + $_.Name) }

(Using a pipeline to start because the -LiteralPath parameter of Copy-Item will bind to the PSPath property from the pipeline, so no need to pull the original file's name from the $file object.)

If $file might be a directory, then you need to do more of the work yourself, but probably easier to filter out directories first:

dir -r -path C:\StuffToCopy\ |
  where { -not $_.PSIsContainer } |
  copy-item -destination { 
     Join-Path C:\ArchiveCopy\ -childpath ($_.Directory.Name + "_" + $_.Name) }

Note:

  • No need to save all the file objects and then loop over them: let the pipeline do the looping
  • No need to -i "*.*": this is the default anyway (and if you need to filter files on a wildcard pattern prefer the -filter pattern parameter: the filter is passed to the filesystem rather than creating .NET objects and then filtering them which is much slower if there are a lot of files).

Upvotes: 16

Related Questions