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.
Related
I have several txt files distributed in several sub-folders.
This is what a file looks like:
Data file. version 01.10.
1
8
*
DAT\Trep\Typ10
DAT\Trep\Typ12
DAT\Trep\Typ13
what I would like to do is to extract only the part after the last "\" in order to get something like this:
Typ10 FileName.txt Path
Typ12 FileName.txt Path
Typ13 FileName.txt Path
...
I tried the following
Get-ChildItem -Path 'D:\MyData\*.txt' -Recurse | ForEach-Object {Write-Output $_; $data=Get-Content $_}
$data = $data -replace '.*\\'
$data
it works well for a single file but not with several (-recurse).
Being a powershell beginner I can't figure out how to improve my script.
I also tried to add this to get the result shown above in my post, but that doesn't work either.
Select-Object -Property #{Name = 'Result list'; Expression = { $data }}, Filename, Path
Thanks in advance for your kind help
Use Select-String:
Get-ChildItem -Path D:\MyData\*.txt -Recurse -File |
Select-String '^.+\\(.+)' |
ForEach-Object {
[pscustomobect] #{
Result = $_.Matches.Groups[1].Value
FileName = $_.FileName
Path = $_.Path
}
}
As for your desire to exclude certain folders during recursive traversal:
Unfortunately, Get-ChildItem -Exclude only excludes the matching folders themselves, not also their content. There are two relevant feature requests to potentially overcome this limitation in the future:
GitHub issue #4126 asks for path patterns to be supported too in the future.
GitHub issue #15159 proposes a new subtree-exclusion parameter, such as
-ExcludeRecursive.
For now, a different approach with post-filtering based on Where-Object is required, using folder names Folder1 and Folder2 as examples:
Get-ChildItem -Path D:\MyData\*.txt -Recurse |
Where-Object FullName -NotLike *\Folder1\* |
Where-Object FullName -NotLike *\Folder2\* |
Select-String '^.+\\(.+)' |
ForEach-Object {
[pscustomobect] #{
Result = $_.Matches.Groups[1].Value
FileName = $_.FileName
Path = $_.Path
}
}
For a more flexible, cross-platform approach based on regex matching (which is invariably more complex), see the bottom section of this answer.
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
So, I've keep having trouble with tasks like this:
$fileNames = Get-ChildItem -Path . -Filter "*.*" `
| Select-Object -ExpandProperty Name
$fileNames.GetType()
I'd expect output to be string[], but it is object[].
Even worse, if I then try to manipulate the file names:
$fileNames = Get-ChildItem -Path . -Filter "*.*" `
| Select-Object -ExpandProperty Name `
| Select-Object { "$_" -replace '^.*deploy\.log\.\d\d\d\d-\d\d-\d\d\.', '' }
I'd expect again string[]. Instead I get some weird hashtable that has as a key the regex.
In both cases, its doing what I expect, just wrapping it up in objects.
What are the rules here? I can I just manipulate a list of strings?
As your last pipeline element, use ForEach-Object instead of Select-Object
$fileNames = Get-ChildItem -Path . -Filter "*.*" `
| Select-Object -ExpandProperty Name `
| ForEach-Object { "$_" -replace '^.*deploy\.log\.\d\d\d\d-\d\d-\d\d\.', '' }
You can skip the Select-Object -Expand part altogether if you wish:
$fileNames = Get-ChildItem -Filter *.* | ForEach-Object {
$_.Name -replace '^.*deploy\.log\.\d\d\d\d-\d\d-\d\d\.', ''
}
The result of your first code snippet is a generic array (hence its type says Object[]), but the elements are actually strings. If for some reason you need the type to be string[] you can simply cast the variable to that type:
[string[]]$filenames = Get-ChildItem ... | Select-Object -Expand Name
Normally that shouldn't be necessary, though.
In your second code snippet you're probably confusing Select-Object with ForEach-Object (see Mathias' answer). Instead of using a ForEach-Object loop you could also use the -replace operator directly on the expanded names:
$filenames = (Get-ChildItem ... | Select-Object -Expand Name) -replace '^.*deploy\.log\.\d{4}-\d{2}-\d{2}\.', ''
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.)
I'm trying to write a one-liner in Powershell that lists all filetypes in a folder (and its sub-folders).
I've got this so far:
Get-ChildItem D:\Audio -Recursive | Select-Object PSParentPath, Extension | Export-Csv D:\Test.csv
However, I'd like to do better and display, for each folder, every found extension only once.
For example, let's say I have ten mp3 files and 1 jpg file in D:\Audio\foo and 5 flac files and 1 txt file in D:\Audio\bar. I'd like the output to be :
foo .mp3
foo .jpeg
bar .flac
bar .txt
I guess I should use Get-Unique but how do I specify it on the Extension property and NOT on the Path property?
Just add -Unique to Select-Object:
Get-Childitem -Recurse | Select-Object PSParentPath,Extension -Unique
(Also, DirectoryName might be better than PSParentPath here)
i complet solution of Jimmeh, use -file for take only file
Get-ChildItem "c:\temp" -Recurse -file | select directoryname, Extension -Unique
Try this:
Get-ChildItem D:\Audio -Recurse | Group-Object psparentpath, extension | ? {(($_.Name -split ", .")[1]) -ne $Null } | ft -AutoSize #{Expression={(($_.Name.Split("\"))[$_.Name.Split("\").Length -1] -split ",")[0]};Label="Folder"}, #{Expression={($_.Name -split ", .")[1]};Label="Extension"}
To show full path to folder + extension, try the following.
Get-ChildItem D:\Audio -Recurse | Group-Object psparentpath, extension | ? {(($_.Name -split ", .")[1]) -ne $Null } | ft -AutoSize #{Expression={($_.Name.Replace("Microsoft.PowerShell.Core\FileSystem::","") -split ", .")[0]};Label="Folder"}, #{Expression={($_.Name -split ", .")[1]};Label="Extension"}