Foreach loop not reading files in numeric order - powershell

I have below files which i am reading using a foreach loop.
$GetGeneratedFiles = Get-ChildItem -Path "C:\Script\LF*.csv" -recurse | % { $_.FullName }
C:\Script\LF_Batch_1.csv
C:\Script\LF_Batch_10.csv
C:\Script\LF_Batch_11.csv
C:\Script\LF_Batch_12.csv
C:\Script\LF_Batch_13.csv
C:\Script\LF_Batch_14.csv
C:\Script\LF_Batch_15.csv
C:\Script\LF_Batch_16.csv
C:\Script\LF_Batch_17.csv
C:\Script\LF_Batch_18.csv
C:\Script\LF_Batch_19.csv
C:\Script\LF_Batch_2.csv
C:\Script\LF_Batch_20.csv
C:\Script\LF_Batch_21.csv etc...upto LF_Batch_.96.csv
Problem is it is reading the files like above not 1,2,3...and so on.
Please need idea how to read in ordered way

Solved using below approach
$GetGeneratedFiles = Get-ChildItem -Path "C:\Script\LF*.csv" -recurse | % { $_.FullName }
$ToNatural = { [regex]::Replace($_, '\d+', { $args[0].Value.PadLeft(20) }) }
$GetGeneratedFiles = $GetGeneratedFiles | Sort-Object $ToNatural
Thanks #vonPryz for the reference.

Another way. It's funny how I just did another answer similar to this. A numeric sort on the names.
echo hi | set-content (1,2,10,20 | % tostring LF_Batch_0\.csv)
dir | sort {[void]($_ -match '\d+'); [int]$matches.0}
Directory: C:\Users\js\foo
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 9/17/2020 9:14 AM 4 LF_Batch_1.csv
-a--- 9/17/2020 9:14 AM 4 LF_Batch_2.csv
-a--- 9/17/2020 9:14 AM 4 LF_Batch_10.csv
-a--- 9/17/2020 9:14 AM 4 LF_Batch_20.csv

Related

I want to import a csv to use as filter in the powershels gci command

I have a csv file with extension and description.
I want to import that file and use it as the filter parameter in a gci command.
But I get no results.
I expect to get a list of the jpg files but get no results.
$extensions=Import-CSV -Path c:\scripts\Media-extension-foto.csv
#$extensions=Import-CSV -Path c:\scripts\Media-extension-foto.csv -header extension
$extensions.extension
$src = "c:\scripts\"
#gci c:\scripts\ -Include $Extensions.extension #-Force -recurse
#gci c:\scripts\ -filter $Extensions.extension #-Force -recurse
gci c:\scripts\|where{$_ -like $extensions.extension}`
my csv file looks like this (just made a small file for testing)
extension,"description"
*.JPEG,JPEG Image
*.JPF,JPEG 2000 Image
*.JPG,JPEG Image
*.JPG_LARGE,Twitter Large JPEG Image
There are jpg files in that folder :
Directory: C:\Scripts
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 23/11/2022 11:02 509592 nieuw9754560_02-10.jpg
-a--- 23/11/2022 11:02 576486 nieuw9754560_02-15.jpg
-a--- 23/11/2022 11:02 641802 nieuw9754560_02-20.jpg
-a--- 23/11/2022 11:01 705702 nieuw9754560_02-25.jpg
-a--- 23/11/2022 11:01 763249 nieuw9754560_02-30.jpg
I've just tested this - I think all you're missing is changing the $_ to $_.Extension for the Get-ChildItem, on the last line.
Hope that helps.
Doesn't directly fix the code but here's another way of getting the result using foreach to iterate through each extension in the array:
foreach($e in $extensions.extension) {
gci c:\scripts\ | where {$_ -like $e}
}

How to split string and rename files in PowerShell?

I want to bulk rename the files in my folder, and all of them have the format of FilenameYeara\b.pdf, for example, TestData2001a.pdf, File2015b.pdf. I want to rename all of them to something like [Yeara\b]Filename, such as [2001a]TestData. The problem is that I don't know how can I split my filename into two parts (actually three if we count the extension, .pdf part), such that I put that second part as the first part of the file name.
Get-ChildItem | Rename-Item {$_.name -replace ‘current’, ’old’ }
How can I achieve this?
This does the regex match "anything, four digits, one character, .pdf" and replaces it with those items in the new ordering.
PS D:\t> gci | ren -newname { $_ -replace '(.*)(\d{4})(.)\.pdf', '[$2$3]$1.pdf' }
Directory: D:\t
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 13/05/2016 02:54 0 File2015b.pdf
-a--- 13/05/2016 02:53 0 TestData2001a.pdf
becomes
Directory: D:\t
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 13/05/2016 02:53 0 [2001a]TestData.pdf
-a--- 13/05/2016 02:54 0 [2015b]File.pdf
(Maybe try it with -Whatif before running for real)
This should get you started
$Matches.Clear()
Get-Item | % {
$_.BaseName -match "(\D+)([0-9]{4}[ab])"
Rename-Item -Path $_.FullName -NewName "$($Matches[2])$($Matches[1])$($_.Extension)"
}

Get-ChildItem -Path in NLog file

If I have this:
Get-ChildItem -Path $BACKUP_REG_PATH >> $TOT_LOG_FILE
I will get a fine list in my log file like this:
Directory: C:\WS\BACKUP\xxxx-Reg
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2016-05-17 11:04 494018 xxxxxx_REGISTRY_EVENTLOG__2016-05-17__11_04_38.reg
-a--- 2016-05-17 11:08 494018 xxxxxx_REGISTRY_EVENTLOG__2016-05-17__11_08_59.reg
-a--- 2016-05-17 11:10 494018 xxxxx_REGISTRY_EVENTLOG__2016-05-17__11_10_31.reg
I want to do this for NLog instead but I don't know how to get a nice list as above.
If I do this:
$regtxt=Get-ChildItem -Path $BACKUP_REG_PATH
$LOGGER.Trace("$regtxt");
I only get a long list on the same row with the Name column.
Any ideas how to solve this?
I don't know NLog but the Trace method probably output the trace in a single line. You could iterate over each item using the Foreach-Object cmdlet and write a trace:
Get-ChildItem -Path $BACKUP_REG_PATH | Foreach-Object {
$LOGGER.Trace($_);
}
Note: This will not output the name column, you may have to trace this yourself.
To solve this, you could pipe the output to the Out-String cmdlet which will give you a single string. You then have to split the string by [System.Environment]::NewLine to get an array to iterate over it:
((Get-ChildItem | select -first 4 | Out-String) -split [System.Environment]::NewLine) |
ForEach-Object {
$LOGGER.Trace($_);
}

Finding a file that has highest number in the filename using powershell

Sorry guys..I am new to powershell. Would be great if someone help with the following scenario:
I have couple of files in a folder c:\test
sample.x.x.1
sample.x.x.2
sample.x.x.3
sample.x.x.4
sample.x.x.5
I want to find the name of the file which has the highest number in its name in the given folder. In the above example, 5 is the highest number and the script should return the output filename as sample.x.x.5
Thanks in advance!
Sorting file names with numbers is quite a problem, as there are two ways. The first one sets them to alphabetical order. That is, 0, 1, 11, 111, 2,... The second one uses natural order. That is, 0, 1, 2, 11, 111.... This is surprisingly tricky and about every third programmer is confused with this.
There's a good answer already, which I'll refer like so,
# Create files 1..5
for($i=1;$i -le 5; ++$i) { set-content sample.x.x.$i -Value $null }
# Tricksy! Create file .10 to confuse asciibetic/natural sorting
set-content sample.x.x.10 -Value $null
ls # Let's see the files
Directory: C:\temp\test
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2015-09-28 10:29 0 sample.x.x.1
-a---- 2015-09-28 10:29 0 sample.x.x.10
-a---- 2015-09-28 10:29 0 sample.x.x.2
-a---- 2015-09-28 10:29 0 sample.x.x.3
-a---- 2015-09-28 10:29 0 sample.x.x.4
-a---- 2015-09-28 10:29 0 sample.x.x.5
# Define helper as per linked answer
$ToNatural = { [regex]::Replace($_, '\d+$', { $args[0].Value.PadLeft(20,"0") }) }
# Sort with helper and check the output is natural result
gci | sort $ToNatural -Descending | select -First 1
Directory: C:\temp\test
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2015-09-28 10:29 0 sample.x.x.10
Alphabetical sorting.
PS C:\Users\Gebb> #("sample.x.x.1", "sample.x.x.5", "sample.x.x.11") | sort
sample.x.x.1
sample.x.x.11
sample.x.x.5
Numerical sorting.
PS C:\Users\Gebb> #("sample.x.x.1", "sample.x.x.5", "sample.x.x.11") |
sort -Property #{Expression={[Int32]($_ -split '\.' | select -Last 1)}}
sample.x.x.1
sample.x.x.5
sample.x.x.11
Largest number.
PS C:\Users\Gebb> #("sample.x.x.1", "sample.x.x.5", "sample.x.x.11") |
sort -Property #{Expression={[Int32]($_ -split '\.' | select -Last 1)}} |
select -Last 1
sample.x.x.11

Don't want some part information in output

Hi Guys I have the following code which search a folder and return any string containing the value down:
filter MultiSelect-String( [string[]]$Patterns ) {
# Check the current item against all patterns.
foreach( $Pattern in $Patterns ) {
# If one of the patterns does not match, skip the item.
$matched = #($_ | Select-String -Pattern $Pattern)
if( -not $matched ) {
return
}
}
# If all patterns matched, pass the item through.
$_
}
Get-ChildItem -recurse | MultiSelect-String 'report','Product1'
So if the code gets the file it displays it like that:
Directory: C:\Users\sarvesh.nundram\Desktop\PMI\RPD_Extract_XML\SQL_tobemigrated2\GROUP1
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 11/21/2013 1:07 PM 133279 Acapulco
What if I don't want these info:
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 11/21/2013 1:07 PM
this?
Get-ChildItem -recurse |
MultiSelect-String 'report','Product1' |
select fullname # or select -expa fullname