I'm trying to search through a directory of files and pull out all the file paths that have the pattern. Then loop through each file and search for another pattern of text. It works if I manually do:
Select-String -Path "C:\inetpub\mailroot\Badmail-Archive\003c908531613052021000000A2.BAD" -Pattern ('Final-Recipient') | Select -ExpandProperty line
It does not if I do it in the loop:
$FileList = Get-ChildItem "C:\inetpub\mailroot\Badmail-Archive" -Filter *.BAD | Select-String -Pattern 'Diagnostic-Code: smtp;550 5.1.1' | Select-Object Path
$FileList += Get-ChildItem "C:\inetpub\mailroot\Badmail-Archive" -Filter *.BAD | Select-String -Pattern 'Diagnostic-Code: smtp;550 5.1.2' | Select-Object Path
$FileList += Get-ChildItem "C:\inetpub\mailroot\Badmail-Archive" -Filter *.BAD | Select-String -Pattern 'Diagnostic-Code: smtp;550 5.2.1' | Select-Object Path
foreach($filepath in $FileList) {
$BADSearch = Select-String -Path $filepath -Pattern ('Final-Recipient') | Select -ExpandProperty line
$eMailAddress = $BADSearch.Split(";")[1]
echo "File Path: $filepath"
echo $eMailAddress
}
File Path: C:\inetpub\mailroot\Badmail-Archive\003c908531613052021000000A2.BAD
Select-String : Cannot find drive. A drive with the name '#{Path=C' does not exist.
At C:\Scripts\BadEmails-SQLGenerator.ps1:46 char:14
+ ... BADSearch = Select-String -Path $filepath -Pattern ('Final-Recipient' ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (#{Path=C:String) [Select-String], DriveNotFoundException
+ FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.SelectStringCommand
Your problem is with treating any arbitrary object as if it's a string. Select-String expects a string instance for the Path parameter, but you're passing it the resulting MatchInfo object returned from the previous Select-String call.
You'll need to tease out the path by selecting the .Path member from the previous command output:
Select-String -Path $filepath.Path # ...
Related
I'm trying to write a script to find the most recent .bak in a certain directory and copy the file to another location. When I use Get-ChildItem the file name isn't enlcosed in single quotes so when i try to copy it Copy-Item cant find it. ( I think)
$dir = 'E:\Backups\'
$dest = 'F:\'
$filename = Get-ChildItem -path $dir -filter *.bak | Sort-Object CreationTime -Descending | Select-Object -First 1 | select FullName | Format-Table -HideTableHeaders
echo #filename
copy-Item -path #filename -destination #dest
echo #filename returns E:\Backups\company.bak but i think need 'E:\Backups\company.bak' for it to work?
PS C:\Users\prodadmin> copy-Item -path #filename -destination #dest
Copy-Item : A positional parameter cannot be found that accepts argument 'Microsoft.PowerShell.Commands.Internal.Format.GroupStartData'.
At line:1 char:1
+ copy-Item -path #filename -destination #dest
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Copy-Item], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.CopyItemCommand
As above, typed it all in one go.
Get-ChildItem returns FileInfo (and also DirectoryInfo) objects.
By using select FullName you tell PowerShell to return an new object with one property called FullName and you lose the Name property.
Format-Table is a cmdlet used for display purposes only, so never use that on data you want to process further.
Lastly, you prefix the variables you have with # instead of $
Try
$dir = 'E:\Backups\'
$dest = 'F:\'
$file = Get-ChildItem -Path $dir -Filter '*.bak' -File | # do not return directories
Sort-Object CreationTime -Descending | # or did you mean LastWriteTime (=> last modified date) ?
Select-Object -First 1 # return just 1 FileInfo object
Write-Host "Found $($file.Name)" # write to console
Copy-Item -Path $file.FullName -Destination $dest
So, i need to save a string that was replaced on files.
I'm doing something wrong, but i`m not be able to figure it out, what!
My code:
Get-ChildItem -Path C:\Users\user\Documents -Recurse -Include "*.txt" -File | Select-String -Pattern \b192\.168\.10\.2\b , \b192\.168\.10\.11\b -AllMatches -List | Foreach-Object { $_ -replace '\b192\.168\.10\.2\b', "DEV" -and $_ -replace '\b192\.168\.10\.11\b', "QUAL" | Set-Content $_}
And gives-me the following error:
Set-Content : Could not open the alternate data stream '1:192.168.10.11' of the file 'C:\Users\user\Documents\result.txt'.
At line:1 char:323
+ ... place '\b192\.168\.10\.11\b', "QUAL" | Set-Content $_}
+
+ CategoryInfo : ObjectNotFound: (C:\Users\paulo....ents\result.txt:String) [Set-Content], FileNotFoundException
+ FullyQualifiedErrorId : GetContentWriterFileNotFoundError,Microsoft.PowerShell.Commands.SetContentCommand
Set-Content : Could not open the alternate data stream '1:192.168.10.11' of the file
'C:\Users\user\Documents\test.txt'
At line:1 char:323 ... place '\b192\.168\.10\.11\b', "QUAL" | Set-Content $_}
CategoryInfo : ObjectNotFound: (C:\Users\user\test.txt:String) [Set-Content], FileNotFoundException
FullyQualifiedErrorId : GetContentWriterFileNotFoundError,Microsoft.PowerShell.Commands.SetContentCommand
Thanks for any Help!
Inside the ForEach-Object block, $_ will refer to the current match result as returned by Select-String - to get the file path, reference the Path property:
... | ForEach-Object { ... |Set-Content -LiteralPath $_.Path}
The -and operator is used inside if tests like if(this -and that).
You should change the double replace actions from
$_ -replace '\b192\.168\.10\.2\b', "DEV" -and $_ -replace '\b192\.168\.10\.11\b', "QUAL"
into
$_ -replace '\b192\.168\.10\.2\b', "DEV" -replace '\b192\.168\.10\.11\b', "QUAL"
Also, if I understand the question properly, you want to find all string replacements in the file, and to get all, you need to remove the -List switch from Select-String.
Next, as Mathias explains in his answer, you need to use the Path property from the current match to get the file FullName.
However, if you pipe this through to Set-Content straight away, you will get an exception because the file then is in use and you cannot write to the same file.
Below creates a new file in the same path, with _replacements appended to the filename
# use '-Include' instead of '-Filter' if you need more file extensions to filter on
Get-ChildItem -Path 'C:\Users\user\Documents' -Recurse -Filter "*.txt" -File |
Select-String -Pattern '\b192\.168\.10\.2\b', '\b192\.168\.10\.11\b' -AllMatches |
Foreach-Object {
$file = '{0}_replacements{1}' -f [System.IO.Path]::GetFileNameWithoutExtension($_.Path),
[System.IO.Path]::GetExtension($_.Path)
$target = Join-Path -Path ([System.IO.Path]::GetDirectoryName($_.Path)) -ChildPath $file
$_ -replace '\b192\.168\.10\.2\b', "DEV" -replace '\b192\.168\.10\.11\b', "QUAL" |
Add-Content -Path $target
}
This results in a file called 'C:\Users\user\Documents\test_replacements.txt'
C:\Users\user\Documents\test.txt:4:DEV
C:\Users\user\Documents\test.txt:7:QUAL
The original file 'C:\Users\user\Documents\test.txt' will not be altered.
I want to shorten Directory with relative path:
$Dir = get-childitem C:\temp -recurse
$List = $Dir | where {$_.extension -eq ".txt"}
$List | format-table name, Directory -replace "C:\temp", ""
I get this error:
Format-Table : A parameter cannot be found that matches parameter name 'replace'.
At line:3 char:38
+ $List | format-table name, Directory -replace "C:\temp", ""
+ ~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Format-Table], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.FormatTableCommand
What's the right syntax ?
You can use a calculated property. Example:
$List | Format-Table name,
#{Name = "Directory"; $Expression = {$_.FullName -replace "C:\\temp", ""}}
A calculated property is simply a hashtable that dictates the content of the property. Calculated properties are available with formatting cmdlets that select properties and output a new custom object (e.g, Select-Object, Format-List, etc.).
(As an aside: The -replace operator uses a regular expression, so you would need to write C:\\temp instead of just C:\temp.)
If your goal is to output file system item directory names: Directory is not a property of all file system objects. Is this what you mean?
Get-ChildItem C:\Temp\*.txt -Recurse | Format-Table Name,
#{Name = "Directory"; Expression = {$_.FullName -replace 'C:\\temp', ''}}
Note how this command takes advantage of the pipeline (no need for the intermediate $List or $Dir variables).
To add to #Bill_Stewart's Answer.
$Dir = get-childitem C:\temp -recurse
$List = $Dir | where {$_.extension -eq ".txt"}
$List | format-table name, #{Label="Directory"; Expression={$_.Directory -replace "C:\\temp", ""}}
I am trying to search a directory structure, and files for all instances of where a pattern exists. Than I want that file location recorded in a log file that I can review latter. I looked at various posts, but I have not found a similar example where this is happening. Reviewed posts include:
PowerShell Scripting - Get-ChildItem
Search List for unique pattern
Search directory and sub-directories for pattern in a file
Use an Easy PowerShell Command to Search Files for Information
Get full path of the files in PowerShell
Here is the code I am using to recuse through the folder structure:
#Set variables for paths
$Results = "C:\Results"
$Source = "C:\Test\*"
$Destination = "C:\MyTest\"
#Create file name for each report with date and time of run
$ReportDate = (Get-Date).ToString("dd-MM-yyyy-hh-mm-ss")
$CustomPattern = Read-Host 'What pattern are you looing for?'
$CustomPatternLog = New-Item -itemType File -Path C:\Results -Name $("CustomerPattern_" + $ReportDate + ".txt")
$CustomPattern = foreach ($file in Get-ChildItem -Path $Destination -Recurse | Select-String -pattern $CustomPattern | Select-Object -Unique Path) {$file.path}
$CustomPattern > "$($Results)\$($CustomPatternLog)"
However, this code is returning the following error:
Get-ChildItem : The specified path, file name, or both are too long.
The fully qualified file name must be less than 260 characters, and
the directory name must be less than 248 characters. At line:19
char:36
+ $CustomPattern = foreach ($file in Get-ChildItem -Path $Destination -Recurse | S ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ReadError: (C:\Test\Mor...ofiles\Customer:St ring) [Get-ChildItem],
PathTooLongException
+ FullyQualifiedErrorId : DirIOError,Microsoft.PowerShell.Commands.GetChil dItemCommand
Do you have a better way to do the same operation?
replace this
$CustomPatternLog = New-Item -itemType File -Path C:\Results -Name $("CustomerPattern_" + $ReportDate + ".txt")
$CustomPattern = foreach ($file in Get-ChildItem -Path $Destination -Recurse | Select-String -pattern $CustomPattern | Select-Object -Unique Path) {$file.path}
$CustomPattern > "$($Results)\$($CustomPatternLog)"
with this
$files = Get-ChildItem -Path $Destination -Recurse
#in case you would need the path replace FullName with PsParentPath
$result = ($files | ?{$_.name -like "*$CustomPattern*"}).FullName
$result | out-file ($CustomPattern + "_" + $ReportDate + ".txt")
and since its shell you can do the same with one liner
(Get-ChildItem -Path $Destination -Recurse | ?{$_.name -like "*$CustomPattern*"}).FullName | out-file ($CustomPattern + "_" + $ReportDate + ".txt")
The snippet (Get-Content $_.FullName | Select-Object -First 1) is called three times. The aim is to declare it as a variable to avoid code duplication.
Get-ChildItem "$env:ChocolateyInstall\lib\eclipse.*" -Recurse -Filter "eclipseInstall.zip.txt" |
ForEach-Object{ if (((Get-Content $_.FullName | Select-Object -First 1) -match "eclipse") -and (Test-Path -Path (Get-Content $_.FullName | Select-Object -First 1))){Remove-Item -Recurse -Force (Get-Content $_.FullName | Select-Object -First 1)}}
Attempt
$a = (Get-Content $_.FullName | Select-Object -First 1)
Get-ChildItem "$env:ChocolateyInstall\lib\eclipse.*" -Recurse -Filter "eclipseInstall.zip.txt" |
ForEach-Object{ if (($a -match "eclipse") -and (Test-Path -Path (Get-Content $_.FullName | Select-Object -First 1))){Write-Host "hello"}}
Result
PS C:\Windows\system32> . "C:\temp\powershelltest\test.ps1"
Get-Content : Cannot bind argument to parameter 'Path' because it is null.
At C:\temp\powershelltest\test.ps1:1 char:19
+ $a = (Get-Content $_.FullName | Select-Object -First 1)
+ ~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-Content], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.GetContentC
ommand
You can assign a snippet of code to a variable like this:
$a = { Get-Content $_.FullName | Select-Object -First 1 }
Then execute the snippet at any time with & $a (you would need to pipe an object to it). I'm not sure this is necessary in your example though.