I am iterating through a directory full of sub directories, looking for the newest file at each level.
The code below does this, but I need to be able to add each line/loop of the iterator to an array so that at the end I can output all the data in tabular format for use in Excel.
Any advice on how I can do this?
$arr = get-childItem -Path "\\network location\directory" | select FullName
$res = #()
foreach($fp in $arr)
{
get-childItem -Path $fp.FullName | sort LastWriteTime | select -last 1 Directory, FullName, Name, LastWriteTime
}
Here's a one-liner for you, split onto multiple lines for readability with the backtick escape character. You can copy paste this and it will run as is. The csv file will be created in the folder where you run this from.
dir -rec -directory | `
foreach {
dir $_.fullname -file | `
sort -Descending lastwritetime | `
select -first 1
} | `
export-csv newestfiles.csv
dir is an alias for get-childitem. foreach is an alias for foreach-object. %, gci and ls are even shorter aliases for get-childitem. Note that I am avoiding storing things in arrays, as this is doubling the work required. There is no need to enumerate the folders, and then enumerate the array afterwards as two separate operations.
Hope this helps.
If I understand you correctly, you just need to pipe the results into $res. So adding | %{$res += $_} should do the trick
$arr = get-childItem -Path "\\network location\directory" | select FullName
$res = #()
foreach($fp in $arr)
{
get-childItem -Path $fp.FullName | sort LastWriteTime | select -last 1 Directory, FullName, Name, LastWriteTime | % {$res += $_}
}
$res | % {write-host $_}
Related
$date = get-date -format "MM/dd/yyyy"
$save = Get-ChildItem \\ABC\xyz\wbc | Where-Object { $_.LastWriteTime -gt $date+' 2:30 AM' -and $_.LastWriteTime -lt $date+' 5:35 AM'} | Select Name
for($i=1;$i -eq 62;$i++)
{
Select-String -Path "\\ABC\xyz\wbc\"+$save[$i]+"\"+$save[$i]+"_2"+"\.out" -Pattern "End save of data."
}
Above is the code that I have written till now.
I have to read multiple files under a directory for a pattern of word, some part of the directory is static i.e. \ABC\xyz\wbc after this portion of the path there are folders created serially I just want to capture these directories one by one which are within specific date and time range and inserts it into the path like "\ABC\xyz\wbc\"+$save[0]. If I try $save[0] I am getting output in the format like
Name
----
16471
I am expecting the path to be like \ABC\xyz\wbc\16471\16471_2*.out so that I can use it in select-string
try using Select -ExpandProperty Name instead of Select Name
for the array you may try:
foreach($element in $save) {
'\\ABC\xyz\wbc\{0}\{0}_2.out' -f $element
}
what should return
\ABC\xyz\wbc\16471\16471_2*.out
Try wrapping it in parenthesis and adding .name at the end
$save = (Get-ChildItem \ABC\xyz\wbc | Where-Object { $.LastWriteTime -gt $date+' 2:30 AM' -and $.LastWriteTime -lt $date+' 5:35 AM'}).name
I've got a script that searches for a string ("End program" in this case). It then goes through each file within the folder and outputs any files not containing the string.
It works perfectly when the phrase is hard coded, but I want to make it more dynamic by creating a text file to hold the string. In the future, I want to be able to add to the list of string in the text file. I can't find this online anywhere, so any help is appreciated.
Current code:
$Folder = "\\test path"
$Files = Get-ChildItem $Folder -Filter "*.log" |
? {$_.LastWriteTime -gt (Get-Date).AddDays(-31)}
# String to search for within the file
$SearchTerm = "*End program*"
foreach ($File in $Files) {
$Text = Get-Content "$Folder\$File" | select -Last 1
if ($Text | WHERE {$Text -inotlike $SearchTerm}) {
$Arr += $File
}
}
if ($Arr.Count -eq 0) {
break
}
This is a simplified version of the code displaying only the problematic area. I'd like to put "End program" and another string "End" in a text file.
The following is what the contents of the file look like:
*End program*,*Start*
If you want to check whether a file contains (or doesn't contain) a number of given terms you're better off using a regular expression. Read the terms from a file, escape them, and join them to an alternation:
$terms = Get-Content 'C:\path\to\terms.txt' |
ForEach-Object { [regex]::Escape($_) }
$pattern = $terms -join '|'
Each term in the file should be in a separate line with no leading or trailing wildcard characters. Like this:
End program
Start
With that you can check if the files in a folder don't contain any of the terms like this:
Get-ChildItem $folder | Where-Object {
-not $_.PSIsContainer -and
(Get-Content $_.FullName | Select-Object -Last 1) -notmatch $pattern
}
If you want to check the entire files instead of just their last line change
Get-Content $_.FullName | Select-Object -Last 1
to
Get-Content $_.FullName | Out-String
Here is my dilemma. I have a csv file with two columns
ID,FullFileName
1,Value1
1,Value2
1,Value3
2,Value1
2,Value2
3,Value1
4,Value1
5,Value1
5,Value2
The output I'm looking for is to get an exported csv with two columns in it ID, and FullFilename. The value in FullFileName will contain the matching joined values separated by a pipe delimiter.
But my output i'm trying to get the following:
ID,FullFilename
1,Value1|Value2|Value3
2,Value1|Value2
3,Value1
4,Value1
5,Value1|Value2
I'm not sure how to make powershell search the value in ID and take all of the results and yield them into a single concatenated value with a pipe separation. Any assistance on trying to search the array or join / concatenate array values would be greatly appreciated.
Group-Object is the useful cmdlet that can help you. Grouping the data by ID turns it into:
PS D:\> ipcsv .\t.csv | group id
Count Name Group
----- ---- -----
3 1 {#{ID=1; FullFileName=Value1}, #{ID=1; FullFileName=Value2}, #{ID=1; FullFileName=Value3}}
2 2 {#{ID=2; FullFileName=Value1}, #{ID=2; FullFileName=Value2}}
1 3 {#{ID=3; FullFileName=Value1}}
1 4 {#{ID=4; FullFileName=Value1}}
2 5 {#{ID=5; FullFileName=Value1}, #{ID=5; FullFileName=Value2}}
So you want the Name (= ID) and the Group property, just the FullFileName, joined up:
Import-Csv -Path c:\path\data.csv |
Group-Object -Property ID |
Select-Object #{Name='ID'; Expression={$_.Name}},
#{Name='FullFilename'; Expression={$_.Group.FullFileName -join '|'}} |
Export-Csv -Path C:\Path\out.csv -NoTypeInformation
$InFile = '.\Sample.csv'
$OutFile= '.\New.csv'
$Csv = Import-Csv $InFile | Group-Object ID | ForEach-Object{
[pscustomobject]#{
ID=$_.Name
FullFileName=$_.Group.FullFileName -join '|'
}
}
$Csv
"----------"
$Csv | Export-Csv $OutFile -NoTypeInformation
Get-Content $OutFile
Sample output:
ID FullFileName
-- ------------
1 Value1|Value2|Value3
2 Value1|Value2
3 Value1
4 Value1
5 Value1|Value2
----------
"ID","FullFileName"
"1","Value1|Value2|Value3"
"2","Value1|Value2"
"3","Value1"
"4","Value1"
"5","Value1|Value2"
Edit Just saw you wanted the pipe as delimiter.
Did my best but was to late, anyway here is the code
Instead of Group-Object i am using a HashTable, i find it easy to work with when my data comes from multiple sources.
$CSV = Import-Csv -Delimiter ',' -Path "$env:TEMP\testfolder\csv.txt" #can be .csv or whatever.
$HastTable = #{}
Foreach ($Line in $CSV) {
if (!$HastTable["$($Line.ID)"]) {
$HastTable["$($Line.ID)"] = $Line
}
else {
$HastTable["$($Line.ID)"].FullFileName += "|$($Line.FullFileName)"
}
}
$HastTable.Values | Export-Csv -Delimiter ',' -NoTypeInformation -Path "$env:TEMP\testfolder\newcsv.txt" #can be .csv or whatever.
I guess the question is in the title.
I have a CSV that looks something like
user,path,original_path
I'm trying to find duplicates on the original path, then output both the user and original_path line.
This is what I have so far.
$2 = Import-Csv 'Total 20_01_16.csv' | Group-Object -Property Original_path |
Where-Object { $_.count -ge 2 } | fl Group | out-string -width 500
This gives me the duplicates in Original_Path. I can see all the required information but I'll be danged if I know how to get to it or format it into something useful.
I did a bit of Googleing and found this script:
$ROWS = Import-CSV -Path 'Total 20_01_16.csv'
$NAMES = #{}
$OUTPUT = foreach ( $ROW in $ROWS ) {
IF ( $NAMES.ContainsKey( $ROW.Original_path ) -and $NAMES[$ROW.original_path] -lt 2 )
{ $ROW }
$NAMES[$ROW.original_path] += 1 }
Write-Output $OUTPUT
I'm reluctant to use this because, well first I have no idea what it's doing. So little of the makes any sense to me, I don't like using scripts I can't get my head around.
Also, and this is the more important part, it's only giving me a single duplicate, it's not giving me both sets. I'm after both offending lines, so I can find both users with the same file.
If anyone could be so kind as to lend a hand I'd appreciate it.
Thanks
It depends on the output format you need, but to build on what you already have we can use this to show the records in the console:
Import-Csv 'Total 20_01_16.csv' |
Group-Object -Property Original_path |
Where-Object { $_.count -ge 2 } |
Foreach-Object { $_.Group } |
Format-Table User, Path, Original_path -AutoSize
Alternatively, use this to save them in a new csv-file:
Import-Csv 'Total 20_01_16.csv' |
Group-Object -Property Original_path |
Where-Object { $_.count -ge 2 } |
Foreach-Object { $_.Group } |
Select User, Path, Original_path |
Export-csv -Path output.csv -NoTypeInformation
I need a batch file /script/tool to delete specified files in folder.
I have a folder with a lot of .xml files. It can contain files named difference of only a few characters (indicating the date).
aa_bb_000000001_2015_9_1.xml
aa_bb_000000001_2015_9_15.xml
aa_bb_000000001_2015_10_1.xml
aa_bb_000000002_2015_5_5.xml
aa_bb_000000002_2015_8_14.xml
aa_bb_000000002_2015_10_1.xml
aa_bb_000000005_2015_7_7.xml
.
.
The length of this part is 15 string
aa_bb_000000001
This part represents a date
2015_10_1
I need to delete all the files that part of the name with a date is earliest.
As a result batch should stay only files:
aa_bb_000000001_2015_10_1.xml
aa_bb_000000002_2015_10_1.xml
aa_bb_000000005_2015_7_7.xml
.
.
Here's one solution that's fairly short. To understand how the code works, it would be best to focus on what the Group-Object command does, what regular expressions are, and how they interact with the -match operator:
$Groups = Get-ChildItem "C:\XMLFiles\*.xml" | Group-Object {$_.Name.Substring(0, 15)}
$FilesToKeep = #{}
foreach ($Group in $Groups) {
$MaxDate = "00000000"
foreach ($FileInfo in $Group.Group) {
$FileInfo.name -match "(\d{4})_(\d{1,2})_(\d{1,2}).xml$" | Out-Null
$Date = $Matches[1]+([int]$Matches[2]).ToString("00")+([int]$Matches[3]).ToString("00")
if ($Date -gt $MaxDate) {
$MaxDate = $Date
$FilesToKeep[$Group.Name] = $FileInfo.FullName
}
}
}
Get-ChildItem "C:\XMLFiles\*.xml" | Where-Object {-not $FilesToKeep.ContainsValue($_.FullName)} | Remove-Item