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

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".

Related

PowerShell - Find Oldest Email

I am stuck, I am trying to find the oldest "EMAIL" in a person's mailbox, but I don't know what else to try. I think I need to add the ContainerClass -eq "IPF.Note" somewhere, but I am not sure where.
The following script works, but it finds the oldest ITEM, which in my case it is a contact. I want to look at each container (Email, Chats, Calendar, Contacts) separately, but for this script, I just want to know the oldest email.
Thank you
Get-MailboxFolderStatistics -IncludeOldestAndNewestItems -Identity USERID |
Where OldestItemReceivedDate -ne $null |
Sort OldestItemReceivedDate |
Select -First 1 OldestItemReceivedDate
You can filter what you have by item type, but I would do it after getting the statistics so you only have to query exchange once:
# Get the folder statistics for all folders
$stats = Get-MailboxFolderStatistics -IncludeOldestAndNewestItems -Identity $USERID
# Get the oldest email. Can re-use $stats for the other item types
$OldestEmail = $stats |
Where-Object {$_.OldestItemReceivedDate -and $_.ContainerClass -eq 'IPF.Note'} |
Sort-Object OldestItemReceivedDate |
Select-Object ContainerClass,OldestItemReceivedDate,FolderPath -First 1
# Outputs
ContainerClass OldestItemReceivedDate FolderPath
-------------- ---------------------- ----------
IPF.Note 2/8/2016 2:07:50 PM /Inbox
You are correct that the mailbox folder statistics command does not search recoverable items by default. It also does not search the mailbox archive unless you specify -Archive. If you need these, you'll have to do additional searches:
# Get recoverable items:
Get-MailboxFolderStatistics -Identity $USERID -FolderScope 'RecoverableItems' -IncludeOldestAndNewestItems |
Where-Object OldestItemReceivedDate |
Sort-Object OldestItemReceivedDate |
Select-Object ContainerClass,OldestItemReceivedDate,FolderPath -First 1
# Note that deleted item containers do not have an item type!
ContainerClass OldestItemReceivedDate FolderPath
-------------- ---------------------- ----------
2/5/2016 3:41:33 PM /Deletions
Presuming this is for compliance reasons to search a mailbox for items on an Exchange Server you should be using the Search-Mailbox cmdlet - https://learn.microsoft.com/en-us/powershell/module/exchange/search-mailbox?view=exchange-ps
For Exchange Online to search a mailbox for items you should use the New-ComplianceSearch cmdlet https://learn.microsoft.com/en-us/powershell/module/exchange/new-compliancesearch?view=exchange-ps
This web page shows how to search by date - New-ComplianceSearch: how to use the newer version of Search-Mailbox https://www.codetwo.com/admins-blog/new-compliancesearch-new-version-of-search-mailbox/
This web page has a script to search mailboxes, including dates PowerShell – New-ComplianceSearch script to go through all mailboxes, find a target message, and remove it - https://365basics.com/powershell-new-compliancesearch-script-to-go-through-all-mailboxes-find-a-target-message-and-remove-it/
Using your original approach, should be done like this. Presuming you have appropriate permissions.
Get-MailboxFolderStatistics -ID <mailboxemailaddress> -IncludeOldestAndNewestItems | select Identity, Name, FolderPath, ItemsInFolder, FolderSize, OldestItemReceivedDate | Export-Csv C:\temp\Mailbox.csv -NoTypeInformation

Select-Object with Out-GridView

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}

Get-ChildItem -File or -Directory doesn't work under different user context

I have a PowerShell cmdlet with the following line
$items = Get-ChildItem -Path $FolderName -File -Force |
Sort CreationTime |
Select -First 1 -Last 1
It works fine under my normal login but if I log onto my machine as a domain admin I get an error message telling me that -File is not recognised as a valid parameter for Get-ChildItem.
I suspected that the domain admin was running an earlier version of PowerShell so under both accounts I have run $PSVersionTable.PSVersion and get the following:
Major Minor Build Revision
----- ----- ----- --------
5 0 10586 117
If anything I would expect my local login to fail and the domain admin login to succeed due to permissions differences but it seems to be working the other way around.
Could Get-ChildItem somehow have been overwritten in your $profile or something else?
You can check what Get-ChildItem executes if you run this:
get-command Get-ChildItem
CommandType Name Version Source
----------- ---- ------- ------
Cmdlet Get-ChildItem 3.1.0.0 Microsoft.PowerShell.Management
If it is overwritten by doing something like this:
Function Get-ChildItem { }
Then it will would show this:
get-command Get-ChildItem
CommandType Name Version Source
----------- ---- ------- ------
Function Get-ChildItem
If that would be the case, you can remove the custom version with
Remove-Item Function:\Get-ChildItem
You could also try to not use the -File parameter, and rather filter out folders yourself:
$items = Get-ChildItem -Path $FolderName -Force |
Where PSIsContainer -eq $False |
Sort CreationTime |
Select -First 1 -Last 1
The problem can be resolved by ensuring that the PATH and PSModulePath variables are set to include the location of the ps1 scripts.
In this particular case the PATH and PSModulePath variable included the scripts location for the 1st user but not the 2nd user.
By correcting this the scripts ran successfully for the 2nd user login.

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...