Inside a specific folder I have a few sub-folders, in each are stored image files.
I would like to copy the first image file from each sub-folder into the parent and rename it to the folder's name that it belongs.
I managed to write the following script with the information from several other questions on the site but there is something that is not working as expected. Running the script doesn't copy/rename any file.
$Root = (Get-Item -Path '.\' -Verbose).FullName #'
$Folders = Get-ChildItem -Path $Root -Directory
$Image = Get-ChildItem -Name -Filter *.* | Select-Object -First 1
Foreach($Fld in $Folders)
{
Copy-Item -Path "$($Fld.FullName)\$Image" -Destination "$Root\$($Fld.Name).jpeg"
}
Read-Host -Prompt "Press Enter to exit"
I want to be able to run the script from any folder, the paths must be relative and not absolute/hardcoded. I think the $Root variable achieves that purpose.
The sub-folders only contain image files, the filter *.* in the $Image Get-ChildItem is fine for the purpose as it will always pick an image. However the Copy-Item command will copy it with the jpeg extension, is it possible to check the image file extension and copy/rename accordingly? Perhaps with some If statements?
You're mistakenly getting the $image in your $root-directory since you are using the get-childitem without any -Path parameter. For your purpose you need Foreach $Fld (folder) seperately:
$Root = (Get-Item -Path '.\' -Verbose).FullName #'
$Folders = Get-ChildItem -Path $Root -Directory
Foreach($Fld in $Folders)
{
$Image = Get-ChildItem -Path $Fld -Name -Filter *.* | Select-Object -First 1
Copy-Item -Path "$($Fld.FullName)\$Image" -Destination "$Root\$($Fld.Name).jpeg"
}
Read-Host -Prompt "Press Enter to exit"
Here is you code a little shortened:
$Folders = Get-ChildItem -Directory # Without -path you are in the current working directory
Foreach($Fld in $Folders)
{
$Image = Get-ChildItem -Path $Fld -Filter *.* | Select-Object -First 1 # Without the -name you get the whole fileinfo
Copy-Item -Path $Image.FullName -Destination "$PWD\$($Fld.Name)$($Image.Extension)" # $PWD is a systemvariable for the current working directory
}
Read-Host -Prompt "Press Enter to exit"
You could be even bolder as the FullName of the folder contains the path:
Copy-Item -Path $Image.FullName -Destination "$($Fld.FullName)$($Image.Extension)"
Related
enter image description hereI have a folder which has a bunch of files named: WBF123456, WBF135464, etc. These files need to be moved to the corresponding folder. At the moment I am using the commandline to manually enter the numbers of each file so they get moved, using this code:
$files = $args[0]
mv O:\SCAN\SecSur\*$files.pdf O:\SPG\G*\*\*$files
How can I automate this process?
It needs to identify the number in the filename, then move it to the folder containing the same number.
Any help would be great. Thanks.
I need to get the files on the left, inside the corresponding folders on the right.
Maybe the below solution will help you. You should change $origin_path and $destination_path
$origin_path= "C:\Users\geralexgr\Desktop\kati\files"
$destination_path = "C:\Users\geralexgr\Desktop\kati\folders"
Get-ChildItem $origin_path -Recurse -Include *.txt | ForEach-Object {
$folder = [regex]::Matches($_.Name, "\d+(?!.*\d+)").value
Move-Item $_.FullName $destination_path\$folder
}
The example will place files under the folders that match the numeric regex.
After powershell execution file WBF12 gets inside 12 folder
Apparently the files to move are .pdf files, so what you can do is get a list of those files in the source folder and then loop over that list to create (if needed) the destination subfolder and move the file there.
Try:
$destinationRoot = 'O:\SPG\G\SomeWhere' # enter the root folder destination path here
$filesToMove = Get-ChildItem -Path 'O:\SCAN\SecSur' -Filter '*.pdf' -File
foreach ($file in $filesToMove) {
$numName = $file.BaseName -replace '\D+' # leaving only the numbers
# create the target path for the file
$targetFolder = Join-Path -Path $destinationRoot -ChildPath $numName
# create that subfolder if it does not already exist
$null = New-Item -Path $targetFolder -ItemType Directory -Force
# now, move the file
$file | Move-Item -Destination $targetFolder
}
Seeing your screenshots, this might be a better approach for you.
$destinationRoot = 'O:\SPG\G\SomeWhere' # enter the root folder destination path here
# get a list of target folders for the files to be moved to and create a lookupHashtable from their names
$targets = #{}
Get-ChildItem -Path $destinationRoot -Directory | Where-Object {$_.Name -match '(\d+)'} | ForEach-Object {
$targets[$matches[1]] = $_.FullName # key is the number, value is the directory fullname
}
# get a list of files to move
$filesToMove = Get-ChildItem -Path 'O:\SCAN\SecSur' -Filter '*.pdf' -File | Where-Object {$_.Name -match '\d+'}
foreach ($file in $filesToMove) {
$numName = $file.BaseName -replace '\D+' # leaving only the numbers
# see if we have a target folder with that same number in its name
if ($targets.ContainsKey($numName)) {
$targetFolder = $targets[$numName]
Write-Host "Moving file $($file.Name) to $targetFolder"
$file | Move-Item -Destination $targetFolder
}
else {
Write-Warning "Could not find a destination folder for file $($file.Name).."
}
}
So what my powershell script does currently is it asks for path, name of new folder and what the old one was and then it copies the old file contents and puts them in the new one.
What i want after that is to delete all shortcuts and make new ones with target of the exe in new folder and the path or "start in" to be the location of the exe
What code i have currently:
$Location = Read-Host -Prompt 'User writes loc'
Set-Location -Path $Location
$oldname = Read-Host -Prompt 'User writes old file name'
$newname = Read-Host -Prompt 'User writes new file name'
Copy-Item -Path "$Location\$oldname" -Destination "$Location\$newname" -Recurse
$folder = "$Location\$newname"
$files = Get-ChildItem -Path $folder -Include *.lnk -File -Recurse
//Here i now want to delete all the shortcuts it found, tried this 2 ways
//both dont work (inside or outside the loop)
Get-ChildItem -Recursive *.lnk | foreach { Remove-Item -Path $_.FullName }
Remove-Item '$folder\*' -Recurse -Include *.lnk
ForEach($file in $files){
//Then have path set to location where it found the shortcut/exe
//and then target the exe (idk how to get "link")
New-Item -ItemType SymbolicLink -Path "Link" -Target $file
}
I have to create a script that searches for file, takes part of the folder name and move the file to a new location with that new name.
I am planning to use powershell for this but would be up willing to look for other options. This used for millions of files.
Example 1
sourcefolder\a\b\test_123456\example.txt -> \destinationfolder\example_123456.txt
Problem is I don't know how many folders deep the file is and the amount of folder name changes, I need everything after the last _
Example 2
sourcefolder\a\b\c\test_test_1234\example.txt -> \destinationfolder\example_1234.txt
I am researching how to script and will update question when I when I have some progress
FileInfo objects include many properties. One of these is the .Directory property which returns the directory (as DirectoryInfo object) that represents the parent folder the file is in. This Directory also has properties, like .Name.
You can use this like below:
$sourceFolder = 'D:\Test' # the root folder to search through
$destinationFolder = 'X:\Archive' # the destinationpath for the moved files
# make sure the destination folder exists
$null = New-Item -Path $destinationFolder -ItemType Directory -Force
# get a collection of FileInfo objects
# if you need more file extensions like both .txt and .log files, replace -Filter '*.txt' with -Include '*.txt', '*.log'
# this will be slower than using -Filter though..
$filesToMove = Get-ChildItem -Path $sourceFolder -File -Filter '*.txt' -Recurse | Where-Object {$_.Directory.Name -like '*_*'}
# using a foreach(..) is a bit faster than 'ForEach-Object'
foreach ($file in $filesToMove) {
# get the last part after '_' of the parent directory name
$suffix = ($file.Directory.Name -split '_')[-1]
# combine to create the new path and filename
$target = Join-Path -Path $destinationFolder -ChildPath ('{0}_{1}{2}' -f $file.BaseName, $suffix, $file.Extension)
$file | Move-Item -Destination $target -Force -WhatIf
}
Take off the WhatIf safety switch if you are satisfied what is displayed on screen about what would be moved is correct.
You don't even need the foreach loop because Move-Item can handle a scriptblock as parameter for the Destination like this:
$sourceFolder = 'D:\Test' # the root folder to search through
$destinationFolder = 'X:\Archive' # the destinationpath for the moved files
# make sure the destination folder exists
$null = New-Item -Path $destinationFolder -ItemType Directory -Force
# get a collection of FileInfo objects
# if you need more file extensions like both .txt and .log files, replace -Filter '*.txt' with -Include '*.txt', '*.log'
# this will be slower than using -Filter though..
$filesToMove = Get-ChildItem -Path $sourceFolder -File -Filter '*.log' -Recurse |
Where-Object {$_.Directory.Name -like '*_*'} |
Move-Item -Destination {
$suffix = ($_.Directory.Name -split '_')[-1]
Join-Path -Path $destinationFolder -ChildPath ('{0}_{1}{2}' -f $_.BaseName, $suffix, $_.Extension)
} -Force
Here, the $_ Automatic variable is used instead of a variable you define in a foreach loop.
P.S. If you only need files from subfolders with a name ending in _ followed by numbers only as opposed to names like sub_folder, change the Where-Object {...} clause in the code to
Where-Object {$_.Directory.Name -match '_\d+$'}
I have a directory of information that is separated into document numbers so each folder that contains documents starts with DOC-######-NameOfDocument. The thing I am trying to do is create a PowerShell script that will search a directory for any folders with a specified document number and then take the contents of that folder, move it up one level, and then delete the original folder (which should now be empty).
Below is the closest I have gotten to my intended result.
$Path = "filepath"
$Folders = Get-ChildItem -Filter "DOC-#####*" -Recurse -Name -Path $Path
$companyID = "######"
foreach ($Folder in $Folders){
$filepath = $Path + $Folder
$Files = Get-ChildItem -Path $filepath
$imagesourc = $filepath + $companyID
$imageDest = $filepath.Substring(0, $filepath.LastIndexOf('\'))
if (Test-Path -Path $imagesourc){
Copy-Item -Path $imagesourc -Destination $imageDest -Recurse
}
foreach ($File in $Files){
$Parent_Directory = Split-Path -Path $File.FullName
$Destination_Path = $filepath.Substring(0, $filepath.LastIndexOf('\'))
Copy-Item -Path $File.FullName -Destination $Destination_Path -Recurse
if ($null -eq (Get-ChildItem -Path $Parent_Directory)) {
}
}
Remove-Item $filepath -Recurse
}
This does what I need but for whatever reason I can't Devine, it will not work on .HTM files. Most of the files I am moving are .html and .htm files so I need to get it to work with .htm as well. The files with .HTM will not move and the folder won't be deleted either which is good at least.
Try using this:
$ErrorActionPreference = 'Stop'
$fileNumber = '1234'
$initialFolder = 'X:\path\to\folders'
$folders = Get-ChildItem -Path $initialFolder -Filter DOC-$fileNumber* -Force -Directory -Recurse
foreach($folder in $folders)
{
try
{
Move-Item $folder\* -Destination $folder.Parent.FullName
Remove-Item $folder
}
catch [System.IO.IOException]
{
#(
"$_".Trim()
"File FullName: {0}" -f $_.TargetObject
"Destination Folder: {0}" -f $folder.Parent.FullName
) | Out-String | Write-Warning
}
catch
{
Write-Warning $_
}
}
Important Notes:
Move-Item $folder\* will move all folder contents recursively. If there are folders inside $folder, those will also be moved too, if you want to target folders which only have files inside, an if condition should be added before this cmdlet.
Try {...} Catch {...} is there to handle file collision mainly, if a file with a same name already exists in the parent folder, it will let you know and it will not be moved nor will the folder be deleted.
-Filter DOC-$fileNumber* will capture all the folders named with the numbers in $fileNumber however, be careful because it may capture folders which you may not intent to remove.
Example: If you want to get all folders containing the number 1234 (DOC-12345-NameOfDocument, DOC-12346-NameOfDocument, ...) but you don't want to capture DOC-12347-NameOfDocument then you should fine tune the filter. Or you could add the -Exclude parameter.
-Force & -Directory to get hidden folders and to target only folders.
The basic idea:
Mirror the directory structure of the target path
Search the target path for files and folders of a certain age and create a text file with all the paths.
Read the previous text file and copy the contents of the different paths to a new drive location.
Script 1 - Mirror the directory structure of the target path from drive to the next. This I feel like I have working pretty decently.
$target = Read-Host "What is the target path?"
$destination = "Z:\This\Is\The\Destination"
Copy-Item $target -Filter {PSIsContainter} -Recurse -Destination $destination -Force
Script 2 - Is used to look through the $target path and looks for files and folders that are -ge -le -eq a lastwritetime, then outputs the locations in a text file.
$path = read-host "What path would you like to search?"
$daysOLD = read-host "How many days old should the files I'm looking for be?"
$outfile = "C:\locationOFtheTEXTfile\ReadThis.txt"
$today = Get-Date
$targetdate = $today.AddDays(-$daysOLD).ToString('MM-dd-yyyy')
$files = Get-ChildItem $path -Recurse| Where-Object {$_.lastwritetime.ToString('MM-dd-yyyy') -le $targetdate} | ForEach-Object {$_.fullname}| out-file $outfile
Script 3 - Is where I am having an issue. I know that I can use Get-Content and point to the location of the text file. What I have a hard time with is having the script read the file, test the path, and not create duplicates in the $destination.
Since I mirrored the directory structure with the first path, I just need the third script to move files to their appropriate folders on the new drive.
$dest = "Z:\This\Is\The\Destination"
$safe = Get-Content "C:\locationOFtheTEXTfile\ReadThis.txt"
$safe | ForEach-Object{
#find drive-delimeter
$first=$_.IndexOf(":\");
if($first -eq 1){
#stripe it
$newdes=Join-Path -Path $dest -ChildPath #($_.Substring(0,1)+$_.Substring(2))[0]
} else {
$newdes=Join-Path -Path $des -ChildPath $_
}
$folder = Split-Path -Path $newdes -Parent
$err=0
#check if folder exists"
$void=Get-Item $folder -ErrorVariable err -ErrorAction SilentlyContinue
if($err.Count -ne 0){
#create when it doesn't
$void=New-Item -Path $folder -ItemType Directory -Force -Verbose
}
$void=Copy-Item -Path $_ -destination $newdes -Recurse -Container -Force -Verbose
}
write-host "Doomsday =("
This script was taken from the web and I haven't had a chance to figure it's parts and pieces for myself. I know that sound pathetic but I don't feel like trying to reinvent the wheel is necessary.