Using select-string to output list from 1000+ files - string

I'm trying to get a specific string from a text file and output it and the filename to a separate txt file. I have tried the following but get an error message. I've looked for answers but haven't found any. Any help is appreciated.
I Should add that I'm fairly new to Powershell.
Select-String -Path C:\temp\test1.txt -Pattern 'batch3'|ForEach-Object {
#' File name - {0} {1}
..................... '# -f $_.Name, (Get-Content $_.FullName -Raw) }
| Out-File 'C:\temp\test_output.txt'
It works if I substitute Select-String for Get-Content. The problem then is that it takes the entire content of the file and that is not what I need.
error message:
Get-Content : Cannot bind argument to parameter 'Path' because it is null.
At line:6 char:29
+ '# -f $.Name, (Get-Content $.FullName -Raw)
+ ~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-Content], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.GetContentCommand

Select-String does not output a property FullName. However, there is Path property. Try this:
(Get-Content $_.Path -Raw)
This will fix the error, but if you want to output just a line with the string you found, not the entire file contents, remove Get-Content and try this:
Select-String -Path C:\temp\test1.txt -Pattern 'batch3'|ForEach-Object {
#' File name - {0} {1}
..................... '# -f $_.Filename, $_.Line }
| Out-File 'C:\temp\test_output.txt'

Related

How can I replace a string in multiple files with a value from a list, sequentially in Powershell?

Lets say I have a bunch of text files with people's names, that all have this as the content:
number
I want to replace "number" with a value from a CSV or text file, sequentially, and based on the file name. CSV has two columns, name and number:
Joe 5551011000
Gary 5551011001
Clark 5551011002
So I want to find the text file named Joe, and replace the "number" with "5551011000", and the text file named Gary, and replace "number" with "5551011001".
Thank you!
I didn't get too far:
Get-ChildItem "C:\test\*.txt" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace 'changeme', 'MyValue' | Set-Content $_
}
This gets me party there, but I don't know how to find a specific file, then replace "number" in that file with the correct value that matches the name.
I also tried a different approach, with manual entry, and it works, but I need it to just be automated:
get-childitem c:\Marriott -recurse -include *.txt |
select -expand fullname |
foreach {
$new = Read-Host 'What is the new value you want for ' $_
(Get-Content $_) -replace 'number',$new |
Set-Content $_
}
I would convert your CSV to a hashtable, then this gets pretty simple.
$ReplaceHT = #{}
Import-Csv c:\path\to\file.csv -Delimiter ' ' -Header 'FileName','Number' | ForEach-Object {$ReplaceHT.add($_.FileName,$_.Number)}
Get-ChildItem c:\Marriott -recurse -include *.txt -PipelineVariable 'File'|Where{$_.name -in $ReplaceHT.Keys} |ForEach-Object{
(Get-Content $File.FullName) -replace 'changeme', $ReplaceHT[$File.Name] | Set-Content $File.FullName
}

Date content comparison if it is greater then todays date

I am looking for some script in PowerShell that will compare the date present in an inside text file as content and compare if that date is >today`+15 days then print the file name.
Also, if that script can compare the date as mentioned above along with the other string if both conditions are matching then print the file name.
The below command gives me the output for those which have matching string same as hello and was created 30 days back. But now I want to fulfill the above two conditions no matter when the file was created.
Get-ChildItem -Path C:\Users\vpaul\Downloads\functional-script\*.txt -Recurse | Select-String -Pattern 'Hello', 'Hell' | Where CreationTime -lt (Get-Date).AddDays(-6)| Export-Csv C:\Users\vpaul\Downloads\functional-script\File_Name.csv -NoTypeInformation
The output from Select-String doesn't have a CreationTime property, which is why your filtering fails - CreationTime doesn't resolve to anything so it's always "less than" any value you provide.
Either do the filtering on CreationTime before piping to Select-String:
Get-ChildItem ... |Where-Object CreationTime -lt (Get-Date).AddDays(-6) |Select-String 'Hell' | ...
Or use the Path property on the output from Select-String to look up the files attributes again:
Get-ChildItem ... |Select-String 'Hell' |Where-Object {(Get-ItemPropertyValue -LiteralPath $_.Path -Name CreationTime) -lt (Get-Date).AddDays(-6)} |...
Since it looks like you're trying to get and compare a date from a matched text string inside the file, as well as CreationTime file attribute... +15 Days and -6 Days respectively...
Example Text file Content:
Hello 4/1/2021
You could try something similar to this:
$ALL_RECURSED_TXTs = Get-ChildItem -Path '[Folder to Recurse]\*.txt' -Recurse | Where-Object { $_.CreationTime -lt (Get-Date).AddDays(-6) };
foreach($File in $ALL_RECURSED_TXTs) {
Get-Content -Path $File.FullName | Select-String -Pattern 'Hello', 'Hell' |
ForEach-Object {
# Find a RegEx match for your Date String that is in the File
$_ -match 'Hello\s(\d+\/\d+\/\d{4}).*' | Out-Null;
if((Get-date($matches[1])) -gt ((Get-Date).AddDays(15))) {
"$($File.FullName)" | Out-File -FilePath '[Path to Output]\MyPrintedFileNames.txt' -Append;
}
}
}
If you want to see your matched lines in your outfile...
"$_ : $($File.FullName)" | Out-File -FilePath '[Path to Output]\MyPrintedFileNames.txt' -Append;
"but now I want to fulfill the above two conditions no matter when the file was created."
Scrap the Where-Object filter on Get-ChildItem if you want all txt files.
Edit: Getting confused again. Lol. If your txt file date string is not on same line as your "Hello|Hell" it'll get more complex. Good Luck!

How can I remove characters from a line in a text file without renaming the file?

I want to be able to take a file in a folder and write it to a text file in batch or PowerShell. The output in the text file should have FileName, NewFileName, DateModified. The FileName is what the file was named before it was ingested in a program and output. NewFileName is the name of the file that was output from the program and stored in the output folder.
The PowerShell script below is what I have used to get the name and date modified of the files to display in a text file.
Get-ChildItem -Path D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Audio\ -Recurse |
Select-Object #{n='File'; e={$_.Name + "," + $_.LastWriteTime}} |
Out-File "D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Audio\Log.txt"
Get-ChildItem -Path D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Video\ -Recurse |
Select-Object #{n='File'; e={$_.Name + "," + $_.LastWriteTime}} |
Out-File "D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Video\Log.txt"
However, the output I want is the original file name that was ingested.
FileName before ingested in program: Some_Name_file.mxf
NewFileName after ingested: random_exactly_37_characters_FileName.mxf_random_exactly_11_characters
The original file does not exist anymore, so I could have just added the path of that and said to write its name. So is there a way I can remove those 37 characters before the file name and the last 11 characters at the end of the filename and write that down on the same text file. I do not want to rename the NewFileName because it would change the date modified parameters.
This assumes that the underscores and the file extension are included in what you want to remove, and you always want to remove 37 leading characters and 11 following characters. You can do this using the Substring property of your file name.
$audioFiles = Get-ChildItem -Path D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Audio\ -File -Recurse |
Select-Object #{n='File';e={$_.Name.Substring(37,($_.Name.Length-37-11))}},LastWriteTime
$audioFiles | Export-Csv "D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Audio\Log.csv" -NoTypeInformation
$videoFiles = Get-ChildItem -Path D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Video\ -File -Recurse |
Select-Object #{n='File';e={$_.Name.Substring(37,($_.Name.Length-37-11))}},LastWriteTime
$videoFiles | Export-Csv "D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Video\Log.csv" -NoTypeInformation
Keep in mind that substring character indexes start at 0 and end at Length-1.
An alternative is to use the -replace operator, which uses regex for string matching.
$audioFiles = Get-ChildItem -Path D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Audio\ -File -Recurse |
Select-Object #{n='File';e={$_.Name -replace '^.{37}(.*).{11}$','$1'}},LastWriteTime
$audioFiles | Export-Csv "D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Audio\Log.csv" -NoTypeInformation
$videoFiles = Get-ChildItem -Path D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Video\ -File -Recurse |
Select-Object #{n='File';e={$_.Name -replace '^.{37}(.*).{11}$','$1'}},LastWriteTime
$videoFiles | Export-Csv "D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Video\Log.csv" -NoTypeInformation
The . matches any non-newline character.
{N} matches the previous mechanism (. in this case) N times.
(.*) is a capture group ($1) that matches any character until there are exactly 11 characters left.
^ denotes the beginning of the string.
$ denotes the end of string.
Essentially, the entire filename gets replaced with just the middle substring.

Powershell - Hide error message from displaying, occuring on line 3

I need help hiding the below error message that occurs when Powershell doesn't find an Excel instance running (or a means of somehow circumventing it):
Get-Process : Cannot find a process with the name "excel". Verify the
process name and call the cmdlet again. At run.ps1:3 char:24
+ $before = #(get-process <<<< excel | %{$_.Id} )
+ CategoryInfo : ObjectNotFound: (excel:String) [Get-Process], ProcessCommandException
+ FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
Line 3-5 of my code is as follows:
$before = #(get-process excel | %{$_.Id} )
$excel=new-object -com excel.application
$excelId = get-process excel | %{$_.Id} | ?{$before -notcontains $_}
Maybe you could do the following?
Get-Process Excel -ErrorAction SilentlyContinue | %{ $_.Id }
Or this?
Get-Process | ?{ $_.name -eq "excel" } | %{ $_.Id }

How to search a string in multiple files and return the names of files in Powershell?

I have started learning powershell a couple of days ago, and I couldn't find anything on google that does what I need so please bear with my question.
I have been asked to replace some text strings into multiple files. I do not necessarily know the extension of the possible target files and I don't know their location either. So far I have managed to recursively browse into the directory (get-ChildItem -recurse) and find the string I was looking for with get-content and select-string:
Get-ChildItem -recurse | Get-Content | Select-String -pattern "dummy"
The problem is, I can see the occurences of the text I am looking for, but I don't know how to tell PS to return the path and the name for every matching files as well.
How can I get the name and location of the files that contains the expression I am looking for?
This should give the location of the files that contain your pattern:
Get-ChildItem -Recurse | Select-String "dummy" -List | Select Path
There are a variety of accurate answers here, but here is the most concise code for several different variations. For each variation, the top line shows the full syntax and the bottom shows terse syntax.
Item (2) is a more concise form of the answers from Jon Z and manojlds, while item (1) is equivalent to the answers from vikas368 and buygrush.
List FileInfo objects for all files containing pattern:
Get-ChildItem -Recurse filespec | Where-Object { Select-String pattern $_ -Quiet }
ls -r filespec | ? { sls pattern $_ -q }
List file names for all files containing pattern:
Get-ChildItem -Recurse filespec | Select-String pattern | Select-Object -Unique Path
ls -r filespec | sls pattern | select -u Path
List FileInfo objects for all files not containing pattern:
Get-ChildItem -Recurse filespec | Where-Object { !(Select-String pattern $_ -Quiet) }
ls -r filespec | ? { !(sls pattern $_ -q) }
List file names for all files not containing pattern:
(Get-ChildItem -Recurse filespec | Where-Object { !(Select-String pattern $_ -Quiet) }).FullName
(ls -r filespec | ? { !(sls pattern $_ -q) }).FullName
This is how I would do it, you don't need get-content:
ls -r | Select-String dummy | select line,path
or
ls -r | Select-String dummy | fl *
To see what the different properties are...
This is faster. The second argument is -filter:
ls -r . *.bat | select-string netsh
ls -r -path . -filter *.bat | select-string netsh
This will display the path, filename and the content line it found that matched the pattern.
Get-ChildItem -Path d:\applications\*config -recurse | Select-String -Pattern "dummy"
Pipe the content of your
Get-ChildItem -recurse | Get-Content | Select-String -pattern "dummy"
to fl *
You will see that the path is already being returned as a property of the objects.
IF you want just the path, use select path or select -unique path to remove duplicates:
Get-ChildItem -recurse | Get-Content | Select-String -pattern "dummy" | select -unique path
I modified one of the answers above to give me a bit more information. This spared me a second query later on. It was something like this:
Get-ChildItem `
-Path "C:\data\path" -Filter "Example*.dat" -recurse | `
Select-String -pattern "dummy" | `
Select-Object -Property Path,LineNumber,Line | `
Export-CSV "C:\ResultFile.csv"
I can specify the path and file wildcards with this structures, and it saves the filename, line number and relevant line to an output file.
Get-ChildItem -r | ? {$_.psiscontainer -eq $false} | ? {gc $_.pspath |select-string -pattern "dummy"}
This will give you the full details of all files
To keep the complete file details in resulting array you could use a slight modification of the answer posted by vikas368 (which didn't seem to work well with the ISE autocomplete):
Get-ChildItem -Recurse | Where-Object { $_ | Select-String -Pattern "dummy" }
or in short:
ls -r | ?{ $_ | Select-String -Pattern "dummy" }
If you search into one directory, you can do it:
select-string -Path "c:\temp\*.*" -Pattern "result" -List | select Path
This will display a list of the full path to each file that contains the search string:
foreach ($file in Get-ChildItem | Select-String -pattern "dummy" | Select-Object -Unique path) {$file.path}
Note that it doesn't display a header above the results and doesn't display the lines of text containing the search string. All it tells you is where you can find the files that contain the string.
With PowerShell, go to the path where your files are and then type this command and replace ENTER THE STRING YOU SEARCH HERE (but keep the double quotes):
findstr /S /I /M /C:"ENTER THE STRING YOU SEARCH HERE" *.*
Have a nice day šŸ™‚
This Scrit worked to find a specific file in a 3 000 000
Param
(
#Define o parametro do ano a eliminar "2020"
$DateDel = '2019',
#Define o parametro do registro do ficheiro "_800" ou "_800sm" ou "_200"
$ResFile1 = '_200',
$ResFile2 = '_800',
$ResFile3 = '_800sm',
#Define o parametro da terminacao do ficheiro "_800.jpg" ou "_800sm.jpg" ou "_200.jpg"
$TypeFile = '.jpg',
#Define o parametro de onde se localizado ficheiro "C:\users\Luis.Cunha\Desktop\LuisCunha\TarefaScript\TesteFinal\TesteScript1"
$HomePath = 'C:\Users\Luis.Cunha\Desktop\LuisCunha\TarefaScript'
)
#Inicia transcriƧao de toda informaĆ§Ć£o para o ficheiro .log indicado
Start-Transcript -Path $HomePath\CountDelItems.log -NoClobber -Append
Get-ChildItem $HomePath -Recurse -File | Measure-Object | %{$_.Count}
#o Get vai buscar o ficheiro com a data e a terminacao definidas no $homepath e $tipofich atraves do caminho indicado no $path
#depois confirma os valores que foram removidos com o verbose
Get-Childitem -Path $HomePath -Recurse -force | Where-Object { !$_.PSIsContainer -and $_.name -like "????$DateDel*$ResFile1$TypeFile" } | Measure-Object | %{$_.Count}
#Get-Childitem -Path $HomePath -Recurse -force | Where-Object { !$_.PSIsContainer -and $_.name -like "????$DateDel*$ResFile1$TypeFile" } | Remove-Item -Verbose -Force
Get-ChildItem $HomePath -Recurse -File | Measure-Object | %{$_.Count}
#Termina transcriĆ§Ć£o
Stop-Transcript

Resources