Move pdf files matching a substring in powershell - powershell

I need to move the pdf file from location1 to location2 based on the substring (between the last & second last '.') fetched from text filename at location3. I cannot rename the pdf files at location1 during run time, as it have hundreds of thousands of pdf files & I need only few matching the substring pattern.
location3:
A_b_c_d_e_f_1.2.3.4.5.txt
G_h_i_j_k_6.7.8.9.txt
l_m_n_o_p_2.7.8.4.txt
location1:
5_rha_thye_lej.pdf
9_tyoe_hslel_hlssls.pdf
4_shl_heoe_keie_ekye.pdf
I achieved to get the substring from txt file name but moving the pdf matching the pattern is causing the problem.
$files = Get-ChildItem "location3" -Filter *.txt
forEach ($n in $files) {
$substring = $n.Name.split(".")[-2]
write-host $substring }
Move-Item (Join-Path location1\$substring) -Destination location2

I had to read this question a few times and i hope I understand what you want:
in location3 there are .txt files that have a filename ending in a number just before the extension, after a .
find pdf files in location1 that have a filename starting with any of those numbers, followed by an underscore
move these files to location2
If that is correct, you could do:
$location1 = 'D:\Test\sourcefiles' # the source folder where the .pdf files are
$location2 = 'D:\Test\destination' # the destination to move the .pdf files to
$location3 = 'D:\Test' # where the .txt files are
# first test if the destinationfolder $location2 exists. If not create it
if (!(Test-Path -Path $location2 -PathType Container)) {
$null = New-Item -Path $location2 -ItemType Directory
}
# get an array of numbers taken from the textfile names in location3
$numbers = Get-ChildItem -Path $location3 -Filter '*.txt' -File |
Where-Object {$_.BaseName -match '\.(\d+)$'} | ForEach-Object { $matches[1] }
# next, loop through the sourcefolder $location1
Get-ChildItem -Path $location1 -Filter '*_*.pdf' -File | # find .pdf files that contain an underscore in the name
Where-Object { $numbers -contains ($_.Name -split '_')[0] } | # that have a name starting with one of the numbers we got above, followed by an underscore
Move-Item -Destination $location2

Related

Powershell: Moving named files to their corresponding folder

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).."
}
}

copy matching files from a drive to a folder based on fodlername in powershell

I have a a bunch of language folders present in a directory under E:\Data\ like hu-hu, de-de etc.. on the other hand i have a bunch of file names in G:\ that contain the part of folder name for e.g.
amd64.de-de_OCR.cab,amd64.handwriting.de-de.cab
I need to copy all matching file names based on the foldername
for e.g. de-de should copy all matching files in G:\ i.e. both amd64.de-de_OCR.cab,amd64.handwriting.de-de.cab
This is the code i have so far but it is not copying over the files, and i am not sure how to proceed next, any help is appreciated.
$listfoldername = Get-ChildItem -Path "E:\Data" -Recurse -Directory -Force -ErrorAction SilentlyContinue | Select-Object Name
$destfolder = Get-ChildItem -Path "E:\Data" -Recurse -Directory -Force -ErrorAction SilentlyContinue | Select-Object FullName
$filename = Get-ChildItem -file G:\
if($filename -like $listfoldername)
{
Copy-Item -Path $filename -Destination $destfolder
}
There's a few issues with your code
The main issue with your code is that you are trying to use the -like operator to compare two objects (your object containing the directories you wish to move files to, and the object containing the files.
What you need to do is loop through each file and directory, one by one, to determine if the directory name (e.g. "hu-hu" is found in the filename (e.g. amd64.hu-hu_OCR.cab)
You'll want to use the wildcard indicator "*" with the -like operator (e.g. "*hu-hu*")
This below code snippet should do the trick. I tested using the file and folder names you've provided.
"G:" contains the folders:
de-de
hu-hu
us-us (note, I added this to make sure the code did not match this directory)
"E:\Data" contains the files
amd64.de-de_OCR.cab
amd64.handwriting.de-de.cab
amd64.handwritinghu-hu.cab
amd64.hu-hu_OCR.cab
$FileDirectory = "G:" # Change to "G:\", the trailing slash breaks syntax highlight on SO
$DataDirectory = "E:\Data"
$listfoldername = Get-ChildItem -Path "$DataDirectory" -Recurse -Directory -Force -ErrorAction SilentlyContinue | Select-Object Name
$filename = Get-ChildItem -file "$FileDirectory"
#Loop through each file one at a time
foreach ($file in $filename) {
# Then, loop through each folder one at a time
foreach ($folder in $listfoldername) {
# Set the current filename and listfoldername to variables for later -like operator
$FileString = $file.Name
$FolderString = $folder.Name
# If the current file "is like" the current folder name
if($FileString -like "*$FolderString*")
{
# Set the name of the current folder to a variable
$DataFolder = $folder.Name
Copy-Item -Path "$FileDirectory\$FileString" -Destination "$DataDirectory\$DataFolder"
} else {
Write-Output ("$FolderString pattern not found in $FileString")
}
}
}
I think you should start off by getting a list of possible language target folders. Then loop over the path where the files are, filtering their names to have at least the dash in it and next test if any of the language target folders matches the filename.
Something like this:
$langFolder = 'E:\Data'
$fileFolder = 'G:\' #'# dummy comment to fix syntax highlighting in SO
# get a list of the language folders
# if the languages folder has multiple subdirectories to include, add -Recurse here
$targetFolders = Get-ChildItem -Path $langFolder -Directory
# get a list of FileInfo objects for the files in the G:\ path
# if you need to search subdirectories aswell, add -Recurse here
$files = Get-ChildItem -Path $fileFolder -File -Filter '*-*.*'
foreach($file in $files) {
# check if a language name matches the file name
foreach($folder in $targetFolders) {
if ($file.BaseName -like "*$($folder.Name)*") {
# we have found a matching language target directory
$file | Copy-Item -Destination $folder.FullName
break # exit this folder foreach loop and get on with the next file
}
}
}
P.S. If all the files are .cab files you could speed up by setting the Filter to '*-*.cab' in line $files = Get-ChildItem ...

Windows - Create Folder and sub folder based on date of filename

I have a folder with a number of pdf files whereby the last 8 characters is the date of the document in the format YYYYMMDD, samples are:
File_YYYYMMDD
Test_Ref_YYYYMMDD
file.nr_YYYYMMDD
I am looking for a way to create a folder structure based on last 8 characters:
OutputFolder\Subfolder YYYY\Subfolder MM\File name remains the same.
Thanks.
For this you need to iterate through the source folder where the pdf files are, and using their BaseName (= filename without extension), get the year and month part.
Having those, creating the folder structure is a breaze in PowerShell:
$sourceFolder = 'D:\OriginalPath' # the path where your pdf files are
$destination = 'D:\PdfFiles' # the folder where the new folder structure should be created
# get the pdf files that have a basename ending with 8 digits
Get-ChildItem -Path $sourceFolder -Filter '*.pdf' -File |
Where-Object { $_.BaseName -match '\d{8}$' } |
ForEach-Object {
# split the year and month part of the file's basename
$match = $_.BaseName -match '(\d{4})(\d{2})\d{2}$'
$year, $month = $matches[1..2]
# construct the folder path
$targetFolder = Join-Path -Path $destination -ChildPath "$year\$month"
# if the target folder does not exist, create it
if (!(Test-Path -Path $targetFolder -PathType Container)) {
$null = New-Item -Path $targetFolder -ItemType Directory
}
# you probably now want to copy or move the file in that target folder
$_ | Copy-Item -Destination $targetFolder
}
Example of the source folder:
D:\ORIGINALPATH
File_20200201.pdf
File_20200327.pdf
Test_Ref_20191127.pdf
After running the code:
D:\PDFFILES
+---2019
| \---11
| Test_Ref_20191127.pdf
|
\---2020
+---02
| File_20200201.pdf
|
\---03
File_20200327.pdf

powershell wildcard character in a control file list

I have a powershell script that uses a control file to archive files:
# Takes the information from $controlfile and moves the files to the archive folder**
foreach ($line in get-content $controlfile)
{
$file = $controlfile
$split = $line.split("|")
$archive_path = $split[0]
$source_path = $split[1]
$basename = $split[2]
$extention = $split[3]
$daystoleave = $split[4]
# move the files to the archive folder
Get-ChildItem $source_path -Filter "$basename*" -Force -Recurse | Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays($daystoleave)} | Move-Item -Destination $archive_path
Get-ChildItem $archive_path -Filter "$basename*" -Force -Recurse | % { rename-item –path $_.Fullname –Newname (("$basename") + ("_") + ($_.LastWriteTime.toString("MM.dd.yy_HH.mm.ss")) + (".$extension")) }
}
Control file example:
\server\Apps\Archive-Requests\|\server\Apps\requests\|?||0
\server\Apps\Archive-Requests\|\server\Apps\requests\|*||0
Above examples don't work because of the ? or * character in the file name split of the control file.
\server\Apps\Archives\Archive_Daily_Reports\|\apps\FICS\Daily Reports\|audit|fics|0
Above example works because "audit" is the beginning of the file name.
This works fine when I want to capture and use the first part of the original file name (ex. SAD123.txt - capture SAD|add LastWriteTime date to name|add extension|leave some file(s) in original folder ($daystoleave).
But if I'd like to capture either the entire original name or a middle portion of the name using wildcard characters, I receive "Illegal characters in path." and nothing changes to the end result filename. Is there a wildcard I can use other than * or ? in the control file.
Is it possible to use a wildcard in the control file?

Copy directories when their name matches -Like txt files

I am trying to copy a bunch of directories. I have text files which have a similar name and I need to match the directories to those text files to determine which directories to copy.
This is what I have done and I can't figure out how to fix it. I am going around in circles.
$destination = "..\..\$args\Images\"
$txtfiles = Get-ChildItem $destination -Include *.txt
$source = "..\..\..\Images\" | ?{ $_.PSIsContainer } | Where-Object { $_.Name -Like "*$txtfiles*" } | Copy-Item $destination
An example of a txt file: 1e03655b-0aac-48b2-82f3-75942084af7a.txt
and folder: name.1e03655b-0aac-48b2-82f3-75942084af7a
So I need to find the folders that match the txt files and copy the folder to the txt file directory.
Thanks
You want to expand the BaseName properties of those text files (to cut off the .txt part) and have an array of strings such as:
1e03655b-0aac-48b2-82f3-75942084af7a
1e03655b-0aac-48b2-82f3-75942084af7b
1e03655b-0aac-48b2-82f3-75942084af8g
1e03655b-0aac-48b2-82f3-75942084afba
Then your $source = line needs to pull a directory listing and not just pipe a string down the pipeline, and then I would suggest matching the directory names with a regex match, and checking to see if that match is -in $txtfiles.
$destination = "..\..\$args\Images\"
$txtfiles = Get-ChildItem $destination -Filter *.txt | Select -ExpandProperty BaseName
$source = "..\..\..\Images\"
GCI $source -Directory | ?{ $_.Name -match "(\w{8}-\w{4}-\w{4}-\w{4}-\w{12})$" } | %{If($Matches[1] -in $txtfiles){Copy-Item $_.FullName $destination}}