I have been looking for the way to do this using get-children and rename combined with if but no luck.
I want to search all subdirectories (subdir1, subdir2, etc) of a directory (test) for a file "trigger.txt" and if the file exists in one of these subdirectories I want to change the name of another file in the same subdirectory (changeme.txt to _changeme.txt)
Rephrasing:
If file subdir1\"trigger.txt" exists change subdir1\"changename.txt" to subdir1\"_changename.txt"
I have found scripts to change the name of file if it exists and to look for a file but I cannot connect it together... Any help?
Try this:
Get-ChildItem -r trigger.txt | Foreach {Rename-Item (Join-Path $_.DirectoryName changeme.txt) _changeme.txt}
And if you want the terse version:
ls -r trigger.txt | %{rni (join-path $_.DirectoryName changeme.txt) _changeme.txt}
Perhaps something like this?
ls -filter trigger.txt -recurse | %{
$original = Join-Path $(Split-Path $_.FullName -Parent) "ChangeMe.txt"
$newName = Join-Path $(Split-Path $_.FullName -Parent) "_ChangeMe.txt"
if ([IO.File]::Exists($original)) {
Write-Host "Renaming $($original)..."
ren -Path $original -NewName $newName
}
}
Related
I am a new starter to powershell and I am trying to achieve the following:
I have a list of files all in the same format: SURNAME_FIRSTNAME_CODE1_CODE2_NAME.pdf/docx etc
I want to create a subfolder named: SURNAME FIRSTNAME CODE1
and then move all of those relavant files into the folder.
I managed to find an article to do it with the first part (i.e SURNAME) but not really sure how to make it work with the others...any help would be greatly appreciated.
Here is what I have so far: (Thanks to a fellow poster for it)
Get-ChildItem -File -Path $directory -Filter "*.*" |
ForEach-Object {
New-Item -ItemType Directory "$directory$($_.Name.Split("_")[0])" -Force;
Move-Item -Path $_.FullName -Destination "$directory$($_.Name.Split("_")[0])\$($_.Name)"
}
This is how I'd do it. It uses Group-Object to group files that belong to the same directory, and the format operator to create the directory name. Let me know if you have any questions.
Get-ChildItem $directory -File |
group { "{0} {1} {2}" -f $_.BaseName.Split("_") } |
foreach {
$newDir = Join-Path $directory $_.Name
New-Item $newDir -ItemType Directory
$_.Group | Move-Item -Destination $newDir
}
I Have this powershell script “copFiles.ps1” that looks in a txt file "Filestocopy.txt" for a list and copies them to a destination
$source = "C:\Data\Filestocopy.txt"
$destination = "C:\Data\Models"
Get-Content $source | ForEach-Object {copy-item $_ $destination}
It’ll only copy the files if they’re in the same folder as the .ps1 file and it ignores subfolders, how can I get it to look in subfolders of the folder that its in, I gather I need to use the -recurse option but don’t know how to rewrite it so it works.
The .ps1 file is fired by a bat file.
Many thanks
I don't know how fast this will be, but you can give an array as the argument for the -Path parameter of Get-ChildItem add the -Recurse switch to dig out the files in subdirectories and simply pipe them along to Copy-Item. something like:
Get-ChildItem (Get-Content $Source) -Recurse |
Copy-Item -Destination $destination
You may also want to add the -File switch.
Update
Based on your comment I played around with this a a little more:
$source = "C:\Data\Filestocopy.txt"
$Destination = "C:\data\Models"
# Get-ChildItem (Get-Content $Source) -Recurse |
Get-ChildItem (Get-Content $Source) -Recurse -File |
ForEach-Object{
If( $_.Directory.FullName -eq $Destination )
{ # Don't work on files already present in the destination
# when the destination is under the current directory...
Continue
}
$FileNum = $null
$NewName = Join-Path -Path $Destination -ChildPath $_.Name
While( (Test-Path $NewName) )
{
++$FileNum
$NewName = Join-Path -Path $Destination -ChildPath ($_.BaseName + "_" + $FileNum + $_.Extension)
}
Copy-Item $_.FullName -Destination $NewName
}
This will increment the destination file name in cases where a file by that name already exists in the destination. If the destination is under the current directory it will prevent analyzing those files by comparing the path of the file to the destination. Files must have unique names in a given folder so I'm not sure how else it can be handled.
I have the following structure:
mainfolder
folder1
000000.jpg
000001.jpg
000003.jpg
000004.jpg
folder2
000000.jpg
000001.jpg
folder3
000000.jpg
000001.jpg
000002.jpg
....
I want to copy and rename all the jpg-files. After the copying and renaming it should look like this:
mainfolder
folder1_000000.jpg
folder1_000001.jpg
folder1_000003.jpg
folder1_000004.jpg
folder2_000000.jpg
folder2_000001.jpg
folder3_000000.jpg
folder3_000001.jpg
folder3_000002.jpg
....
Can someone tell me how the PowerShell Skript for this looks like?
I would like to share the beautiful oneliner that lets you do this in PowerShell:
Get-ChildItem -Path mainfolder -Recurse -Filter "*.jpg" | % { $_ | Move-Item -Destination ("mainfolder\{0}_{1}" -f $_.Directory.Name, $_.Name) }
try this:
$DirRank=New-Object 'system.collections.generic.dictionary[string,int]'
$mainfolder="c:\temp"
Get-ChildItem $mainfolder -Recurse -File | %{
#Build or increment key for every sub-directory
if ($DirRank.ContainsKey($_.DirectoryName))
{
$DirRank[$_.DirectoryName]++
}
else
{
$DirRank[$_.DirectoryName]=0
}
#build new file name
$NewName="{0}\{1}_{2:d6}{3}" -f $mainfolder, $_.Directory.Name, $DirRank[$_.DirectoryName], $_.Extension
$fullename=$_.FullName
#rename and move item (remove -whatif for really rename)
move-Item $_.FullName $NewName -WhatIf -Force
}
I am trying to use powershell to copy one type of file (.xlsx) from one folder to another.
Once the copy is completed, I would like the extension on the original file to be changed. (.xlsx to .cmp)
I have the copy part down (below) but I am lost when it comes to the rename. Can you guys please help. I am a PS noob! Thank you.
$src = "C:\Users\x\Documents\Test1"
$dst = "C:\Users\x\Documents\Test2"
Get-ChildItem $src -Filter "*.xlsx" | Move-Item -Destination $dst -Force
As far as I know, you'll have to iterate over your files to be able to perform this rename.
# Set-up variables
$sourcePath = "C:\temp"
$sourceExtension = "txt"
$destinationPath = "C:\temp2"
$destinationExtension = "cmp"
# Grab the list of files
$files = Get-ChildItem -Path $sourcePath -Filter "*.$sourceExtension"
# Loop over the files
foreach ($file in $files) {
# Construct the new file name
$newFileName = (Join-Path -Path $destinationPath -ChildPath $file.BaseName) + ".$destinationExtension"
Write-Output "New File Name = $newFileName"
# Move the file to the new destination with its new name!
Move-Item -Path $file.FullName -Destination $newFileName
}
Note: BaseName = filename without extension
This should do it:
$src = "C:\Users\x\Documents\Test1"
$dst = "C:\Users\x\Documents\Test2"
Get-ChildItem $src -Filter "*.xlsx" | ForEach-Object {
Copy-Item $_ -Destination $dst
Rename-Item $_ -NewName ($_.Name -Replace '.xlsx','.cmp')
}
Uses a ForEach-Object loop to go through each item in the $src folder. Then for each item (represented inside the loop as $_) we use Copy-Item to copy it to the destination Then use Rename-Item with a -Replace to change the file extension.
I need to copy a large number of files to a backup folder but I want to maintain their relative paths. I only need specific files; i.e.
C:\scripts\folder\File.ext1
C:\scripts\folder2\file2.ext2
C:\scripts\file3.ext1
But I only need to copy the ext1 files like so:
C:\backup\folder\File.ext1.bak
C:\backup\file3.ext1.bak
The source paths are of multiple depths.
This is what I have to copy the files:
$files = gci -path C:\scripts\ -recurse -include *.ext1
$files | % { Copy-Item $_ "$($_).bak"; move-item $_ -destination C:\backup\ }
This just dumps all the files into C:\backup\ and does not appear to get any of the paths. Not sure how that part would be done.
Something like this could work:
gci -path C:\scripts\ -recurse -include *.ext1 |
% { Copy-Item $_.FullName "$($_.FullName).bak"
move-item $_.FullName -destination ($_.FullName -replace 'C:\\scripts\\','C:\backup\') }
It is not clever, but it's quick & dirty and works without a lot of effort.
get-childitem returns absolute paths, but you can make them relative to the current working directory as follows:
resolve-path -relative
So to copy a filtered set of files from the current directory recursively to a destination directory:
$dest = "c:\dest"
$filter = "*.txt"
get-childitem -recurse -include $filter | `
where-object { !$_.PSIsContainer } | `
resolve-path -relative | `
% { $destFile = join-path $dest $_; new-item -type f $destFile -force | out-null; copy-item $_ $destFile; get-item $destfile; }
new-item is needed to create the parent directories
get-item provides a display of all the new files it created
Of course robocopy does all this, but there will be times when you want to do more special filtering or filename mangling...
Use robocopy.
robocopy c:\scripts c:\backup *.ext1 /s
Oops. I failed to notice you wanted to add the .bak extension too. I still think it is a good idea to use robocopy to copy the files then:
dir c:\backup -recurse -include *.ext1 | % { ren $_ "$_.bak" }
You can try this
Clear-Host
$from = "'C:\scripts\"
$to = "'C:\backup\"
$inc = #('*.ext1', '*.extx')
$files = get-childItem -path $from -include $inc -Recurse
$files | % {$dest = (Join-Path $to $($_.FullName+".bak").SubString($from.length)); $dum = New-Item -ItemType file $dest -Force; Copy-Item -Path $_ -Destination $dest -Recurse -Force }
the new-item is there in order to force path creation.
Jean Paul