Appending text to the beginning of a variable file name

This topic contains 8 replies, has 3 voices, and was last updated by  Dave Wyatt 4 years, 1 month ago.

  • Author
    Posts
  • #7849

    Kirk Albers
    Participant

    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.

     

  • #7853

    Don Jones
    Keymaster

    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.

  • #7854

    Kirk Albers
    Participant

    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.

  • #7874

    Kirk Albers
    Participant

    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.

  • #7875

    Don Jones
    Keymaster

    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?

  • #7892

    Kirk Albers
    Participant

    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.

  • #7893

    Don Jones
    Keymaster

    $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.

  • #7899

    Kirk Albers
    Participant

    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.
  • #7915

    Dave Wyatt
    Moderator

    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

You must be logged in to reply to this topic.