Powershell GCI Recursive Depth Stops Working When Adding Include Parameter - powershell

I have what I'm assuming to be a simple question. I have a large block of code that I have written. In short, it downloads a dynamic list of file names and extensions, imports a csv with the roots of every one of our shares, and compares the files to find matches.
$Directory = Get-ChildItem -Path $path -Recurse -Depth 2 -Include $ExtList -Force
Super simple, right? Except the depth parameter isn't working. It recursively searches through every single level. If I do this:
$Directory = Get-ChildItem -Path $path -Depth 2 -Force
The Depth parameter works perfectly and it only searches through the two levels. If I don't include recurse or depth, it works as expected by searching only the top level. The only difference is that I'm removing the -Include parameter.
$Path is a variable like \server\root\
$ExtList is an array of filenames
Again, they both work individually, but not together.
I need to have both the depth and include parameters in here. Does anybody know what I am doing wrong, or if it's a glitch?
Edit ---------------------------
Doing "Where-Object" I tried this:
$Directory = Get-ChildItem -Path $path -Recurse -Depth 2 -Force | Where-Object {$_.Extension -like $ExtList}
And... nothing happens. For testing, this script takes about 10 minutes to successfully run on a good day, it finished in less than 1 second. (715ms to be exact)
When I go into debugging, it's like there is nothing being piped into the where-object.
EDIT------
The $ExtList setup looks like this:
#((Invoke-WebRequest -Uri "https://fsrm.experiant.ca/api/v1/get").content | convertfrom-json | % {$_.filters})
That will get you the exact list and format that I'm using.
$Path pulls from a csv file that looks like this:
This CSV has over 3000 different shares in it. I know it's weird, yes I have to do it this way for our infrastructure.

After switching to run on a Windows Server 2012 R2 box, the depth parameter works with include. It seems to have been a bug with the version that I was on.

Related

Run executable in Powershell with specific filenames as arguments

I'm trying to batch-convert heic images to png images using Powershell. What I have tried:
Get-ChildItem -Include ('*.HEIC', '*.heic') -File | & .\bin\vips.exe copy $_.Name "$(_.BaseName).png"
Pause
and
Get-ChildItem -Include ('*.HEIC', '*.heic') -File | & .\bin\vips.exe copy $_.Name ($_.BaseName + '.png')
Pause
Both times I'm getting an error VipsForeignLoad: file ".png" does not exist which tells me it treats ".png" as the first (and only) argument and ignores the object Name and Basename properties.
You're missing a $. "$($_.BaseName).png" I would use -Filter vs -Include as it is more efficient.
Edited: Try this approach bypassing the Pipe and see if you get a different result. I've also added some additional code to insure everything is fully evaluated. If this approach works you can experiment with reducing come of the $() evaluation levels.
Also are you using Linux? Some of my googling led me to believe you might be. If so you should specify this in your tags for clarity.
Clear-Host
$x = Get-ChildItem -Filter "*.HEIC" -File
ForEach ($File in $x) {
& .\bin\vips.exe copy "$($File.FullName)" $("$($File.BaseName)" + ".pdf")
}
Also note the file extension in the Filter is case insensitive so no need to repeat.
I'd also recommend adding the -Path parameter for clarity rather than assuming the default directory but that's just me.
HTH

Use Powershell to list the Fully Pathed Filenames on Individual Separate Lines?

If I execute:
Get-ChildItem *.ext -recurse
the output consists of a series of Directory sections followed by one or more columns of info for each matching file separated by said directory sections. Is there something like the Unix find command? In which each matching file name appears on a single line with its full relative path?
Get-Childitem by default outputs a view for format-table defined in a format xml file somewhere.
get-childitem | format-table
get-childitem | format-list *
shows you the actual properties in the objects being output. See also How to list all properties of a PowerShell object . Then you can pick and choose the ones you want. This would give the full pathname:
get-childitem | select fullname
If you want an output to be just a string and not an object:
get-childitem | select -expand fullname
get-childitem | foreach fullname
Resolve-Path with the -Relative switch can be used to display the relative paths of a set of paths. You can collect the full path names (FullName property) from the Get-ChildItem command and use the member access operator . to grab the path values only.
Resolve-Path -Path (Get-ChildItem -Filter *.ext -Recurse).FullName -Relative
Note: The relative paths here only accurately reflect files found within the current directory (Get-ChildItem -Path .), i.e. Get-ChildItem -Path NotCurrentDirectory could have undesirable results.
Get-ChildItem's -Name switch does what you want:
It outputs the relative paths (possibly including subdir. components) of matching files as strings (type [string]).
# Lists file / dir. paths as *relative paths* (strings).
# (relative to the input dir, which is implicitly the current one here).
Get-ChildItem -Filter *.ext -Recurse -Name
Note that I've used -Filter, which significantly speeds up the traversal.
Caveat: As of PowerShell 7.0, -Name suffers from performance problems and behavioral quirks; see these GitHub issues:
https://github.com/PowerShell/PowerShell/issues/9014
https://github.com/PowerShell/PowerShell/issues/9119
https://github.com/PowerShell/PowerShell/issues/9126
https://github.com/PowerShell/PowerShell/issues/9122
https://github.com/PowerShell/PowerShell/issues/9120
I am having some problem passing the path plus filename to a parser. There are about 90 files of 1 GB each involved in my task. Each of the file is contained in a folder of its own. All of the folders are contained under a parent folder.
Goal: Ideally, I would like to parse 20 files simultaneously for multitasking and continue to the next 20 until all 90 files are done.
This would mean that I would like to spawn some concurrent parsing of 20 files in a batch at any one given time. In carrying out the parsing, I would like to use measure-command to time the work from beginning to finish.
Script I have used:
Get-ChildItem –Path "E:\\OoonaFTP\\input\\Videos3\\" -Filter *.mp4 -recurse | select -expand fullname
Foreach-Object {
Measure-Command { "E:\OoonaFTP\Ooona_x64_ver_2.5.13\OoonaParser.exe -encode -dat -drm $_.FullName" } | Select-Object -Property TotalSeconds
}
===============================
I have this working batch script with a for statement but doing each iteration one after another. This is not what is the ideal case though. I would really like to accomplish this in PowerShell and with simultaneous tasks.
Could someone please suggest some ways by which I could accomplish this?
Thank you very much!
Thanks for the various suggestions. I'm curious that some of them lead to empty output in my Powershell (PSVersion: 5.1.18362.145).
I tried a number of these and, inspired by some of them, found the best answer for my case at the moment:
Get-ChildItem *.ext -recurse | Select-Object -property fullname
(When I made the window wide enough I got all the info I needed; in general I suppose I might need to do more to get the formatting I want.)

List out the .txt files which I modified in the previous five minutes

I managed to list out all the files which I modified in the last 5 minutes, but I only need the modified txt files. How can I get that?
Here is my code:
Get-ChildItem -Recurse| where-object{$_.LastWriteTime -gt (Get-Date).AddMinutes(-5)}
I know I should use -match, but I don't know where to put it and how to use it properly.
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-childitem?view=powershell-6
has an example part way down that has -Path *.txt (and it also has an -Include *.txt -Exclude A* if you want examples of how to be more specific) - try those
As these things are options of Get-ChildItem they should go just before/after the -Recurse, i.e. before the pipe |

How can I use PowerShell or a cmd "dir" to get the contents of multiple, but similar paths?

For example, I want the contents of the "Last" folder in the structure below. The various path structures are identical except for the first two levels.
C:\zyx-wvu\abc\Level3\Last
C:\tsr-qpo\def\Level3\Last
C:\nml-kji\ghi\Level3\Last
In PowerShell I get close with:
Get-ChildItem -Path C:\*-*\*
...but it doesn't return any results (as in it never finishes) when I try:
Get-ChildItem -Path C:\*-*\*\Level3
Get-ChildItem -Path C:\*-*\*
will only show you what's in the second layer behind anything with a hyphen in c:\
aka it will show
c:\1-2\alpha
c:\1-5\beta
etc...
What you want is
Get-ChildItem -Path C:\*-*\*\*
or more likely you want
Get-ChildItem -Path C:\*-*\* -recurse
if you want to find paths with the SAME name... you could group them together, and pull out anything with more than one finding... you didn't ask very specifically what you wanted, but here's some ideas.
get-childitem -Path c:\*-*\*\* | group-object -property basename | where count -gt 1 | select -expand group

Copying files defined in a list from network location

I'm trying to teach myself enough powershell or batch programming to figure out to achieve the following (I've had a search and looked through a couple hours of Youtube tutorials but can't quite piece it all together to figure out what I need - I don't get Tokens, for example, but they seem necessary in the For loop). Also, not sure if the below is best achieved by robocopy or xcopy.
Task:
Define a list of files to retrieve in a csv (file name will be listed as a 13 digit number, extension will be UNKNOWN, but will usually be .jpg but might occasionally be .png - could this be achieved with a wildcard?)
list would read something like:
9780761189931
9780761189988
9781579657159
For each line in this text file, do:
Search a network folder and all subfolders
If exact filename is found, copy to an arbitrary target (say a new folder created on desktop)
(Not 100% necessary, but nice to have) Once the For loop has completed, output a list of files copied into a text file in the newly created destination folder
I gather that I'll maybe need to do a couple of things first, like define variables for the source and destination folders? I found the below elsewhere but couldn't quite get my head around it.
set src_folder=O:\2017\By_Month\Covers
set dst_folder=c:\Users\%USERNAME&\Desktop\GetCovers
for /f "tokens=*" %%i in (ISBN.txt) DO (
xcopy /K "%src_folder%\%%i" "%dst_folder%"
)
Thanks in advance!
This solution is in powershell, by the way.
To get all subfiles of a folder, use Get-ChildItem and the pipeline, and you can then compare the name to the insides of your CSV (which you can get using import-CSV, by the way).
Get-ChildItem -path $src_folder -recurse | foreach{$_.fullname}
I'd personally then use a function to edit the name as a string, but I know this probably isn't the best way to do it. Create a function outside of the pipeline, and have it return a modified path in such a way that you can continue the previous line like this:
Get-ChildItem -path $src_folder -recurse | foreach{$_.CopyTo (edit-path $_.fullname)}
Where "edit-directory" is your function that takes in the path, and modifies it to return your destination path. Also, you can alternatively use robocopy or xcopy instead of CopyTo, but Copy-Item is a powershell native and doesn't require much string manipulation (which in my experience, the less, the better).
Edit: Here's a function that could do the trick:
function edit-path{
Param([string] $path)
$modified_path = $dst_folder + "\"
$modified_path = $path.substring($src_folder.length)
return $modified_path
}
Edit: Here's how to integrate the importing from CSV, so that the copy only happens to files that are written in the CSV (which I had left out, oops):
$csv = import-csv $CSV_path
Get-ChildItem -path $src_folder -recurse | where-object{$csv -contains $_.name} | foreach{$_.CopyTo (edit-path $_.fullname)}
Note that you have to put the whole CSV path in the $CSV_path variable, and depending on how the contents of that file are written, you may have to use $_.fullname, or other parameters.
This seems like an average enough problem:
$Arr = Import-CSV -Path $CSVPath
Get-ChildItem -Path $Folder -Recurse |
Where-Object -FilterScript { $Arr -contains $PSItem.Name.Substring(0,($PSItem.Length - 4)) } |
ForEach-Object -Process {
Copy-Item -Destination $env:UserProfile\Desktop
$PSItem.Name | Out-File -FilePath $env:UserProfile\Desktop\Results.txt -Append
}
I'm not great with string manipulation so the string bit is a bit confusing, but here's everything spelled out.