I am trying to move files based on a list of prefix from a text file to match a portion of the actual files which are dynamically generated.
Example of prefix in text file:
103 1stCity
25 2ndCity
302 3rdCity
There are no commas and each city is a new line in the text file (not CSV format).
Example of files to search:
103 1stCity 20170901 12387.txt
129 OtherCity 20170905 354568.txt
Here is what I have:
$file_list = Get-Content "P:\some\path\to\PrefixOfClientNames.txt"
$search_folder = "J:\FilesToSearch_SomeStayHere"
$destination_folder = "J:\SomeFilesGetMovedHere"
foreach ($file in $file_list) {
$file_to_move = Get-ChildItem -Path $search_folder |
Where-Object { $_.Name -like $file }
if ($file_to_move) {
Move-Item $file_to_move $destination_folder -WhatIf
}
If all matching files should go to the same destination folder you'd build a regular expression from the prefix file and anchor it at the beginning of the string:
$prefixes = Get-Content 'P:\some\path\to\PrefixOfClientNames.txt' |
ForEach-Object { [regex]::Escape($_) }
$pattern = '^{0}' -f ($prefixes -join '|')
then use a pipeline for moving matching files:
Get-ChildItem -Path $search_folder | Where-Object {
$_.Name -match $pattern
} | Move-Item -Destination $destination_folder -WhatIf
Other method
$file_list = Get-Content "C:\Temp\prefix.txt" | %{$_ + '*'}
$search_folder = "C:\Temp\searchfolder"
$destination_folder = "C:\Temp\searchfolder"
Get-ChildItem $search_folder -file -Recurse | %{
$name=$_.BaseName
$fullname=$_.FullName
if (($file_list | where { $name -like $_} | select -First 1).Count -gt 0)
{
Move-Item $fullname $destination_folder -WhatIf
}
}
Related
I need to sort words alphabetically from a specific file and put them into 26 text files named A.txt, B.txt and so on up to Z.txt.
$Content = Get-Content ".\\1.txt"
$Content = ($Content.Split(" .,:;?!/()\[\]{}-\`\`\`"")|sort)
$linecount = 0
$filenumber = 0
$destPath = "C:\\test"
$destFileSize = 26
$Content |Group {$_.Substring(0,1).ToUpper()} |ForEach-Object {
$path = Join-Path $destPath $_.Name
$\_.Group |Set-Content $path
}
$Content | % {
Add-Content $destPath$filenumber.txt "$\_"
$linecount++
If ($linecount -eq $destFileSize) {
$filenumber++
$linecount = 0
}
}
You could do something like this, but this also could mean some files may not be written if there are no words beginning with a certain letter found in the file:
$destPath = "D:\test"
(Get-Content -Path 'D:\Test\Lorem.txt' -Raw) -split '\W' -ne '' |
Group-Object {$_.Substring(0,1).ToUpperInvariant()} |
Where-Object {$_.Name -cmatch '[A-Z]'} | ForEach-Object {
$_.Group | Sort-Object | Set-Content -Path (Join-Path -Path $destPath -ChildPath ('{0}.txt' -f $_.Name))
}
If you always want exactly 26 files even if some may contain nothing, use this instead
$destPath = "D:\test"
$wordGroups = (Get-Content -Path 'D:\Test\Lorem.txt' -Raw) -split '\W' -ne '' |
Group-Object {$_.Substring(0,1).ToUpperInvariant()}
foreach ($char in ('ABCDEFGHIJKLMNOPQRSTUVWXYZ' -split '(.)' -ne '')) {
$outFile = Join-Path -Path $destPath -ChildPath ('{0}.txt' -f $char)
$group = $wordGroups | Where-Object { $_.Name -eq $char }
if ($group) { $group.Group | Sort-Object | Set-Content -Path $outFile } # output the found words
else { $null | Set-Content -Path $outFile } # or create an empty file
}
The Where-Object {$_.Name -cmatch '[A-Z]'} clause makes it ignore words starting with some other character than A to Z
In a directory, there are files with the following filenames:
ExampleFile.mp3
ExampleFile_pn.mp3
ExampleFile2.mp3
ExampleFile2_pn.mp3
ExampleFile3.mp3
I want to iterate through the directory, and IF there is a filename that contains the string '_pn.mp3', I want to test if there is a similarly named file without the '_pn.mp3' in the same directory. If that file exists, I want to remove it.
In the above example, I'd want to remove:
ExampleFile.mp3
ExampleFile2.mp3
and I'd want to keep ExampleFile3.mp3
Here's what I have so far:
$pattern = "_pn.mp3"
$files = Get-ChildItem -Path '$path' | Where-Object {! $_.PSIsContainer}
Foreach ($file in $files) {
If($file.Name -match $pattern){
# filename with _pn.mp3 exists
Write-Host $file.Name
# search in the current directory for the same filename without _pn
<# If(Test-Path $currentdir $filename without _pn.mp3) {
Remove-Item -Force}
#>
}
enter code here
You could use Group-Object to group all files by their BaseName (with the pattern removed), and then loop over the groups where there are more than one file. The result of grouping the files and filtering by count would look like this:
$files | Group-Object { $_.BaseName.Replace($pattern,'') } |
Where-Object Count -GT 1
Count Name Group
----- ---- -----
2 ExampleFile {ExampleFile.mp3, ExampleFile_pn.mp3}
2 ExampleFile2 {ExampleFile2.mp3, ExampleFile2_pn.mp3}
Then if we loop over these groups we can search for the files that do not end with the $pattern:
#'
ExampleFile.mp3
ExampleFile_pn.mp3
ExampleFile2.mp3
ExampleFile2_pn.mp3
ExampleFile3.mp3
'# -split '\r?\n' -as [System.IO.FileInfo[]] | Set-Variable files
$pattern = "_pn"
$files | Group-Object { $_.BaseName.Replace($pattern,'') } |
Where-Object Count -GT 1 | ForEach-Object {
$_.Group.Where({-not $_.BaseName.Endswith($pattern)})
}
This is how your code would look like, remove the -WhatIf switch if you consider the code is doing what you wanted.
$pattern = "_pn.mp3"
$files = Get-ChildItem -Path -Filter *.mp3 -File
$files | Group-Object { $_.BaseName.Replace($pattern,'') } |
Where-Object Count -GT 1 | ForEach-Object {
$toRemove = $_.Group.Where({-not $_.BaseName.Endswith($pattern)})
Remove-Item $toRemove -WhatIf
}
I think you can get by here by adding file names into a hash map as you go. If you encounter a file with the ending you are interested in, check if a similar file name was added. If so, remove both the file and the similar match.
$ending = "_pn.mp3"
$files = Get-ChildItem -Path $path -File | Where-Object { ! $_.PSIsContainer }
$hash = #{}
Foreach ($file in $files) {
# Check if file has an ending we are interested in
If ($file.Name.EndsWith($ending)) {
$similar = $file.Name.Split($ending)[0] + ".mp3"
# Check if we have seen the similar file in the hashmap
If ($hash.Contains($similar)) {
Write-Host $file.Name
Write-Host $similar
Remove-Item -Force $file
Remove-Item -Force $hash[$similar]
# Remove similar from hashmap as it is removed and no longer of interest
$hash.Remove($similar)
}
}
else {
# Add entry for file name and reference to the file
$hash.Add($file.Name, $file)
}
}
Just get a list of the files with the _pn then process against the rest.
$pattern = "*_pn.mp3"
$files = Get-ChildItem -Path "$path" -File -filter "$pattern"
Foreach ($file in $files) {
$TestFN = $file.name -replace("_pn","")
If (Test-Path -Path $(Join-Path -Path $Path -ChildPath $TestFN)) {
$file | Remove-Item -force
}
} #End Foreach
I have many folder
ex: folder1,folder2,folder3... about folder100
In those folder have many files
ex: 1.html,2.html,3.html,4.html...about 20.html
I want to replace some text in those all html file in all folder
but not all text i want to replace is same.
ex:(for 1.html, i want to replace ./1_files/style.css to style.css) and (for 2.html, i want to replace ./2_files/style.css to style.css)....
So i try something like this and it work well
Get-ChildItem "*\1.html" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace './1_files/style.css', 'style.css' | Set-Content $_
}
Get-ChildItem "*\2.html" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace './2_files/style.css', 'style.css' | Set-Content $_
}
Get-ChildItem "*\3.html" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace './3_files/style.css', 'style.css' | Set-Content $_
}
Get-ChildItem "*\4.html" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace './4_files/style.css', 'style.css' | Set-Content $_
}
but i have to write many of those code "\4.html" "\5.html" "*\6.html" ...
i try this but it do not work
Do {
$val++
Write-Host $val
$Fn = "$val.html"
Get-ChildItem "*\$Fn" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace './$val_files/style.css', 'style.css' |
Set-Content $_
}
} while($val -ne 100)
Please show me correct way to do..loop replace
thanks you
Assuming all your subfolders can be found inside one source folder path, you can do below to do the replacement in all those files:
# the path where all subfolders and html files can be found
$sourcePath = 'X:\Wherever\Your\Subfolders\Are\That\Contain\The\Html\Files'
Get-ChildItem -Path $sourcePath -Filter '*.html' -Recurse -File |
# filter on html files that have a numeric basename
Where-Object {$_.BaseName -match '(\d+)'} | ForEach-Object {
# construct the string to repace and escape the regex special characters
$replace = [regex]::Escape(('./{0}_files/style.css' -f $matches[1]))
# get the content as one single multiline string so -replace works faster
(Get-Content -Path $_.FullName -Raw) -replace $replace, 'style.css' |
Set-Content -Path $_.FullName
}
I want to filter lines according to specific word from file in powershell.
For example: the files animal1.txt and animal2.txt. Every file contain lines
dog
cat
dog
dog
bird
Then I want to create two derived files:
animal1_bak.txt that stores lines which contains the word 'dog' from animal1.txt
animal2_bak.txt that stores lines which contains the word 'dog' from animal2.txt
What I found on web is:
Select-String -Path "*.*" -Pattern "dog"
But the instruction to create the derived word is missing.
What can I do?
You can first get-content and use set-content like below
Get-Content -Path E:\KTDocs\Scripts\animal1.txt | where {
$_ -like '*dog*'} |Set-Content e:\animalbak.txt
try Something like this
select-string -Path "c:\temp\animal*.txt" -Pattern "dog" | Group Path | %{
$FileName="{0}_bak.txt" -f $_.Name
$_.Group.Line | select -unique | Out-File $FileName -Append
}
$folderpath = "D:\AnimalFolder" # your folder path here
$Allfiles = Get-ChildItem -Path $folderpath -Recurse -File -Force -ErrorAction SilentlyContinue |where{$_.Name -match ".txt"} |Select-Object -expandproperty FullName
foreach($filepath in $allfiles)
{
$Data = get-content $filepath
foreach($line in $data)
{
if($line -match "dog")
{
$newpath = $filepath.split('.')[0]
$getfullpath = $newpath + "_bak.txt"
$line | out-file $getfullpath -append
}
}
}
$getFiles = Get-ChildItem -Path $readDir -File -Include "*.doc","*.docx","*.xlsx"-Recurse | %{
if(($_ -match "\.doc$") -or ($_ -match "\.docx$")){
$Doc = $word.Documents.Open($_.fullname)
$nameDoc = $fileSaveLoc + $_.Name.Replace(".docx",".txt").replace(".doc",".txt")
$Doc.saveas([ref] $nameDoc, [ref] 5)
$Doc.close()
if((Get-ChildItem "I:\temp\").length -ne 0){
$locations = (Get-Item "I:\temp\"), (Get-ChildItem "I:\temp\" -Directory -recurse) | % {
Get-ChildItem -File $_.FullName | Select-String -List -Pattern '^\d{3}-?\d{2}-?\d{4}$' |
% Path
}
if($locations -ne $null){
$locations | out-file "I:\temp\SSN_FILES.txt"
#Get-ChildItem "I:\temp\" -exclude "fullpath.txt","SSN_FILES.txt" | remove-item
}else{
Get-ChildItem "I:\temp\" -exclude "fullpath.txt","SSN_FILES.txt" | remove-item
}
}
}
elseif($_ -match "\.xlsx$"){
$workbook = $excel.Workbooks.Open($_.FullName)
$csvFilePath = "I:\temp\" + $_.Name.Replace(".xlsx",".csv")
#$csvFilePath = $_.FullName -replace "\.xlsx$", ".csv"
$workbook.SaveAs($csvFilePath, [Microsoft.Office.Interop.Excel.XlFileFormat]::xlCSV)
$workbook.Close()
if((Get-ChildItem "I:\temp\").length -ne 0){
$locations = (Get-Item "I:\temp\"), (Get-ChildItem "I:\temp\" -Directory -recurse) | % {
Get-ChildItem -File $_.FullName | Select-String -List -Pattern '^\d{3}-?\d{2}-?\d{4}$' |
% Path
}
if($locations -ne $null){
$locations | out-file "I:\temp\SSN_FILES.txt"
#Get-ChildItem "I:\temp\" -exclude "fullpath.txt","SSN_FILES.txt" | remove-item
}else{
Get-ChildItem "I:\temp\" -exclude "fullpath.txt","SSN_FILES.txt" | remove-item
}
}
}
}
So this basically says:
check for a file matching doc/docx/xlsx
convert them into a file that can be parsed through
parse through each file at every iteration and compare it to a regex
if the regex is not null, then output it to a file with the file path
otherwise, delete it and anything else that was created except for two files
restart the process at the next file
Now the problem I am encountering is that the files aren't being deleted. I can't get them to be removed when they are created, when I know they don't match the regex. Setting ($locations -eq $true) doesn't solve that issue because it never goes into the first conditional statement.
The folder should contain only the two files that were created and possibly the ones that match the regex.