This is what I'm running:
Get-Childitem $("C:\Powershell Tests\Group 1") -Recurse -Force | where { -not$_.PSIsContainer } | group name -NoElement | sort name > "C:\Powershell Tests\Group 1.txt"
I'm later using this text file and comparing with the names in another to see what he differences are between the two.
In the text file I'm getting the name truncated with "..."
What can I add so that it doesn't truncate so that I can compare?
PowerShell outputs objects, not text.
If you want to output the file's names, then select the names and output them:
Get-ChildItem "C:\PowerShell Tests\Group 1" -Recurse -Force |
Where-Object { -not $_.PSIsContainer } |
Select-Object -ExpandProperty Name |
Sort-Object -Unique |
Out-File "C:\Powershell Tests\Group 1.txt"
Notes:
you don't need the subexpression operator, $( ), for the parameter to Get-ChildItem.
I removed your call to Group-Object. (It looked to me like you want a sorted list of unique file names.)
Related
I spent quite some time searching for the solution of my problem, but found nothing. I have one single folder with mostly .html files, and I frequently need to search to find the files that contain certain strings. I need the search result to be displayed with just the file name (as the file will only be in that one folder) and file's last write time. The list needs to be sorted by the last write time. This code works perfectly for finding the correct files
Get-ChildItem -Filter *.html -Recurse | Select-String -pattern "keyWord string" | group path | select name
The problem with it is that it displays the entire path of the file (which is not needed), it does not show the last write time, and it is not sorted by the last write time.
I also have this code
Get-ChildItem -Attributes !Directory *.html | Sort-Object -Descending -Property LastWriteTime | Select-Object Name, LastWriteTime
That code prints everything exactly as I want to see it, but it prints all the file names from the folder instead of printing only the files that I need to find with a specific string in them.
Since you are only using Select-String to determine if the text exists in any of the files move it inside a Where-Object filter and use the -Quiet parameter so that it returns true or false. Then sort and select the properties you want.
Get-ChildItem -Filter *.html |
Where-Object { $_ | Select-String -Pattern 'keyWord string' -Quiet } |
Sort-Object LastWriteTime |
Select-Object Name, LastWriteTime
For multiple patterns one way you can do it is like this
Get-ChildItem -Filter *.html |
Where-Object {
($_ | Select-String -Pattern 'keyWord string' -Quiet) -and
($_ | Select-String -Pattern 'keyWord string #2' -Quiet)
} |
Sort-Object LastWriteTime |
Select-Object Name, LastWriteTime
And another way using Select-String with multiple patterns which may be a bit faster
$patterns = 'keyword 1', 'keyword 2', 'keyword 3'
Get-ChildItem -Filter *.html |
Where-Object {
($_ | Select-String -Pattern $patterns | Select-Object -Unique Pattern ).Count -eq $patterns.Count
} |
Sort-Object LastWriteTime |
Select-Object Name, LastWriteTime
If you don't care about it being a bit redundant, you can Get-ChildItem the results after your searching:
Get-ChildItem -Filter *.html -Attributes !Directory -Recurse | Select-String -Pattern "keyWord string" | group path | foreach {Get-ChildItem $_.Name } | Sort-Object -Descending LastWriteTime | Select Name,LastWriteTime
After you Select-String you get the attributes of that object instead of the original, so we're taking the results of that object and passing it back into the Get-ChildItem command to retrieve those attributes instead.
I use this to get a list of folders containing .h files.
**
$type = "*.h"
$HDIRS = dir .\$type -Recurse |
Select-Object Directory -Unique |
Format-Table -HideTableHeaders
** It gives me a list of folders.
Now I want "-I " before every foldername. Common string manipulation doesn't seem to work
You still have rich objects after the select so to manipulate the strings you have to reference the one property you've selected "Directory"
$type = "*.h"
$HDIRS = Dir .\$type -Recurse |
Select-Object Directory -Unique |
ForEach-Object{
$_.Directory = "-I" + $_.Directory
$_
} |
Format-Table -HideTableHeaders
This will result in $HDIRS looking like a list of folder paths like -IC:\temp\something\something...
However, the format output objects are generally not suitable for further consumption. It looks like you're interested in the strings you could simply make this a flat array of strings like:
$type = "*.h"
$HDIRS = Dir .\$type" -Recurse |
Select-Object -ExpandProperty Directory -Unique |
ForEach-Object{ "-I" + $_ }
The mantra goes filter left, format right.
Our data:
$type = '.\*.h'
Get-ChildItem -Path $type -Recurse
The manipulation (filter):
Select-Object { "-I $($_.Directory)" } -Unique
And the format:
Format-Table -HideTableHeaders
In many cases, PowerShell cmdlets allow you to pass scriptblocks (closures) to evaluate to values and that's what I'm doing above with the Select-Object call.
$inputpath = 1.txt, 2.txt ....
Command:
Get-ChildItem -Path $inputpath\* -Include *.txt | Sort-Object -Property Name | Get-Content | ForEach-Object { Add-Content -Path d:\MergedFile.txt -Value "$_" }
The Result is a mixed file with duplicated content and in a random order. How can I append multiple files to a new file while considering the order of the source files?
When you sort on a file's Name property, you're sorting string values, and the result will be sorted alphabetically - which means 10 goes before 9 for example.
If you want to sort by the numerical value represented by the string name, you'll have to explicitly tell Sort-Object to treat the input values as such:
Get-ChildItem ... | Sort-Object -Property {$_.Name -replace '\D' -as [int]} |...
In the property expression {$_.Name -replace '\D' -as [int]} we take the Name property value (like before), remove any non-digit characters, and finally convert the resulting string to an integer.
I have a bunch of lists of documents generated in powershell using this command:
Get-ChildItem -Recurse |
Select-String -Pattern "acrn164524" |
group Path |
select Name > test.txt
In this example it generates a list of files containing the string acrn164524 the output looks like this:
Name
----
C:\data\logo.eps
C:\data\invoice.docx
C:\data\special.docx
InputStream
C:\datanew\special.docx
I have been using
Get-Content "test.txt" | ForEach-Object {
Copy-Item -Path $_ -Destination "c:\destination\" -Recurse -Container -Force
}
However, this is an issue if two or more files have the same name and also throws a bunch of errors for any lines in the file that are not a path.
sorry if I was not clear enough I would like to keep files with the same name by appending something to the end of the file name.
You seem to want the files, not the output of Select-String. So let's keep the files.
Get-ChildItem -Recurse -File | Where-Object {
$_ | Select-String acrn164524 -Quiet
} | Select-Object -ExpandProperty FullName | Out-File test.txt
Here
-File will make Get-ChildItem only return actual files. Think
about using a filter like *.txt to reduce the workload more.
-Quiet will make Select-String return $true or $false, which
is perfect for Where-Object.
Instead of Select-Object -ExpandProperty X in order to retrieve an array of raw property values (as opposed to an array of PSObjects, which is what Select-Object would normally do), it's simpler to use ForEach-Object X instead.
Get-ChildItem -Recurse -File | Where-Object {
$_ | Select-String acrn164524 -Quiet
} | ForEach-Object FullName | Out-File test.txt
I have a group of txt files contain similar strings like this:
Windows 7 Professional Service Pack 1
Product Part No.: *****
Installed from 'Compliance Checked Product' media.
Product ID: 0000-0000-0000 match to CD Key data
CD Key: xxxxx-xxxxx-xxxxx-xxxxx-xxxxx
Computer Name: COMP001
Registered Owner: ABC
Registered Organization:
Microsoft Office Professional Edition 2003
Product ID: 00000-00000-00000-00000
CD Key: xxxxx-xxxxx-xxxxx-xxxxx-xxxxx
How may I pick all office keys one time and save into another file?
My code:
$content = Get-ChildItem -Path 'S:\New folder' -Recurse |
where Name -like "b*" |
select name
Get-Content $content
I get a list of files name but it wouldn't run for Get-Content.
The code you posted doesn't work, because $content contains a list of custom objects with one property (name) containing just the file name without path. Since you're apparently not listing the files in the current working directory, but some other folder (S:\New Folder), you need the full path to those files (property FullName) if you want to be able to read them. Also, the property isn't expanded automatically. You must either expand it when enumerating the files:
$content = Get-ChildItem -Path 'S:\New folder' -Recurse |
Where-Object { $_.Name -like "b*" } |
Select-Object -Expand FullName
Get-Content $content
or when passing the value to Get-Content:
$content = Get-ChildItem -Path 'S:\New folder' -Recurse |
Where-Object { $_.Name -like "b*" } |
Select-Object FullName
Get-Content $content.FullName
With that out of the way, none of the code you have does even attempt to extract the data you're looking for. Assuming that the license information blocks in your files is always separated by 2 or more consecutive line breaks you could split the content of the files at consecutive line breaks and extract the information with a regular expression like this:
Get-ChildItem -Path 'S:\New folder' -Recurse | Where-Object {
-not $_.PSIsContainer -and
$_.Name -like "b*"
} | ForEach-Object {
# split content of each file into individual license information fragments
(Get-Content $_.FullName | Out-String) -split '(\r?\n){2,}' | Where-Object {
# filter for fragments that contain the string "Microsoft Office" and
# match the line beginning with "CD Key: " in those fragments
$_ -like '*Microsoft Office*' -and
$_ -match '(?m)(?<=^CD Key: ).*'
} | ForEach-Object {
# remove leading/trailing whitespace from the extracted key
$matches[0].Trim()
}
} | Set-Content 'C:\output.txt'
(\r?\n){2,} is a regular expression that matches 2 or more consecutive line breaks (both Windows and Unix style).
(?m)(?<=^CD Key: ).* is a regular expression that matches a line beginning with the string CD Key: and returns the rest of the line after that string. (?<=...) is a so-called positive lookbehind assertion that is used for matching a pattern without including it in the returned value. (?m) is a regular expression option that allows ^ to match the beginning of a line inside a multiline string instead of just the beginning of the string.
try Something like this:
Get-ChildItem "c:\temp" -file -filter "*.txt" |
%{select-string -Path $_.FullName -Pattern "CD Key:" } | select line | export-csv "c:\temp\found.csv" -notype
If you want computer information you can do it (-context take N rows before and M rows after example -context 3, 2 take 3 before and 2 after) :
Get-ChildItem "c:\temp" -file -filter "*.txt" |
%{select-string -Path $_.FullName -Pattern "CD Key:" -context 6,0 } | where {$_.Context.PreContext[0] -like 'Computer Name:*'} |
select Line, #{Name="Computer";E={($_.Context.PreContext[0] -split ':')[1] }} | export-csv "c:\temp\found.csv" -notype
Or classically:
Get-ChildItem "c:\temp" -file -filter "*.txt" | foreach{
$CurrenFile=$_.FullName
#split current file rows to 2 column with ':' like delimiter
$KeysValues=get-content $CurrenFile | ConvertFrom-String -Delimiter ":" -PropertyNames Key, Value
#if file contains CD Key, its good file
if ($KeysValues -ne $null -and $KeysValues[2].Key -eq 'CD Key')
{
#build object with asked values
$Object=[pscustomobject]#{
File=$CurrenFile
ComputerName=$KeysValues[3].Value
OfficeKey=$KeysValues[7].Value
}
#send objet to standard output
$Object
}
} | export-csv "c:\temp\found.csv" -notype