I am currently taking a CSV File and renaming it to a .txt file. I Currently save the name as yyyymmdd.txt, I am trying to check the folder for the txt file and append "-01" to the file. (yyyy-mm-dd-01.txt,..-02,..-03,..) each time the script checks it should add 01 to the file. My current problem is the file gets renamed to yyyymmdd.txt01 and if it checks it just puts yyyymmdd.txt11
I've tried a few ways, but have failed to succeed.
$filevalue = 'C:\test\test_notepad.csv'
$path = 'C:\test\'
$file = 'test.txt'
$file2 = 'test_notepade.csv'
$date = Get-Date -Format "yyyy-mm-dd-"
$filename = "$date.txt"
Rename-Item $filevalue $filename
$originalFiles = Get-ChildItem "C:\test\text" -Filter *.txt
$x = 1
ForEach ($originalFile in $originalFiles) {
$x++
Rename-Item -Path $originalFile.FullName -NewName ($originalFile.Name -replace "^", "1")
}
here's a way to do what you want. the stuff before the ForEach-Object is to make a testing file - and to ensure there is only the one since i didn't include any error checking. [grin]
what it does ...
iterates thru 17 times to test the code
gets the file info
splits the .BaseName on the unique _ character
grabs the last item in the resulting array
converts that number string to an [int]
increments it
pads it to two digits
replaces the old seq number in the file name with the new one
renames the file
here's the code ...
$Today = Get-Date -Format 'yyyy-MM-dd'
# delete any existing test file
$Null = Remove-Item -Path "$env:TEMP\$($Today)_*.txt" -ErrorAction SilentlyContinue
# create a file to work with
$Null = New-Item -Path $env:TEMP -Name "$($Today)_07.txt" -ItemType File -ErrorAction SilentlyContinue
# pretend to access the listing 17 times
1..17 |
ForEach-Object {
$FileInfo = Get-ChildItem -LiteralPath $env:TEMP -Filter "$Today*.txt"
$OldSeqNumber = $FileInfo.BaseName.Split('_')[-1]
$NewSeqNumber = '{0:D2}' -f ([int]$OldSeqNumber + 1)
$NewFileName = $FileInfo.Name.Replace("_$OldSeqNumber", "_$NewSeqNumber")
Rename-Item -LiteralPath $FileInfo.FullName -NewName $NewFileName
}
original file name = 2019-05-07_07.txt
last new file name = 2019-05-07_24.txt
Related
I have multiple XML files in different subfolders that I am looking to use Powershell to convert them to CSV and output them using the original file name into a different folder. Example of my code:
$xmlfilepaths = Get-ChildItem -Path "\\path\to\files\" -Recurse | where {$_.Name -like '*.xml'}
foreach ($xmlpath in $xmlfilepaths.FullName)
{
$xmlcontent = Get-Content -Path $xmlpath
}
This part works, but what I would like to do is output these CSV's to another folder, and keep the filename of the original XML file as the file name. Example:
\path\to\files\alpha\testing123.xml -> \path\to\output\files\testing123.csv
\path\to\files\bravo\production789.xml -> \path\to\output\files\production789.csv
My problem is once I am in the 'foreach' how do I "pull" the file name from either the $xmlpath or $xmlfilepaths variable and pass it along so that my file name input is the same as my filename output?
The original file name is contained in the Name property of each object stored in $xmlfilepaths.
Renaming your variables to something more accurate might help make it more obvious what to do:
$xmlFiles = Get-ChildItem -Path "\\path\to\files\" -Recurse -File -Filter *.xml
foreach ($xmlFile in $xmlFiles)
{
$xmlContent = Get-Content -Path $xmlFile.FullName
# !!!
# do what you need to do to convert the XML to CSV
# !!!
# construct new file name and write output file
$newFileName = $xmlFile.Name -replace '.xml$','.csv'
$outputPath = Join-Path '\path\to\output\files' $newFileName
$xmlContent |Set-Content $outputPath
}
To get new filename use following :
$filename = "\path\to\files\alpha\testing123.xml"
$basename = $filename.Substring($Filename.LastIndexOf("\") + 1)
$basename = $basename.SubString(0, $basename.LastIndexOf("."))
Write-Host $basename
$newName = "\path\to\output\files\" + $basename + ".csv"
Write-Host $newname
I was trying to follow the solution given by #StephenP in this post:
Renaming and Moving Files Powershell
I am trying to Move a renamed file to the Output Folder, but it didn't move.
What could go wrong?
Here's my code:
$Files = GCI "$ParentFolder" | ?{$_.Extension -Match "png?"}
$Date = Get-Date -Format "yyyymmddhhmmss"
$Dest = ".\Output"
$Files | ForEach-Object {
# Get the File BaseName and Select the Screen Title only
$FileName = $_.BaseName
$NameCount = $FileName.length
$ScreenTitle = $FileName.substring(0,$NameCount -21)
# Set the New File Name as Variable
$NewFileName = "$($Date)_[$($ScreenTitle)]"
# Start Renaming
$GetName = $_.FullName -replace "$FileName","$NewFileName"
Rename-Item $_ $GetName
# Move the renamed file
Move-Item $GetName -Destination $Dest
}
Thank you for helping :)
First of all, you don't need to rename the file first and then move, because you can do this using Move-Item at the same time.
Use -Filter '*.png' instead of a Where-Object afterwards. The Filter is much more efficient.
Your code does not check if the length of the file BaseName is actually more than 21 characters long, so this $FileName.Substring(0, $NameCount -21) can throw exceptions. However, since you didn't provide any filename examples, I left that in.
Try
$Files = Get-ChildItem -Path $ParentFolder -Filter '*.png' -File
$Date = Get-Date -Format "yyyymmddhhmmss"
$Dest = ".\Output"
$Files | ForEach-Object {
# Get the File BaseName and Select the Screen Title only
$FileName = $_.BaseName
$NameCount = $FileName.Length
# very tricky this.. could throw error if $FileName is less than 21 characters..
$ScreenTitle = $FileName.Substring(0, $NameCount -21)
# Set the New File Name as Variable
$NewFileName = '{0}_[{1}]{2}' -f $Date, $ScreenTitle, $_.Extension
# Move the file with a new name to the destination
$_ | Move-Item -Destination (Join-Path -Path $Dest -ChildPath $NewFileName)
}
As aside, using square brackets in filenames could cause you problems and to do more PowerShell on these files, you need to always remember to use -LiteralPath instead of -Path on cmdlets that support it like Get-ChildItem
i´ve got little bit stucked with my powershell script.
I would like to run through multiple folders, grab files based on their last modified date and copy them to a new location.
There i have to rename them to a specific convention based on it´s original Filename.
What i wrote only runs through the first part and copy files successfully but not rename them afterwards. Of course when i run the script a second time it renames the files...
File convention is:
120_00001_000_002222_202201_20220124_121833_Formular - Copy.pdf
result should be
2222_120_Memory 01-2022_012022.pdf
this is what i got already
$path = "G:\Temp"
$Target = "K:\Local"
$Max_days = "-60" #Max Days past
$Curr_date = Get-Date
$files = get-childitem $Target *.pdf
Get-ChildItem -Path $path -Recurse -Filter 120_*.pdf |
Where-Object {
$_.LastWriteTime `
-gt (Get-Date $Curr_date.AddDays($Max_days)) `
} | ForEach-Object { $_ | Copy-Item -Destination $Target -Force -PassThru }
foreach($pdf in $files)
{
$split = $pdf.name -replace ".pdf" -split "_"
$newname = "$($split[3].TrimStart("0"))_$($split[0])_$("Memory") $($split[4].Substring($split[4].Length - 2, 2))-$($split[5].Substring(0,4))_$($split[4].Substring($split[4].Length - 2, 2))$($split[5].Substring(0,4))$($pdf.Extension)"
write-verbose "Original: $($pdf.name)" -verbose
write-verbose "NewName: $($newname)" -verbose
Rename-Item $pdf.FullName -NewName $newname -verbose
}
Thanks in adavnced
Edited the Question to more precision.
As commented, you could do this in one loop and rename the file while copying.
Try below:
$path = 'G:\Temp'
$Target = 'K:\Local'
$Max_days = -60 # Max Days in the past
$refDate = (Get-Date).AddDays($Max_days).Date # set to midnight
# get the files of interest
Get-ChildItem -Path $path -Recurse -Filter '120_*_*_*_*_*_*_*.pdf' -File |
Where-Object { $_.LastWriteTime -gt $refDate } |
ForEach-Object {
# rename the file to match the new file naming convention
$split = $_.BaseName -split "_"
# just for clarity, using this example:
# '120_00001_000_002222_202201_20220124_121833_Formular - Copy.pdf'
# $split[0] --> 120 used unchanged
# $split[1] --> 00001 unused
# $split[2] --> 000 unused
# $split[3] --> 002222 used without leading zeros
# $split[4] --> 202201 used, only the last two digits (month)
# $split[5] --> 20220124 used, only the first four digits (year)
# $split[6] --> 121833 unused
# $split[7] --> Formular - Copy unused
# these elements are used more than once, so for convenience store in separate variables
$month = $split[4].Substring($split[4].Length - 2, 2)
$year = $split[5].Substring(0,4)
# construct the new file name
$newName = '{0}_{1}_Memory {2}-{3}_{2}{3}{4}' -f $split[3].TrimStart("0"),
$split[0],
$month,
$year,
$_.Extension
# construct the complete target path and filename
$targetFile = Join-Path -Path $Target -ChildPath $newName
# now copy the file with a new name to the target folder
$_ | Copy-Item -Destination $targetFile -Force
}
I've used the -f Format operator to construct the new filename, because I believe this makes the code easier to read.
I did not take into consideration that naming collisions might occur (file with that new name already in the target folder).
If that can happen, you need to tell us what strategy to use.
Perhaps append an index number to the file in brackets like Windows does?
My PowerShell script creates a log file, but when I run the script for the second time, it tells me that the testfile1.log file already exists.
How do I make the script if it finds testfile1.log, it creates testfile2.log, and if this also exists, it creates testfile3.log, and so on..
New-Item -Path $path -Name "testfile1.log" -ItemType "file"
You could do it this way, first get all the files in the desired path and sort them by the ending digits on their name. If no files are found create the testfile1.log, if there were files found, get the last sorted file (the one with the highest ending digit) extract the ending digits and add +1 to the count and use it to create the new file.
$files = Get-ChildItem $path -Filter testfile*.log | Sort-Object {
$_.BaseName -replace '\D' -as [int]
}
if(-not $files)
{
New-Item -Path $path -Name "testfile1.log" -ItemType File
}
else
{
[int]$number = $files[-1].BaseName -replace '\D'
$number++
New-Item -Path $path -Name "testfile$number.log" -ItemType File
}
An alternative method, based on this answer could be
$path = 'D:\Test'
$log = 'testfile'
$index = ((Get-ChildItem -Path $path -Filter "$log*.log" -File |
Where-Object { $_.BaseName -match "$log\d+$" } |
Select-Object #{Name = 'index'; Expression = {[int]($_.BaseName -replace '\D')}}).index |
Measure-Object -Maximum).Maximum + 1
# create the new file
New-Item -Path (Join-Path -Path $path -ChildPath "$log${index}.log") -ItemType File
A concise solution that also builds on this answer (see there for an explanation of the core technique):
$path = '.' # Output dir.
$nameTemplate = 'testfile{0}.log' # {0} is the sequence-number placeholder
New-Item -ItemType File -Path $path -Name (
$nameTemplate -f (1 + (
# Find all existing log files
Get-ChildItem (Join-Path $path $nameTemplate.Replace('{0}', '*')) |
Measure-Object -Maximum {
# Extract the embedded sequence number.
$_.Name -replace [regex]::Escape($nameTemplate).Replace('\{0}', '(\d+)'), '$1'
}
).Maximum)
) -WhatIf
Note: The -WhatIf common parameter in the command above previews the operation. Remove -WhatIf once you're sure the operation will do what you want.
Note:
The above uses a complex -replace operation to reliably extract the sequence number from existing file names; if you know that that only one number is present in each given file name, $_.BaseName -replace '\D' (removing all non-digit characters) will do in the Measure-Object call above.
If you wanted to use zero-padded, fixed-width sequence numbers, you can adjust (all occurrences of) the {0} placeholder accordingly; e.g, to create sequence numbers 01, 02, ... 99, use {0:00} - see the Composite formatting help topic, which describes the string formatting language also used by PowerShell's -foperator
I have many file in a folder, I would like to check the existing and matching of the file with variable that I initialize. Then, if the file exit and match, I want to get some information from the files (many file), then create a new file depend on how many file exist and match.
I tried this code, I can check the matching and existing file. I can create a new file and get the information from the file, but I only can create 1 file.
The information that I get from the file, each file is different.
$ID = "123"
$Pre = "ABC"
$Path = "C:\Folder"
$PO = Get-ChildItem -Path $Path
foreach ($File in $PO) {
if (($File.Name -match $ID) -and ($File.Name -match $Pre)) {
Write-Host ">>POfile Found: $File"
} else {
Write-Host ">>Check Again!"
}
}
# CREATE FILE
$Jb_Path = "C:\Folder\Jb"
## GET INFORMATION
$count = 1
$Get_PO = Get-ChildItem -Path $Path\$File -File -Recurse
$POfile = Get-Random -InputObject $Get_PO -Count $count
Write-Host ">>Selected POfile= $POfile"
$FilteredContents = Get-Content $POfile | Where-Object {$_ -like "*;INFO*"}
$Get_INFO = $FilteredContents.Substring(5,2)
## NEW FILE
New-Item -Path $Jb_Path\NEW_$Pre$ID-$Get_INFO.txt -Force
In the section # CREATE FILE you are referencing the variable $File which has the last value iterated in the previous foreach (even if it didn't match the if condition).
Asuming the $Pre is for prefix and comes first in a file name simply do a
Get-ChildItem "$Path\*$Pre*$ID*"
to only get file names for your criteria.
As $File contains only one file name a Get-Random doesn't make sense, especially as it might not contain a line with ;INFO
Assuming the two characters to extract are in front of ;INFO this untested script might do:
$Pre = "ABC"
$ID = "123"
$Path = "C:\Folder"
$Jb_Path= "C:\Folder\Jb"
Get-ChildItem "$Path\*$Pre*$ID*" | Get-Content |
Select-String -Pattern '^.....(..).*;INFO' |
Get-Random | ForEach-Object {
$NewFile = Join-Path $Jb_Path ('NEW_{0}{1}-{2}.txt' -f $Pre,
$ID,$_.Matches.Groups[1].Value)
New-Item -Path $NewFile -ItemType File -Force -WhatIf
}
It will only output what it would do without the -WhatIf parameter.
If no file matching the criteria and RegEx pattern is found it will silently continue.
If my assumptions led me wrong, enhance your question be editing it with more details.