Select-Object with Out-GridView - powershell

I am creating a tool for our help desk to copy frequent resolution comments they may use when resolving tickets. I currently have:
Get-ChildItem ".\FileStore" | Out-GridView -PassThru -Title "Quick Notes" | Get-Content | Set-Clipboard
Which outputs something similar to (but in GridView):
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 15/11/2018 14:38 14 1.txt
-a---- 15/11/2018 14:39 14 2.txt
-a---- 15/11/2018 14:39 14 3.txt
-a---- 15/11/2018 14:39 14 4.txt
I am aiming to just have the Name column output, however I am unsure on how to achieve this. I have tried Select, Select-Object and Format-Table which do not work, as I receive the following:
Get-Content : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of
the parameters that take pipeline input.
Is it possible to output only the Name column to the GridView?

To allow Get-Content to find the file, you need to select more than just a Name, because Get-Content have no way to interpret the Name property. It have no matching parameter. Best thing to select is PSPath property, which contains fully qualified PowerShell path? and will match LiteralPath parameter of Get-Content cmdlet.
Sadly Out-GridView does not have direct way to specify which properties to display, but it use standard PowerShell mechanism for selecting them. So, we can use it instead. To do that you need to attach MemberSet property PSStandardMembers with property set DefaultDisplayPropertySet, which says which properties to display by default.
Get-ChildItem ".\FileStore" |
Select-Object Name, PSPath |
Add-Member -MemberType MemberSet `
-Name PSStandardMembers `
-Value ([System.Management.Automation.PSPropertySet]::new(
'DefaultDisplayPropertySet',
[string[]]('Name')
)) `
-PassThru |
Out-GridView -PassThru -Title "Quick Notes" |
Get-Content | Set-Clipboard

That looks very like my answer to a deleted question from user Adam partly surfacing in a follow-up question
My answer (with a different path) was this:
Get-ChildItem -Path ".\FileStore" |
Select-Object Name,FullName |
Out-GridView -PassThru -Title "Quick Notes"|
ForEach-Object{Get-Content $_.Fullname | Set-Clipboard -Append}

Related

How to get a list of files into a Powershell array

I want to get a list of files into a Powershell variable that I can use in subsequent code.
Files:
file1.csv
file2.csv
$sourceFiles = Get-ChildItem .\file*.csv
But the output that I get is:
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 4/10/2022 1:52 AM 31 file1.csv
-a---- 4/10/2022 1:52 AM 31 file2.csv
I am trying to get the output $sourceFiles = "file1.csv","file2.csv"
How is the best way to do this?
You should add -Name to the Get-ChildItem command.
$sourceFiles = Get-ChildItem .\file*.csv -Name
Write-Host $sourceFiles
According with documentation -Name does the job.
Gets only the names of the items in the location. The output is a string object that can be sent down the pipeline to other commands. Wildcards are permitted.
I'm in need of this these days, and I ended up writing a PowerShell script:
$InputFolder = $args[0]
$OutputFile = $args[1]
$BinStream = [System.IO.FileStream]::new($OutputFile,[System.IO.FileMode]::OpenOrCreate)
$BinWriter = [System.IO.BinaryWriter]::new($BinStream)
$InputFolder
| Get-ChildItem
| Sort-Object -Property LastWriteTime
| ForEach-Object {
$Data = $_ | Get-Content -AsByteStream -Raw
$BinWriter.Write($Data)
}
$BinWriter.Close()
You can sort by a different object property, maybe datetime of creation, LastWriteTime just happens to be the one that I needed. The reason I cannot sort by name is that my file names do not have the index suffix padded with zeros.
There's probably a more straight-forward way, without diving into .NET classes, but I don't have much of a PowerShell skill, so whatever I put together to satisfy my immediate need is a result of quick googling and browsing through PowerShell reference online.

How to delete a specific snapshot using Powershell in Hyper-V

Dears,
I am trying to delete a specific snapshot for one of our VMs but all the snapshots are being deleted instead.
PS C:\Users\abood> Get-VMSnapshot -VMName KUW-HV01
VMName Name SnapshotType CreationTime ParentSnapshotName
------ ---- ------------ ------------ ------------------
KUW-HV01 OLD Standard 7/22/2020 9:17:48 PM
KUW-HV01 NEW Standard 7/22/2020 9:18:08 PM OLD
PS C:\Users\abood> Remove-VMSnapshot -VMName KUW-HV01 -WhatIf | Where-Object {$_.Name -eq "NEW"}
What if: Remove-VMSnapshot will remove snapshot "NEW".
What if: Remove-VMSnapshot will remove snapshot "OLD".
How can i delete only "NEW" or "OLD" while keeping the other one?
Thanks in advance,
Most cmdlets that take an action against something (such as Remove-VMSnapshot) will allow you to pipe objects into them to specify what objects to take that action against. For example, you already used Get-VMSnapshot to get the two snapshots of that specific VM. You can then use Where-Object to specify only the snapshot you want to delete and filter out any that you want to keep like this:
Get-VMSnapshot -VMName KUW-HV01 | Where-Object {$_.Name -eq "NEW"}
VMName Name SnapshotType CreationTime ParentSnapshotName
------ ---- ------------ ------------ ------------------
KUW-HV01 NEW Standard 7/22/2020 9:18:08 PM OLD
Then you pipe that to Remove-VMSnapshot to specify exactly what you want to remove.
Get-VMSnapshot -VMName KUW-HV01 | Where-Object {$_.Name -eq "NEW"} | Remove-VMSnapshot -WhatIf
That should result in this:
What if: Remove-VMSnapshot will remove snapshot "NEW".

Compare two text files with duplicates and write the distinct differences to text file

I want to compare 2 text files and output the difference in another text file.
compare-object (get-content c:\temp\hostname_old.txt) (get-content c:\temp\hostname_new.txt) | Select-Object -ExpandProperty InputObject | Out-File $Location
hostname_old.txt
server02
server05
server04
server06
server01
hostname_new.txt (has duplicate names)
server04
server01
server02
server04
server02
Result:
server04
server02
server05
server06
Note how server04 and server02 are present in this list of differences, even though they're present in both input files.
This is what I want:
server05
server06
Use Select-Object -Unique to eliminate the duplicates before comparing:
compare-object -PassThru `
(get-content c:\temp\hostname_old.txt) `
(get-content c:\temp\hostname_new.txt | Select-Object -Unique)
As in this answer to your previous question, -PassThru is used to pass out the differing lines directly, without the [pscustomobject] wrappers (that indicate the source set of the difference via their .SideIndicator property) that Compare-Object outputs by default.

How to group Get-ChildItem -Recurse results in one output table?

I'm using the following Powershell command:
Get-ChildItem -Recurse *.txt
But if there's multiple results the output will be like this:
Directory: C:\TestFolder\myfolder\
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- d/m/yyyy hh:MM PM 1234 dragons.txt
Directory: C:\TestFolder\anotherfolder\
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- d/m/yyyy hh:MM PM 66550 jabberwocky.txt
But I want to get grouped results in some form.
Maybe like this:
Mode LastWriteTime Length Directory Name
---- ------------- ------ --------- ----
-a--- d/m/yyyy hh:MM PM 1234 C:\TestFolder\myfolder\ dragons.txt
-a--- d/m/yyyy hh:MM PM 66550 C:\TestFolder\anotherfolder\ jabberwocky.txt
Or this:
Length FullPath
------ --------
1234 C:\TestFolder\myfolder\dragons.txt
66550 C:\TestFolder\anotherfolder\jabberwocky.txt
You probably get the idea. How can I accomplish this, preferably in a simple and elegant manner?
I tried Get-ChildItem -Recurse *.txt | Format-Table but that doesn't do much. I've also checked the most relevant similar questions suggested by Stack Overflow (i.e. "Recurse with PowerShell's Get-ChildItem", and others), but haven't been able to distill a solution so far.
Addendum:
I used help group and found that group is actually the exact alias for the Cmdlet I thought I was looking for: Group-Object. If I do this:
Get-ChildItem -Recurse *.txt | Group-Object "FullName"
I get:
Count Name Group
----- -------- -----
1 C:\TestFold... {C:\TestFolder\myfolder\dragons.txt}
1 C:\TestFold... {C:\TestFolder\anotherfolder\jabberwocky.txt}
But this requires me to simplify with an additional step to:
Get-ChildItem -Recurse *.txt | Group-Object "FullName" | Select-Object "Name"
Which gets:
Name
----
C:\TestFolder\myfolder\dragons.txt
C:\TestFolder\anotherfolder\jabberwocky.txt
If I really want extra properties, then I guess I want to "group on multiple properties", making the question effectively a duplicate of this other SO question.
However, all this "grouping" seems like overkill. Is there not a direct way of using Get-ChildItem to get the output I want?
PowerShell has its own way of displaying System.IO.DirectoryInfo and System.IO.FileInfo objects. If you don't want to see that then you just need to use Select-Object.
Get-ChildItem -Recurse c:\temp | select Mode,LastWriteTime,Length,Directory,Name
Group-Object is completely unnecessary. Given your need I suppose Group-Object seemed appealing but its power is not needed here like it is used for in the linked question. What you really wanted to do is change how PowerShell deals with those objects. Format-Table does not work for the same reason. It was taking the PowerShell by design output and making a table. If you called the properties with Format-Table you would have the same solution as we did with Select-Object.
Get-ChildItem -Recurse c:\temp | Format-Table Mode,LastWriteTime,Length,Directory,Name
Please... Please... don't use that line if you intend to use the output in other functions. Format-cmdlets break objects and are used for the purpose of displaying data only.
If you are just trying to get a list of files recursively with their fullpath names, don't use Group or Select. All of these Commands pretends to be a spreadsheet of objects displayed in a text console.
Instead use the foreach-object operator "%{ }" to dump the raw string date to the console. Example:
Get-ChildItem -Recurse *.txt | %{ $_.fullname }
(Incidentally the above is equivalent to linux command: "find .")
If you want to see which fields are accessible from the foreach-object script block. you can issue this command:
Get-ChildItem my_filepath | get-member
Alternatively, you could pipe the output of Get-ChildItem to Export-Csv command and open it in notepad.
Get-ChildItem -Recurse -file *.txt |
Select FullName |
Export-Csv "files.csv"
notepad files.csv
Alternatively, use cmd:
cmd /c dir /b /s *.txt

Why does grouping the output of a Powershell pipe sometimes not work?

I have read that when the output of Format-Table (with -GroupBy) is not
grouped, you need to 1. sort and 2. pass -AutoSize. Sometimes this does not
seem to work. This is te test case I came up with:
PS C:\> ls -Path C:\Windows\help -Include "*.chm" -Recurse|sort Directory|ft -GroupBy Directory -Auto
Directory: C:\Windows\help
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 23.05.2011 10:54 21544 NVWCPFI.chm
Directory: C:\Windows\help
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 23.05.2011 10:54 21879 NVWCPESM.chm
...
Why is the output not grouped by directory? Why are there two separate entries
for the same directory? How can I group the output? (Please ignore the fact,
that output of the first command is already grouped, I just use this command as
a test case.)
Edit
As pointed out I initially forgot the the Directory argument to sort. (The output still has the same problem.)
I am using Powershell 2.0
In order to group output in Format-Table it first needs to be sorted. A technet blog, which has a discussion on this, is here. While you do have a Sort-Object cmdlet you dont choose a value to sort on. Note I do not get the same output at you with your cmdlet on powershell 3.0
Get-ChildItem -Path C:\Windows\help -Include "*.chm" -Recurse| Sort-Object Directory | Format-Table -GroupBy Directory
The output will indeed be sorted but i gather this is not what you are looking for. Another approach that might be more desired would be to use Select-Object to only output the desired information.
Get-ChildItem -Path C:\Windows\help -Include "*.chm" -Recurse| Sort-Object Directory | Select Name,Directory | Format-Table -AutoSize
You would need to experiment with the values of Select-Object to get your desired output. The next example would give you count information of chm's in folders. Not Format-Table related at all but interesting none the less.
Get-ChildItem -Path C:\Windows\help -Include "*.chm" -Recurse | Group-Object Directory
Try this if work:
...|sort directory |ft -GroupBy...