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?
Related
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
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 ...
I need to bulk rename files in a file share that
contain a specific character, namely a tilde ~ and
have the file extension in capital letters or none at all.
The goal would be to replace the tilde with a simple -, keep the file extension, if there is one, but transform it into lowercase letters.
I've had success with the first part of the script that finds the files
$PATH = "\\<Fileservername>\<Folder>\"
$pattern = "*~*"
Get-ChildItem $PATH -Recurse | where {$_.Name -like $pattern}
What I'm struggling with is the second part of the script the renaming.
I've found two topics here:
Powershell renaming a specific Character
PowerShell Regex Bulk Replace Filenames
I haven't been able to adapt those solutions to my need plus there may be additional steps to take in order to convert the given file name from capital letters to lowercase letters or skip this if the file has no file extension.
An example would be to rename ACUJLH~H to ACUJLH-H and KYA3BM~Q.PDF to KYA3BM-Q.pdf.
Here's my contribution. I have added the -File switch to the Get-ChildItem cmdlet so it will look for files only and will not try and handle directory names.
Also, I have changed the replace pattern to ~+ so files that have repeating tildes will be replaced with a single - character. (KYA3BM~~~~Q.PDF becomes KYA3BM-Q.pdf)
$path = "D:\Code\PowerShell\StackOverflow"
$pattern = "*~*"
Get-ChildItem $path -Recurse -File | Where-Object {$_.Name -like $pattern} |
ForEach-Object {
$directory = $_.DirectoryName # or [System.IO.Path]::GetDirectoryName($_.FullName) or use Split-Path $_.FullName -Parent
$filename = $_.BaseName -replace '~+', '-' # or [System.IO.Path]::GetFileNameWithoutExtension($_.Name) -replace '~+', '-'
$extension = $_.Extension # or [System.IO.Path]::GetExtension($_.Name)
if (![string]::IsNullOrEmpty($extension)) { $filename += $extension.ToLower() }
$newname = Join-Path -Path $directory -ChildPath $filename
Rename-Item -LiteralPath $_.FullName -NewName $newName -Force
}
You will need to filter files those meets your criteria. Then using ForEach-Object compare for extensions and build new file names for every found item. Finally, using Rename-Item cmdlet you make the change.
$PATH = '\\<Fileservername>\<Folder>\'
Get-ChildItem $PATH -Recurse -Include '*~*' | ForEach-Object {
[String]$Extension = [System.IO.Path]::GetExtension($_)
[String]$NewFileName = [System.IO.Path]::GetFileNameWithoutExtension($_.Name) -replace '~','-'
if ($Extension){ $NewFileName += $Extension.ToLower() }
Rename-Item $_.FullName $(Join-Path ([System.IO.Path]::GetDirectoryName($_)) $NewFileName) -Force
}
I have the following PowerShell script that puts all .jpg files found in its subfolders into a 'Scans' folder and renames these .jpg files to match the name of their respective parent directory (=subfolder). When multiple .jpg files exist the renaming process will automatically add a number to the filename, like File_1,jpg and File_2.jpg.
So before the script is run a folder may look like this:
Parent Directory from which script is executed
|
Subfolder (containing .jpg files and the 'Scans' subfolder)
|
Scans (=folder)
Photo.jpg
Picture.jpg
Shot(1).jpg
Shot(2).jpg
Once the script has run the folder looks like this:
Parent Directory from which script is executed
|
Subfolder (containing the 'Scans' subfolder)
|
Scans (=folder containing supposed to contain all .jpg files)
|
Subfolder_1.jpg
Subfolder_2.jpg
Shot(1) (=file moved but extension stripped)
Shot(2) (=file not moved and extension stripped)
So the .jpg files containing parenthesis 'Shot(1).jpg' and 'Shot(2).jpg' are not properly renamed and moved to the 'Scans' folder. In fact their '.jpg' extension is stripped off.
The script works fine as long as the .jpg files do not contain any parentheses (()), as in
'Shot(1).jpg' and 'Shot(2).jpg' → when multiple .jpg files exist
'Pics(2001).jpg' → when the subfolder name contains parentheses as in 'Pics(2001)', the .jpg is correctly renamed, but then contains parentheses and the script would fail again when run a second time.
I have read about escaping special characters in other threads but have not been able to implement a solution into the script below. Does anybody here have a solution so that the parentheses are not causing any issues when moving and renaming these .jpg files?
$path = Split-Path -parent $MyInvocation.MyCommand.Definition
function renamePhotos {
# Loop through all directories
$dirs = dir $path -Recurse | Where { $_.psIsContainer -eq $true }
foreach ($dir In $dirs) {
$i = 1
$newdir = $dir.parent.name + "_"
$images = Get-ChildItem -Path $dir.fullname -Filter *.jpg -Recurse
foreach ($image In $images) {
$split = $image.name.split(".jpg")
$replace = $split[0] -Replace $split[0],($newdir + $i + ".jpg")
$image_string = $image.fullname.ToString().Trim()
Rename-Item "$image_string" "$replace"
$i++
Move-Item -Path $dir\*.jpg -Destination $dir\Scans
}
}
}
# RUN SCRIPT
renamePhotos
"SCRIPT FINISHED"
The -replace operator does a regular expression replacement. If you want to use it you need to escape special characters in your source string:
-replace [regex]::Escape($split[0]), "$newdir$i.jpg"
However, you don't need that in the first place. Simply use the appropriate properties of the FileInfo objects:
$images = Get-ChildItem -Path $dir.fullname -Filter *.jpg -Recurse
foreach ($image in $images) {
$newname = $newdir + $i + $image.Extension
Rename-Item $image.FullName $newname
$i++
}
Move-Item -Path $dir\*.jpg -Destination $dir\Scans
Or simply move the items to the new location with their new name without renaming them first:
$images = Get-ChildItem -Path $dir.fullname -Filter *.jpg -Recurse
foreach ($image in $images) {
$newname = $newdir + $i + $image.Extension
Move-Item $image.FullName "$dir\Scans\$newname"
$i++
}
I have this piece of powershell code below which creates an individual text file in the folder C:\Users\XX\Desktop\info\ from each individual zip file in the folder C:\Users\XX\Desktop\Powershell\Zip, with the name of the text files being the name of the zip files.
Get-ChildItem -Path "C:\Users\XX\Desktop\Powershell\Zip" -Recurse -exclude '*.info' | ForEach { [System.IO.File]::WriteAllText("C:\Users\XX\Desktop\info\"+ $_.Name + ".txt", $_.FullName)}
ontop of that I have the script below which gets the last modified date for the zip files
$path = 'C:\Users\XX\Desktop\Powershell\Zip'
$files = Get-ChildItem $path -Recurse -excluse '*.info'
foreach($file in $files){
$file.lastwritetime
and also this command that gets the computer name
{
(Get-WmiObject Win32_Computersystem).name
}
All these will be in one script, but I need the outputs of the 2nd and 3rd section of the script to append to the text file created in the first section of the script, appending to the appropriate file.
I have tried a couple of commands, the main one being [System.IO.File]::AppendAllText, but I cant seem to get anywhere with this.
Any ideas on the right way I should be doing this?
Thankyou.
You can try this :
$path = 'C:\Users\XX\Desktop\Powershell\Zip'
$files = Get-ChildItem $path -Recurse -Exclude '*.info'
$ComputerName = (Get-WmiObject Win32_Computersystem).name
foreach($file in $files) {
$OutputFilePath = "C:\Users\XX\Desktop\info\"+ $file.Name + ".txt"
[System.IO.File]::WriteAllText($OutputFilePath, $file.FullName)
$file.lastwritetime | Add-Content $OutputFilePath
$ComputerName | Add-Content $OutputFilePath
}