Appending text to the beginning of a variable file name

I have a process in place where various departments drop images into shared folders.

We then use scripts to copy/move the files from these drop boxes into a backup folder and finally into a folder that a program utilizes to import the images from, into a larger application.

The images are all named with a seemingly random series of letters and numbers.

I need to append a department name to the beginning of each of these files in the process of moving them.

So I have these directories: $source, $destination, & $bkp

in $source the file name maybe 0147258369.jpg BUT it should end up in the $destination and $Bkp directories as Marketing–0147258369.jpg

I’ve been working with the following code but it doesn’t seem to be working:

$Source = "c:\test1"
$Destination = "c:\test2"
$Bkp = "c:\test3"
$Time = GET-DATE
$DateTime = Get-Date -format g

if(test-path -path $bkp)
 {
  if(Test-Path -Path $Source\* -include *.pdf, *.tif, *.jpg)
   {
    Add-Content -Path $Source\copy.log -value "**********BEGIN ACTION @ $time**********"
    Copy-Item -path $Source\* -include *.pdf,*.tif,*.jpg -destination "$Bkp\DepartmentName-$($_.Name)" -passthru | format-table -property LastWriteTime,Name -autosize | out-file $Source\copy.log -Append -Encoding ascii
    Move-Item -path $Source\*.pdf -destination "$Destination\DepartmentName-$($_.Name)"
    Move-Item -path $Source\*.tif -destination "$Destination\DepartmentName-$($_.Name)"
    Move-Item -path $Source\*.jpg -destination "$Destination\DepartmentName-$($_.Name)"
    Add-Content -Path $Source\copy.log -value "**********STOP ACTION @ $time**********`r`n================================================`r`n"
    Copy-Item $Source\copy.log $Bkp\copy.log
   }
    ELSE
   {
    Add-Content -Path $Source\copy.log -value "**********BEGIN ACTION @ $time*********`r`n`r`n0 Files Copied`r`n`r`n**********STOP ACTION @ $time**********`r`n================================================`r`n"
   }
   
 }

The code also includes logging.

I’m not sure what I am doing wrong. I am afraid to depend on a rename-item action because the import from the $destination is on a 60 second interval and RNI might not change the file name before the system tries to grab it.

 

I think have some confusion about how some things in the pipeline work. You can’t use $_ except in specific places where the shell is expecting it - and Move-Item isn’t one of those places. Move-Item can’t be used to rename files in a batch like you’re trying; you need to work with them one at a time.

Get-ChildItem -Path $Source -include *.pdf,*.tif,*.jpg |

ForEach-Object {

$_ | Move-Item -Destination "$Destination\$Department-$($_.Name)"

}

Might be closer, I think, if I’m following what you’re after. Which I might not be.

The following works, but does not modify the name of the files at all.

$Source = "c:\test1"
$Destination = "c:\test2"
$Bkp = "c:\test3"
$Time = GET-DATE
$DateTime = Get-Date -format g

if(test-path -path $bkp)
	{
		if(Test-Path -Path $Source\* -include *.pdf, *.tif, *.jpg)
			{
				Add-Content -Path $Source\copy.log -value "**********BEGIN ACTION @ $time**********"
				Copy-Item -path $Source\* -include *.pdf,*.tif,*.jpg -destination $Bkp -passthru | format-table -property LastWriteTime,Name -autosize | out-file $Source\copy.log -Append -Encoding ascii
				Move-Item -path $Source\*.pdf -destination $Destination
				Move-Item -path $Source\*.tif -destination $Destination
				Move-Item -path $Source\*.jpg -destination $Destination
				Add-Content -Path $Source\copy.log -value "**********STOP ACTION @ $time**********`r`n================================================`r`n"
				Copy-Item $Source\copy.log $Bkp\copy.log
			}
				ELSE
			{
				Add-Content -Path $Source\copy.log -value "**********BEGIN ACTION @ $time*********`r`n`r`n0 Files Copied`r`n`r`n**********STOP ACTION @ $time**********`r`n================================================`r`n"
			}
			
	}

This is what we use for most of these processes
Its just that for a few departments we need to append the department name to the beginning of each filename. (The program at the end of this process imports the image into a batch basket and the department name is a needed identifier.)

So what I am doing is testing a path ($BKP) for its existance, if it is there then test the $source path for 3 types of files, if a file of these types exists there, copy it/them to a backup location, move it to a destination, & log what files where copy/moved.

Code not shown: If backup location can’t be reached send out an email alert. If no files exist in $source of the specified types, log that no action was taken.

Another approach might be to Rename-Item before attempting to copy/move but I am still confused on how to append text to the beginning of a filename that is variable.
The dropped off files are never named the same thing so I can’t hardcode the start/end file names.
I need to be able to append the Department Name to the beginning of the filenames leaving the rest alone.

Example: sourcefile = a1b2c3.jpg –> destinationfile = MyDept–a1b2c3.jpg … (next file)Sourcefile = x7y8z9.pdf >– Destinationfile = MyDept–x7y8z9.pdf

So the file name is variable name that I need to add a prefix to.

Your revised approach is still doing multiple files. Move-Item can’t apply a new filename unless it is only moving ONE file. That’s why I added the ForEach in my example. When Move-Item has multiple files, it will only accept a destination path, not a destination filename.Â

Let’s try spelling it out a bit more…

$SourcePath = "C:\Source"

$DestinationPath = "C:\Destination"

$files = Get-ChildItem -Path $SourcePath

$prefix = "Sales"

foreach ($file in $files) {

$oldname = $file.name

$newname = "$($prefix)-$($oldname)"

Move-Item $file $destinationpath

}

Is that perhaps clearer?

The code looks like it makes sense, but I have a couple of questions. in the $files object, does using the -includes switch cause a problem? I want to avoid affecting other file types in the $sourcepath.

Also, when I attempt to run just the piece of code you last posted I get the following error:
I modified only the $sourcepath and $destination paths to point to the following locations “C:\test1” & “C:\Test2” respectively.

Move-Item : Cannot find path 'C:\Scripts\PowerShell\Test.jpg' because it does not exist.
At C:\Scripts\PowerShell\TestCMR2.ps1:10 char:3
+         Move-Item $file $destinationpath
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\Scripts\PowerShell\Test.jpg:String) [Move-Item], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.MoveItemCommand

I don’t understand why the ObjecNotFound is referencing the path of the script itself.

$files will contain whatever Get-ChildItem returns - so you can use any switch of Get-ChildItem, and that includes -Include.

You need to consider how you’re running Get-ChildItem. The error tells me that it returned the file c:\scripts\PowerShell\test.jpg. I can’t tell you how that path got into $files. I’m assuming you modified Get-ChildItem somehow, or did something. Try adding a line to your script like Write-Output $files. That would come after the Get-ChildItem and before the ForEach. That’ll let you see that the variable contains. If you’re not happy with what it contains, then modify your Get-ChildItem appropriately.

So this is now what I get, I’m stumped as to why the -Includes switch isn’t working as expected.

PS C:\test> $file = Get-ChildItem -path "c:\test1"
PS C:\test> write-output $file


    Directory: C:\test1


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         6/25/2013   1:02 PM        364 copy.log
-a---         6/25/2013  12:57 PM      31743 test.jpg
-a---         6/25/2013  12:57 PM      11177 test.pdf
-a---         6/25/2013  12:57 PM     182842 Test.tif


PS C:\test> $file = gci -path "C:\test1" -Include *.jpg,*.pdf,*.tif
PS C:\test> write-output $file
PS C:\test>
[\pre]
Notice there is no output for the 2nd write-output.

It looks like you either need to use the -Recurse argument, or add “*” to the end of your Path parameter (depending on whether you want to search any subdirectories).

Get-ChildItem -Path “C:\Test*” -Include *.jpg
Get-ChildItem -Path “C:\Test” -Include *.jpg -Recurse