Copy files renaming if already exists PowerShell - powershell

This script works to rename files while copying them if they are duplicates. I need to rename the current destination file first then copy the source file as is. Any ideas?
function Copy-FilesWithVersioning{
Param(
[string]$source,
[string]$destination
)
Get-ChildItem -Path $source -File
ForEach-Object {
$destinationFile = Join-Path $destination $file.Name
if ($f = Get-Item $destinationFile -EA 0) {
# loop for number goes here
$i = 1
$newname = $f.Name -replace $f.BaseName, "$($f.BaseName)_$I")
Rename-Item $destinationFile $newName
}
Copy-Item $_ $destination
}
}
Copy-FilesWithVersioning c:\scripts\Source c:\scripts\DestinationA
Errors:
At line:10 char:53
+ if($f = Get-Item $destinationFile -EA 0){
+ ~
Missing closing '}' in statement block or type definition.
At line:8 char:23
+ ForEach-Object{
+ ~
Missing closing '}' in statement block or type definition.
At line:2 char:34
+ function Copy-FilesWithVersioning{
+ ~
Missing closing '}' in statement block or type definition.
At line:13 char:77
+ ... $newname = $f.Name -replace $f.BaseName, "$($f.BaseName)_$I")
+ ~
Unexpected token ')' in expression or statement.
At line:15 char:13
+ }
+ ~
Unexpected token '}' in expression or statement.
At line:17 char:9
+ }
+ ~
Unexpected token '}' in expression or statement.
At line:18 char:1
+ }
+ ~
Unexpected token '}' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingEndCurlyBrace

The errors you're seeing are caused by the spurious closing parenthesis in this line:
$newname = $f.Name -replace $f.BaseName, "$($f.BaseName)_$I")
Remove the parenthesis from the end of the line and these errors will disappear.
There are several other mistakes in your code, though, so even with that fixed the code still won't work.
You're missing a pipe between the Get-ChildItem and ForEach-Object. It's required for passing the output of one cmdlet to the other.
Get-ChildItem -Path $source -File |
ForEach-Object {
...
}
The variable $file is undefined. In a PowerShell pipeline you want to work with the "current object" variable ($_). Change this line
$destinationFile = Join-Path $destination $file.Name
into
$destinationFile = Join-Path $destination $_.Name
$_ in the statement
Copy-Item $_ $destination
is expanded to just the name of the file, not the full path. Change that into
Copy-Item $_.FullName $destination
Better yet, move the Copy-Item statement after the ForEach-Object, so you don't need to explicitly specify the source in the first place (the cmdlet reads input from the pipeline):
Get-ChildItem ... | ForEach-Object {
...
$_ # need this line to pass the current object back into the pipeline
} | Copy-Item -Destination $destination
Note that you must output the current object back to the pipeline and specify the destination as a named parameter (-Destination $destination) for the latter to work.
Your check for the presence of a file in the destination folder is a little awkward. Use Test-Path instead. You can construct the new filename from the current object.
if (Test-Path -LiteralPath $destinationFile) {
$i = 1
Rename-Item $destinationFile ($_.BaseName + "_$i" + $_.Extension)
}

Try code from this link: https://www.pdq.com/blog/copy-individual-files-and-rename-duplicates/:
$SourceFile = "C:\Temp\File.txt"
$DestinationFile = "C:\Temp\NonexistentDirectory\File.txt"
If (Test-Path $DestinationFile) {
$i = 0
While (Test-Path $DestinationFile) {
$i += 1
$DestinationFile = "C:\Temp\NonexistentDirectory\File$i.txt"
}
} Else {
New-Item -ItemType File -Path $DestinationFile -Force
}
Copy-Item -Path $SourceFile -Destination $DestinationFile -Force

Related

Move Item path null

I have to move files from a folder corresponding to a CSV column like that :
id
name
1a
file1
2b
file2
3c
file3
4d
file4
So if in my folder I have a file named file1 I need to create a folder named 1a and put file1 inside.
I have the following script
$CsvId = Import-Csv './test.csv'
$sourcePath= "C:\Users\olong\Desktop\object"
$dirPath = "C:\Users\olong\Desktop\dir"
$files = Get-ChildItem -Path $sourcePath | ForEach-Object -Process {[System.IO.Path]::GetFileNameWithoutExtension($_)}
$pattern = '(?<=_).*(?=_)'
ForEach ($item In $CsvId) {
$objectID = $item.'id'
$docID = $item.'name'
$location = $dirPath+ "\" + $objectID
Foreach ($file in $files) {
if($file -contains $docID) {
if (-not (Test-Path -Path $location)) {
mkdir -Path $location
}
Move-Item ($file.FullName) -Destination $location -Verbose -Force
}
}
}
But it gives me that error :
Move-Item : Cannot bind argument to parameter 'Path' because it is null.
At C:\Users\olong\Desktop\scriptMove.ps1:19 char:15
+ Move-Item ($file.FullName) -Destination $location -Verbose -Force
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Move-Item], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.MoveItemCommand
With PowerShell's debugger $file is not null and with or without parenthesis on $file.FullName does nothing
I think what you want to do is to get the file(s) as mentioned in the csv under header 'name' having any extension into a subfolder as mentioned in field 'id' and create that subfolder first if it does not already exist.
If my assumtion is correct, you can try below:
$sourcePath = "C:\Users\olong\Desktop\object"
$destinationPath = "C:\Users\olong\Desktop\dir"
Import-Csv -Path './test.csv' | ForEach-Object {
$targetDirectory = Join-Path -Path $destinationPath -ChildPath $_.id
# create the output subfolder if it does not already exist
$null = New-Item -Path $targetDirectory -ItemType Directory -Force
# next use the file basename from the $_.name column as filter and move the file(s)
Get-ChildItem -Path $sourcePath -Filter "$($_.name).*" -File | Move-Item -Destination $targetDirectory
}

Powershell | Rename file with random name

I'm making a script to rename a specific file with a random name. But when running, the following error always occurs:
It is not possible to convert the value ".jpg" to the type "System.Int32". Error: "The input string was not in the correct format."
In C:\Windows\system32\WindowsPowerShell\v1.0\Modules\SetDiscordWallpaper\SetDiscordWallpaper.ps1:7 character:7
+ Rename-Item -Path $file.FullName -NewName ($random + $file.Exte ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastFromStringToInteger
Here is the code I am using
function Set-DiscordWallpaper {
$path = "C:\Windows\Temp\*"
foreach($file in $(Get-ChildItem -Path $path -Include "Wallpaper.jpg")) {
$extension = [System.IO.Path]::GetExtension($file.FullName);
$randomName = [System.IO.Path]::ChangeExtension([System.IO.Path]::GetRandomFileName(), $extension)
$newPath = "C:\inetpub\wwwroot\"
Write-Host "Changing File $($file.Name) to $randomName"
Move-Item -Path $file.FullName -Destination $newPath
}
}
I ask you to help me please. I'm waiting the answer. Thanks
The code (second part in your question) creates the new random filename just fine, only the line Move-Item -Path $file.FullName -Destination $newPath does nothing with that new name and moves the file with its original name to the new path.
Change that line to
Move-Item -Path $file.FullName -Destination (Join-Path -Path $newPath -ChildPath $randomName)
so the file gets moved with the random name in the new path.
Or is your intention to copy the file to its new destination keeping the original filename there and after that rename the original?
In that case do:
Write-Host "Changing File $($file.Name) to $randomName"
Copy-Item -Path $file.FullName -Destination $newPath # copy with original name
$file | Rename-Item -NewName $randomName # rename the original file

How do I remove a leading or trailing blank space in file name with PowerShell?

I'm basically trying to trim() any filenames that have a leading or trailing space at the end of the name. This is the code I've got so far
$foldersToCheck = "$env:userprofile\documents", "$env:userprofile\pictures", "$env:userprofile\desktop"
foreach ($folder in $foldersToCheck) {
get-childitem -path $folder -recurse | foreach-object {
if ($_.name.startswith(" ") -or $_.name.endswith(" ")) {
$newName = $_.name.trim()
rename-item -path $_ -newName $newname
}
}
}
If I create a test file (c:\users\someusername\desktop\ test.txt), then I receive this error
rename-item : Cannot rename because item at ' test.txt' does not exist.
At line:6 char:13
+ rename-item -path $_ -newName $newname
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Rename-Item], PSInvalidOperationException
+ FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.RenameItemCommand
So, it looks like it found the file that needs to be renamed, but then says it doesnt exist.
The problem here is that PowerShell resolves $_ to just the file name when attempting to convert it to a string it can bind to -Path.
Explicitly pass the full path of the file and it'll work:
Rename-Item -Path $_.FullName -NewName $newname
Alternatively, pipe the $_ file object to Rename-Item and PowerShell will automatically figure out that it needs to bind $_.FullName to Rename-Item's -LiteralPath parameter:
$_ |Rename-Item -NewName $newname
You can also turn the whole loop into a single pipeline, and then take advantage of a pipeline-bound expression against -NewName:
$foldersToCheck |Get-ChildItem -Recurse |Rename-Item -NewName { $_.Name.Trim() }
If the existing Name and the -NewName values are the same, Rename-Item will just leave the files alone anyway :)

Move-Item to correct Destination

The Script:
Creates a list of folders based on the filenames in the scripts root directory, each folder breaks down the name by "Year/Month/Day"
Moves each file to the designated folder
Error Message:
CategoryInfo : ObjectNotFound:
(S:\Data\TECHNOL...59_20180108.txt:String)
[Move-Item], ItemNotFoundException FullyQualifiedErrorId :
PathNotFound,Microsoft.PowerShell.Commands.MoveItemCommand
My Issue
The files will not move to the correct endpath
#Create Directory
Set-StrictMode -Version 2
$rootPath = split-path -parent $MyInvocation.MyCommand.Definition
cd $rootPath
$FileNameArray = Get-ChildItem -Filter "*.txt"
$FileNameArray = $FileNameArray -replace "....$"
$FileNameArray = $FileNameArray -replace "^59_"
Foreach($f in $FileNameArray)
{
$Year = $f -replace "^\d{0}|\d{4}$" #"....$"
$Month = $f -replace "^\d{4}|\d{2}$"
$Month = $Month | sort -Unique
$Day = $f -replace "^\d{6}|\d{0}$"
#Loop 2a
Foreach($m1 in $Month){
#Loop 2a-a
Foreach($d1 in $Day){
Move-Item -Path ($rootPath + '\59_' + $file + '.txt')
-Destination ($rootPath + '\' + $Year + '\' + $m1 + '\' + $d1)
}
}
}
Apologies for the spaghetti code & simple question, I am new to both Computer Science and PowerShell.
The following script has two security features:
The MD command has a trailing -confirm you have to answer
The Move-Item has a -WhatIf which shows what would be done without the Parameter
If the script works OK, remove them both.
## Q:\Test\2018\05\03\SO_50158185.ps1
Set-StrictMode -Version 2
$rootPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
cd $rootPath
Get-ChildItem "59_20[0-9][0-9][0-1][0-9][0-3][0-9].txt" |
Where-Object {$_.BaseName -Match '59_(?<year>\d{4})(?<Month>\d{2})(?<Day>\d{2})'}|
ForEach-Object {
$DestDir = Join-Path $rootPath ("{0}\{1}\{2}" -f $Matches.Year,$Matches.Month,$Matches.Day)
If (!(Test-Path $DestDir)) {MD $DestDir -Confirm| Out-Null}
$_ | Move-Item -Destination $DestDir -WhatIf
}
Figured it out guys! Just needed to change $file to $f. Thanks for all the help.

Path not found when using Move-Item

I want to do to the following things:
do the listing of all the items in the directory
move the files according to their names into different location
Example: In my document folder I have various files. According to the file names, I will move them to different directory. I use the following script. But it is not working.
$allfiles = Get-ChildItem $home\documents
$count = 0
foreach($file in $allfiles)
{
if ($file.name -like "*Mama*")
{
move-item $file.name -Destination $home\documents\mom
$count++
}
elseif ($file.name -like "*Papa*")
{
move-item -destination $home\documents\Dad
$count++
}
elseif ($file.name -like "*bro")
{
Move-Item -Destination $home\documents\Brother
$count++
}
}
write-host "$count files been moved"
What I am doing wrong here?
My Error output is
move-item : Cannot find path 'C:\users\administrator\documents\Lecture3.txt' because it does not exist.
At line:6 char:10
{ move-item $file.name -Destination $home\documents\Win213SGG\lectures
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : ObjectNotFound: (C:\users\admini...ts\Lecture3.txt:String) [Move-Item], ItemNotFoundExceptio
n
FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.MoveItemCommand
move-item : Cannot find path 'C:\users\administrator\documents\Lecture3_revised.txt' because it does not exist.
At line:6 char:10
+ { move-item $file.name -Destination $home\documents\Win213SGG\lectures
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\users\admini...re3_revised.txt:String) [Move-Item], ItemNotFoundExceptio
n
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.MoveItemCommand
cmdlet Move-Item at command pipeline position 1
Supply values for the following parameters:
Path[0]:
Or you could make it even neater by using the pipe functionality in powershell. Like this, you don't have to specify with '-path' which file to move, but you can pass it on directly from the result of Get-ChildItem:
Get-ChildItem $home\documents | Foreach-Object {
$count = 0
if ($_.Name -like "*Mama*")
{
$_ | Move-Item -Destination $home\documents\mom
$count++
}
elseif ($_.Name -like "*Papa*")
{
$_ | Move-Item -Destination $home\documents\Dad
$count++
}
elseif ($_.Name -like "*bro")
{
$_ | Move-Item -Destination $home\documents\Brother
$count++
}
}
write-host "$count files been moved"
Try this -
$allfiles = Get-ChildItem $home\documents
$count = 0
foreach($file in $allfiles)
{
if ($file.name -like "*Mama*")
{
move-item -path $file -Destination $home\documents\mom
$count++
}
elseif ($file.name -like "*Papa*")
{
move-item -path $file -destination $home\documents\Dad
$count++
}
elseif ($file.name -like "*bro")
{
Move-Item -path $file -Destination $home\documents\Brother
$count++
}
}
write-host "$count files been moved"
You haven't specified the File Name at two occasions which is a mandatory parameter for move-item. And at one place you are trying to move the files using the Name parameter which is not an item(in literal sense). See if above works for you.