Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some feature requests #28

Open
4 of 5 tasks
TripleNico opened this issue Apr 29, 2023 · 2 comments
Open
4 of 5 tasks

Some feature requests #28

TripleNico opened this issue Apr 29, 2023 · 2 comments
Assignees
Labels
enhancement New feature or request

Comments

@TripleNico
Copy link

TripleNico commented Apr 29, 2023

First of all let me say i really like you're way of scripting and love to see your enthusiasm in your work.

Last year i've made my own version of you script then because i needed to be more lightweight and there were a few things not available then like the -LowDisk switch. But today i've check what you've been working at and i'm impressed, it almost fits my need and i know it's a lot to ask (since i can do it myself) but could you consider to add these features?

  • Switch called -SendStatusUpdate: this features send after every VM a email with the status of that VM export. For example, in my case i have a few VM's that are TB's and the script runs at night. When it's morning i can see due to the emails where the backup script is in the process. I simply put a SendEmail at the end of the ForEach VM (Check second code block below)
  • Switch calles -OptimizeVHD: this features uses the Optimize-VHD function before copying it to the backup destination. Example of the code i use inside the ForEach VM:
#Optimze the VHDX
Try {
    Write-Log -Type Info -Evt "Optimizing VHD(s)..."
    $VMVHDS = Get-VHD -Path $($Vm | Get-VMHardDiskDrive | Select-Object -ExpandProperty "Path")
    #Loop through each VHD(X) file of an VM an optimize it
    ForEach ($VHD in $VMVHDS) {
        #Now optimize the VHD to save space and therefore shorten the copy time
        Write-Log -Type Info -Evt "Used space before optimizing VHD [$($VHD.Path)] = $([math]::ceiling((Get-VHD -Path $VHD.Path).FileSize / 1GB )) GB"
        Optimize-VHD -Path "$($VHD.Path)" -Mode Full
        Write-Log -Type Info -Evt "Used space after optimizing VHD [$($VHD.Path)] = $([math]::ceiling((Get-VHD -Path $VHD.Path).FileSize / 1GB )) GB"
        $intTotalDisksSize += (Get-VHD -Path $VHD.Path).FileSize
    }
    Write-Log -Type Info -Evt "Done optimizing VHD(s)"
}
Catch {
    Write-Log -Type Err -Evt "Error during Optimize-VHD: $($_.Exception.Message)"
}
  • Print the duration of how long it took per VM to back. In my script i simply compare time from the beginning of the ForEach VM and in one of the last lines print the duration. This gives me a pretty good idea how long it takes per VM.
    For example:
Write-Log -Type Info ""
Write-Log -Type Info "-------------------------- Processing VM: $Vm --------------------------------"
$StartTime = $(get-date)

... do stuff ...

$elapsedTime = $(get-date) - $StartTime
$totalTime = "{0:HH:mm:ss}" -f ([datetime]$elapsedTime.Ticks)
SendMail "VM $Vm done" "Processed VM: $Vm in $totalTime"
Write-Log -Type Info "-------------------------- Done processing VM: $Vm in $totalTime --------------------------------"
Write-Log -Type Info ""
  • Switch -PrintVMInfo: this features simply printout all info it could find. For example what i use:
## Print info per VM.
ForEach ($Vm in $Vms) {
    #Get SystemInfo
    Try {
        #Log VM specs
        $VhdSize = Get-VHD -Path $($Vm | Get-VMHardDiskDrive | Select-Object -ExpandProperty "Path") | Select-Object @{Name = "FileSizeGB"; Expression = { [math]::ceiling( $_.FileSize / 1GB ) } }, @{Name = "M
        Write-Output "VM [$Vm] has [$((Get-VMProcessor $Vm).Count)] CPU cores, [$([math]::ceiling((Get-VMMemory $Vm).Startup / 1gb))GB] RAM and Storage [CurrentFileSizeGB = $($VhdSize.FileSizeGB)GB - MaxSizeG
    }
    Catch {
        Write-Error "Error during Systeminfo: $($_.Exception.Message)"
    }
}   
  • Extra funtions start Start and Stop a backupserver. This is something i have in my script because when the backuopserver isn't needed it is shutdown. (For security and power reasons). Snippit of the code:
function Invoke-WakeOnLan {
    param
    (
        # one or more MACAddresses
        [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
        # mac address must be a following this regex pattern:
        [ValidatePattern('^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$')]
        [string[]]
        $MacAddress 
    )
 
    begin {
        # instantiate a UDP client:
        # Support from PowerShell V5.X $UDPclient = [System.Net.Sockets.UdpClient]::new()
        $UDPclient = New-Object -TypeName System.Net.Sockets.UdpClient
    }
    process {
        foreach ($_ in $MacAddress) {
            try {
                $currentMacAddress = $_
        
                # get byte array from mac address:
                $mac = $currentMacAddress -split '[:-]' |
                # convert the hex number into byte:
                ForEach-Object {
                    [System.Convert]::ToByte($_, 16)
                }
 
                #region compose the "magic packet"
        
                # create a byte array with 102 bytes initialized to 255 each:
                $packet = [byte[]](, 0xFF * 102)
        
                # leave the first 6 bytes untouched, and
                # repeat the target mac address bytes in bytes 7 through 102:
                6..101 | Foreach-Object { 
                    # $_ is indexing in the byte array,
                    # $_ % 6 produces repeating indices between 0 and 5
                    # (modulo operator)
                    $packet[$_] = $mac[($_ % 6)]
                }
        
                #endregion
        
                # connect to port 400 on broadcast address:
                $UDPclient.Connect(([System.Net.IPAddress]::Broadcast), 4000)
        
                # send the magic packet to the broadcast address:
                $null = $UDPclient.Send($packet, $packet.Length)
                Write-Log -Type Info -Evt "Sent magic packet to $currentMacAddress..."
            }
            catch {
                Write-Log -Type Err -Evt "Unable to send ${mac}: $_"
            }
        }
    }
    end {
        # release the UDF client and free its memory:
        $UDPclient.Close()
        $UDPclient.Dispose()
    }
}

... later on ...

# Let's start the BackupServer if it's not running
If (Test-Connection -ComputerName "IP/Hostname" -Count 2 -Delay 5 -Quiet ) {
    #Backup server responded meaning it's already online.
    Write-Log -Type Info -Evt "BackupServer is online, waiting 30 seconds just to be sure..."
    Start-Sleep 30
}
else {
    Write-Log -Type Info -Evt "Sending magic packet to BackupServer [$BackupServerMacAddress]"
    Invoke-WakeOnLan -MacAddress "$BackupServerMacAddress" -Verbose
    #Now wait until backupserver is online
    Write-Log -Type Info -Evt "Waiting for BackupServer to come online..."
    If (Test-Connection -ComputerName "IP/Hostname" -Count 12 -Delay 10 -Quiet ) {
        #Backupserver responded now give some extra time for Windows to fully be up and running
        Write-Log -Type Info -Evt "BackupServer is online, waiting 2 more minutes for Windows to complete..."
        Start-Sleep 120
    }
    else {
        Write-Log -Type Err -Evt "Backupserver failed to respond within 2 minutes. BACkUP SCRIPT WILL NOT CONTINUE"
        $MailBody = Get-Content -Path $Log | Out-String
        SendMail "VM Backup: Failed to start backupserver" $MailBody
        Write-Log -Type Info -Evt "Log finished"
        Exit
    }
}


... When done, shutdown ...

## Now shutdown the backup server
Try {
    Write-Log -Type Info -Evt "Waiting for BackupServer to shutdown..."
    Stop-Computer -ComputerName "IP/Hostname" -Credential $credObject -Force
    #Wait until backupserver is down
    While ( Test-Connection "IP/Hostname" -Quiet -Count 1) {
        Start-Sleep -Seconds 10
        #Check if we are waiting more than two minutes
        if ($timer.Elapsed.TotalSeconds -gt 120) {
            Write-Log -Type Err -Evt "Backupserver shutdown did not complete before timeout period."
            Break
        }
    }
    #Double check if server is down or Watchdog has kicked in
    if (-Not (Test-Connection "IP/Hostname" -Quiet -Count 2)) {
        Write-Log -Type Info -Evt "BackupServer succesfully shutdown"
    }
}
catch {
    Write-Log -Type Err -Evt "Error backup shutdown: $($_.Exception.Message)"
}

Those are the points i have, not to bad right ;-)

Again, thanks for all your effort so far!

@Digressive Digressive self-assigned this May 8, 2023
@Digressive Digressive added the enhancement New feature or request label May 8, 2023
@Digressive
Copy link
Owner

Thank you for this, very interesting! I'll work on getting these enhancements implemented in future.

@Digressive
Copy link
Owner

I'm adding all the suggestions here except for the Wake On Lan option for the time being. WOL feels a little out of scope but I'm willing to add it if there's a demand.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants