Passing agruments to another program in Powershell - powershell

I am trying to write a script that will parse a directory, find the 3 newest files of a given extension among other files with the same name but different extension and then pass the output to a command line program.
So far I have:
$file = dir test -Exclude *.md5 | sort -prop LastWriteTime | select fullname -last 3
\path\program argumentA $file[0] argumentB "argumentC"
\path\program argumentA $file[1] argumentB "argumentC"
\path\program argumentA $file[2] argumentB "argumentC"
Not sure if it matters a whole lot but argument2 needs to be in quotes for the program to use it. I will eventually either have the output written to a file or, preferably use the output in another line of code described in the bonus question.
The problem I am having is that when I use $file[0] as an argument nothing happens. When I use the file name stored in $file[0] instead of using the variable, it runs, but does not pass argumentB or argumentC. If I run it from cmd I get the proper output.
My questions are:
How do I get the program to recognize a variable?
How do I get the program to recognize the other arguments?
Bonus question:
The program will output a list of files. How do I delete everything in the given folder except for the files listed in the output of the program?

Try
$($file[0])
I find that I often have to wrap things in "magical" dollar sign brackets to get them working in PowerShell.

Since you are piping to Select-Object and selecting the FullName property you have 3 objects of type System.Management.Automation.PSCustomObject with a FullName property. You should access the FullName property on the object when using it as a command line argument for your program like this:
$file = dir test -Exclude *.md5 | sort -prop LastWriteTime | select fullname -last 3
\path\program argumentA $file[0].FullName argumentB "argumentC"
If you remove the fullname property from the Select-Object cmdlet Powershell will not create a PSCustomObject and you can access all properties and methods from the original System.IO.FileInfo object.
This is how you can see the difference:
PsCustomObject
$file = dir test -Exclude *.md5 | sort -prop LastWriteTime | select fullname -last 3
$file[0] | gm
System.IO.FileInfo
$file = dir test -Exclude *.md5 | sort -prop LastWriteTime | select -last 3
$file[0] | gm

I would actually use a loop with this to avoid duplication. (That way you'll avoid copy-and-paste errors and simplify the problem, especially if you add error-handling or anything else later).
$files = dir test -Exclude *.md5 | sort -prop LastWriteTime |
select fullname -last 3
foreach ($file in $files) {
& \path\program argumentA $file argumentB "argumentC"
}
As PS treats collections the same as normal objects anyway, this works even if you only select 1 object.

Related

How to use Get-Content to get all information from the most recent file

I am trying to use Get-Content to get the most recent .xml file and all its content to be displayed in the powershell window, but I am having a hard time.
I have use the the following:
Get-ChildItem "\\Server1\c$\Program Files\AAA\Logs\" | Sort-Object CreationTime | Select-Object -Last 1
Get-Content -Path "\\Server1\c$\Program Files\AAA\Logs\" | Where-Object {$_.LastWriteTime -lt (get-date).addDays(-1)} | Select -Last 1
But I cannot figure out how to go about grabbing the latest file and displaying all its content in the console
You are close. You have to pipe the result of your first line to Get-Content:
Get-ChildItem "\\Server1\c$\Program Files\AAA\Logs\" | Sort-Object CreationTime | Select-Object -Last 1 | Get-Content
Your second line does not make much sense. If you provide a valid path to Get-Content, it will return to you the content of the file as a string. You cannot apply any creation time logic to this content afterwards with Where-Object.
Your first line though, works like this:
It gets all files and folders that are contained in your given path. If this path really just contains valid log files, you can leave it like this. Otherwise you should filter this result, so you really just get your desired files. To be precise, Get-ChildItem returns an array of System.IO.FileInfo objects. They contain a lot of information about your files.
You then sort this array of System.IO.FileInfo objects by the CreationTime property with Sort-Object.
Finally, you select the last element of the sorted array. This is still a System.IO.FileInfo object. That's why you see some of its properties in your output.
If you then pipe this System.IO.FileInfo object to Get-Content, the FullPath property of this object will be mapped to the -Path parameter of Get-Content, thus returning the content of the file specified by the System.IO.FileInfo object.

PowerShell find most recent file

I'm new to powershell and scripting in general. Doing lots of reading and testing and this is my first post.
Here is what I am trying to do. I have a folder that contains sub-folders for each report that runs daily. A new sub-folder is created each day.
The file names in the sub-folders are the same with only the date changing.
I want to get a specific file from yesterday's folder.
Here is what I have so far:
Get-ChildItem -filter “MBVOutputQueriesReport_C12_Custom.html” -recurse -path D:\BHM\Receive\ | where(get-date).AddDays(-1)
Both parts (before and after pipe) work. But when I combine them it fails.
What am I doing wrong?
What am I doing wrong?
0,1,2,3,4,5 | Where { $_ -gt 3 }
this will compare the incoming number from the pipeline ($_) with 3 and allow things that are greater than 3 to get past it - whenever the $_ -gt 3 test evaluates to $True.
0,1,2,3,4,5 | where { $_ }
this has nothing to compare against - in this case, it casts the value to boolean - 'truthy' or 'falsey' and will allow everything 'truthy' to get through. 0 is dropped, the rest are allowed.
Get-ChildItem | where Name -eq 'test.txt'
without the {} is a syntax where it expects Name is a property of the thing coming through the pipeline (in this case file names) and compares those against 'test.txt' and only allows file objects with that name to go through.
Get-ChildItem | where Length
In this case, the property it's looking for is Length (the file size) and there is no comparison given, so it's back to doing the "casting to true/false" thing from earlier. This will only show files with some content (non-0 length), and will drop 0 size files, for example.
ok, that brings me to your code:
Get-ChildItem | where(get-date).AddDays(-1)
With no {} and only one thing given to Where, it's expecting the parameter to be a property name, and is casting the value of that property to true/false to decide what to do. This is saying "filter where *the things in the pipeline have a property named ("09/08/2016 14:12:06" (yesterday's date with current time)) and the value of that property is 'truthy'". No files have a property called (yesterday's date), so that question reads $null for every file, and Where drops everything from the pipeline.
You can do as Jimbo answers, and filter comparing the file's write time against yesterday's date. But if you know the files and folders are named in date order, you can save -recursing through the entire folder tree and looking at everything, because you know what yesterday's file will be called.
Although you didn't say, you could do approaches either like
$yesterday = (Get-Date).AddDays(-1).ToString('MM-dd-yyyy')
Get-ChildItem "d:\receive\bhm\$yesterday\MBVOutputQueriesReport_C12_Custom.html"
# (or whatever date pattern gets you directly to that file)
or
Get-ChildItem | sort -Property CreationTime -Descending | Select -Skip 1 -First 1
to get the 'last but one' thing, ordered by reverse created date.
Read output from get-date | Get-Member -MemberType Property and then apply Where-Object docs:
Get-ChildItem -filter “MBVOutputQueriesReport_C12_Custom.html” -recurse -path D:\BHM\Receive\ | `
Where-Object {$_.LastWriteTime.Date -eq (get-date).AddDays(-1).Date}
Try:
where {$_.lastwritetime.Day -eq ((get-date).AddDays(-1)).Day}
You could pipe the results to the Sort command, and pipe that to Select to just get the first result.
Get-ChildItem -filter “MBVOutputQueriesReport_C12_Custom.html” -recurse -path D:\BHM\Receive\ | Sort LastWriteTime -Descending | Select -First 1
Can do something like this.
$time = (get-date).AddDays(-1).Day
Get-ChildItem -Filter "MBVOutputQueriesReport_C12_Custom.html" -Recurse -Path D:\BHM\Receive\ | Where-Object { $_.LastWriteTime.Day -eq $time }

Powershell refer to objects in table

I have a script I am working on that will output all fileNames and lineNumbers of a key word search.
$Paths = gci . *.* -rec | where { ! $_.PSIsContainer } | resolve-path
foreach($path in $Paths)
{
$ftp += Select-String -Path $Path -Pattern "FTP"
}
$ftpgroups = $ftp | select fileName,LineNumber | Format-Table -groupBy Filename
I decided to go with ft -groupby because group-object was not working correctly. But I need a way to reference this table so I can put it into a csv. When using the get-member commandlet it only gives me properties of formating. The ideal output for this is to have 1 fileName matched up to a group of fileLines. That way I can match that up to the path (which group-object worked succesfully on).
I am open to new ideas if I am going about this the wrong way. Thank you in advanced, hope it doesn't cause you as much trouble as it has me.
As you have found, the output of any of the Format-* cmdlets is formatting objects. These objects are meant for display to the console and not further manipulation. You really need Group-Object for this. In what way wasn't it working for you? I would think, this would work:
$ftpgroups = $ftp | Select Filename,LineNumber | Group Filename

How do I write a powershell script that gets the file with the most recent last write time from a folder?

The subject line says it all. I'd also like to do this using pipes.
I figured that I could use Get-ChildItem, Measure-Object and Where-Object, but Measure-Object doesn't like dates.
Should I have a script block which loops through each item returned from Get-ChildItem and does a comparison to see if it's the most recent? I thought that there should be a handy PS cmdlet for that.
Get-ChildItem | Sort LastWriteTime -Descending | Select -First 1

Run a function on each element of a list in powershell

I have a directory full of file pairs. Each pair of files have the same name with the extensions of mp3 and cdg (karaoke files!). I would like to use powershell to get the list of all distinct file names with no extensions
I've gotten as far as:
dir -recurse -filter "*.mp3" | select-object Name | sort
But I can't quite figure out how to pass each Name to [System.IO.Path]::GetFileNameWithoutExtension
how would I do this?
What you're looking for is the for-each (%) filter (not precisely sure if it's a filter or a cmdlet but it has the same usage syntax).
Try the following
dir -recurse -filter "*.mp3" |
%{ $_.Name } |
%{ [IO::Path]::GetFileNameWithoutExtension($_) } |
sort
EDIT Update
I changed my answer from "select-object Name" to "%{ $_.Name}". The former essentially takes the Name property off of the pipeline value and creates a new object with a single property of the specified name with the value on the original object. The latter will process every value in the pipeline and pass the result of executing $_.Name down the pipeline.
dir -recurse -filter "*.mp3"| select #{name='Name';Expression={[System.IO.Path]::GetFileNameWithoutExtension($_.Name)}} | sort
If you hate typing %{$_.foo} all the time like I do, try Get-PropertyValue (alias: gpv) from PSCX.
More musings here for the suitably geeky: http://richardberg.net/blog/?p=55
Now that PowerShell v2 is RTMd, you can select the BaseName member:
dir -recurse -filter *.mp3 | select BaseName | sort