VSS - Delete snapshots having the same date, but different timestamp

This topic contains 5 replies, has 3 voices, and was last updated by Profile photo of Artion Karreci Artion Karreci 7 months ago.

Viewing 6 posts - 1 through 6 (of 6 total)
  • Author
    Posts
  • #35512
    Profile photo of Artion Karreci
    Artion Karreci
    Participant

    I am trying to write a PS script that would do the following:

    Creates a persistent, client accessible, shadow copy of the volume
    Parses the existing snapshots and deletes those having the same date, but different timestamp, older than yesterday, keeping only the latest of that date.
    Deletes snapshots older than a month

    The script will run as a scheduled task every hour since power on.

    This is an effort to circumscribe the damage of a cryptoplocker attack.

    I found some code to accomplish part of it (the first and the third), but i don't know how to accomplish the second one. Follows the code I found googling:

    #get static method
    $shadow=[WMICLASS]"root\cimv2:win32_shadowcopy"

    #create a new shadow copy
    $shadow.create($Drive, "ClientAccessible")

    #PowerShell Script
    #This script deletes all shadow copies older than 30 days
    #By Wayne Johnson

    Get-WmiObject Win32_Shadowcopy | ForEach-Object {
    $WmiSnapShotDate = $_.InstallDate
    $strShadowID = $_.ID
    $dtmSnapShotDate = [management.managementDateTimeConverter]::ToDateTime($WmiSnapShotDate)
    $strClientAccessible = $_.ClientAccessible
    $dtmCurDate = Get-Date
    $dtmTimeSpan = New-TimeSpan $dtmSnapShotDate $dtmCurDate
    $intNumberDays = $dtmTimeSpan.Days
    If ($intNumberDays -ge 31 -and $strClientAccessible -eq "True") {
    $_.Delete()
    }
    }

    #35565
    Profile photo of random commandline
    random commandline
    Participant

    I am confused by your request. Do you need to keep the latest shadow copy for each day then, at a later date, delete latest copies that are a month old? So far, what I have below will group copies, select the groups older than yesterday, and select the latest copy of each group.

    # Group shadowcopies by date
    $groups = (Get-WmiObject  -Class win32_shadowcopy) | ForEach-Object {
    $datetime = $_.convertToDateTime($_.installdate)
        [pscustomobject]@{
        pscomputername = $_.pscomputername
        deviceobject = $_.deviceobject
        id = $_.id
        providerid = $_.providerid
        installdate = $_.installdate
        datetime = $datetime
        date = $datetime.date
        ClientAccessible = $_.ClientAccessible
        }} | Group-Object -Property date
    
    # Select shadow copy groups older than yesterday
    $groups | Where-Object {$_.group.date -lt (Get-Date).AddDays(-1)}
    
    # Select latest copy for each date
    $groups | ForEach-Object {$_.group | Select-Object -Last 1}
    
    #35579
    Profile photo of Yuan Li
    Yuan Li
    Participant

    My script is similar to random's. I just add another loop so it will check the ID and delete those snapshots that no need anymore.

    $delsnap=@()
    Get-WmiObject -ComputerName sydittest -Class win32_shadowcopy | 
    select deviceobject,ID,@{n='datetime';e={[management.managementDateTimeConverter]::ToDateTime($_.installdate)}},@{n='dayofyear';e={[management.managementDateTimeConverter]::ToDateTime($_.installdate).dayofyear}} | 
    group dayofyear | Where-Object{$_.dayofyear -lt (get-date).DayOfYear} |
    foreach {
    
    if ($_.count -gt 1){
    
    $max=$_.count-1
    
    for($i=0;$i -lt $max;$i++ ){
    
    $temp=[pscustomobject]@{id=$_.group[$i].id}
    $delsnap+=$temp
    }
    }
    
    
    }
    
    $delsnap | foreach{
    
    $id=$_.id.ToString()
    
    Get-WmiObject -ComputerName sydittest -Class win32_shadowcopy | foreach {
    if($_.id -eq $id){
    
    $_.delete() 
    }
    
    
    
    }
    
    }
    
    
    #35608
    Profile photo of Artion Karreci
    Artion Karreci
    Participant

    Thank you both very much. in a few days i'll test the final script and let know.
    @random: Yes the idea is to keep all the snapshots of the last two days and the last snapshot of the day not more than a month. So in 24/7 system when the script starts it will take ≈ 24 snapshots a day for a total of ≈ 48 snapshots in two days. After that, on the third day of execution, it will delete all the snapshots that are more than 2 days older but the latest of that day. This way after 31 days of execution i'll have 28 latest of the day snapshots plus ≈ 48 hourly snapshots of the last two days.

    #35663
    Profile photo of Artion Karreci
    Artion Karreci
    Participant

    @random commandline
    I tried the script. I have to find a manner to select not the last of the day but all the others but the last to delete them. I tried the -SkipLast 1 but it is not supported in PSH 4. I tried also the sort-object reverse and keep -Skip 1 but it keeps sorting from the farest to the latest.

    @Yuan Li
    I tried also your script, but it deletes all snapshots but the last of today also. I'll try to find a manner to make it work.

    @both of you
    Thank you very much. At least i'm in the right way.

    #35674
    Profile photo of Artion Karreci
    Artion Karreci
    Participant

    Hi,
    this is the final script. Any suggestions to optimize it?

    # Create shadowcopy of D:\ for Previous versions
    
    $shadow = [WMICLASS]"root\cimv2:win32_shadowcopy"
    $shadow.create("D:\", "ClientAccessible")
    
    # Group shadowcopies by date sorted by time descending
    $CurrDate = Get-Date
    $groups = (Get-WmiObject  -Class win32_shadowcopy) | ForEach-Object {
    	$datetime = $_.convertToDateTime($_.installdate)
        [pscustomobject]@{
    		pscomputername = $_.pscomputername
    		deviceobject = $_.deviceobject
    		id = $_.id
    		providerid = $_.providerid
    		installdate = $_.installdate
    		datetime = $datetime
    		date = $datetime.ToShortDateString()
    		time = $datetime.ToShortTimeString()
    		timespan = (New-TimeSpan $datetime $CurrDate).Days
    		ClientAccessible = $_.ClientAccessible
        }
    } | Sort-Object -property @{
    		Expression="time";Descending=$true
    		} | Group-Object -Property date
    
    # Select shadowcopy groups older than yesterday but the latest of the day
    
    $oldshadow = $groups | Where-Object {
    				$_.group.date -lt (Get-Date).AddDays(-2)
    				} | ForEach-Object {
    					$_.group | Select-Object -Skip 1
    					}
    					
    # Select shadowcopy groups older than 31 days					
    					
    $oldestshadow = $groups | Where-Object {
    				$_.group.timespan -ge 31
    				} | ForEach-Object {
    					$_.group | Select-Object
    					}	
    
    # Delete all shadowcopies older than yesterday but the latest of the day or older than a month
    			
    $shadow2 = Get-WmiObject Win32_ShadowCopy					
    $oldshadow | ForEach-Object {
    					$shadow2.Delete()
    					}
    $oldestshadow | ForEach-Object {
    					$shadow2.Delete()
    					}
    
Viewing 6 posts - 1 through 6 (of 6 total)

You must be logged in to reply to this topic.