Watch Demo×
×

See NinjaOne in action!

By submitting this form, I accept NinjaOne's privacy policy.

Optimize Your IT Management: Mastering Hyper-V Replication Monitoring with PowerShell

Key takeaways

  • Automated Hyper-V replication monitoring: The script automates the process of monitoring Hyper-V replication status, enhancing efficiency in virtual environment management.
  • Customizable alert thresholds: Administrators can set custom thresholds for replication alerts using parameters like -FailedFor.
  • Elevated permissions required: Running the script requires administrator privileges to access detailed VM replication information.
  • Environment-specific customization: Utilize environment variables and custom fields to tailor the script’s functionality to specific IT environments.
  • Proactive IT management tool: The script serves as a proactive tool for IT professionals, ensuring timely identification and resolution of replication issues.
  • Enhanced over manual methods: Offers a more comprehensive and automated approach compared to manual checks or basic scripts.
  • Integral part of IT infrastructure management: When integrated with platforms like NinjaOne, the script adds significant value to managing and securing IT infrastructure.
  • Requires PowerShell 5.1 or newer: Ensure compatibility and functionality with the appropriate version of PowerShell.

Effective management of virtual environments is crucial for IT professionals, ensuring optimal performance and security. One key aspect of this is monitoring and managing Hyper-V replication, a feature widely used in virtualized networks for redundancy and failover purposes. Efficient monitoring of Hyper-V replication status ensures business continuity and data integrity in case of unexpected failures.

Background

Hyper-V replication is a mechanism that allows virtual machines (VMs) to replicate from one Hyper-V host to another, providing a crucial disaster recovery solution. IT professionals and Managed Service Providers (MSPs) require robust tools to monitor this replication process. The script we’re discussing serves this exact purpose, enabling administrators to efficiently track the health and status of VM replications and react promptly to any anomalies.

The script:

#Requires -Version 5.1

<#
.SYNOPSIS
    This will get information about the current status of Hyper-V Replication. If its abnormal it'll check the last replication time to see if it should alert on it.
.DESCRIPTION
    This will get information about the current status of Hyper-V Replication. If its abnormal it'll check the last replication time to see if it should alert on it.
.EXAMPLE 
    (No Parameters)
    Replication is currently failing!
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorExcep 
   tion
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorExceptio 
   n,customscript_gen_2.ps1
 

    VMName      PrimaryServer            State   Health LastReplicationTime 
    ------      -------------            -----   ------ ------------------- 
    WIN10-TEST  SRV16-TEST.test.lan      Error Critical 4/13/2023 8:20:11 AM
    Win10-TEST2 SRV16-TEST.test.lan      Error Critical 4/13/2023 8:20:11 AM

PARAMETER: -FailedFor "30"
    Time in minutes any given vm replication is allowed to be abnormal.
    Ex. "20" will alert on a vm replication after its been in the abnormal state for 20 minutes.
.EXAMPLE
    -FailedFor "20"
    WARNING: Some of the vm's currently have replication paused!
 

    VMName      PrimaryServer                  State  Health LastReplicationTime 
    ------      -------------                  -----  ------ ------------------- 
    WIN10-TEST  SRV16-TEST.test.lan      Replicating  Normal 4/13/2023 8:40:04 AM
    Win10-TEST2 SRV16-TEST.test.lan        Suspended Warning 4/13/2023 8:32:06 AM

PARAMETER: -IncludePaused
    Script will consider paused vm's abnormal if this parameter is used.    
.EXAMPLE
    -IncludePaused
    Replication is currently failing!
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorExcep 
   tion
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorExceptio 
   n,customscript_gen_2.ps1
 

    VMName      PrimaryServer                  State  Health LastReplicationTime 
    ------      -------------                  -----  ------ ------------------- 
    WIN10-TEST  SRV16-TEST.test.lan      Replicating  Normal 4/13/2023 8:40:04 AM
    Win10-TEST2 SRV16-TEST.test.lan        Suspended Warning 4/13/2023 8:32:06 AM

PARAMETER: -FromCustomField "ReplaceMeWithAnyIntegerCustomField"
    Name of an integer custom field that contains your desired FailedFor threshold.
    ex. "ReplicationAlertThreshold" where you have entered in your desired alert limit in the "ReplicationAlertThreshold" custom field rather than in a parameter.
.EXAMPLE
    -FromCustomField "ReplaceMeWithAnyIntegerCustomField"
    WARNING: Some of the vm's currently have replication paused!
 

    VMName      PrimaryServer                  State  Health LastReplicationTime 
    ------      -------------                  -----  ------ ------------------- 
    WIN10-TEST  SRV16-TEST.test.lan      Replicating  Normal 4/13/2023 8:40:04 AM
    Win10-TEST2 SRV16-TEST.test.lan        Suspended Warning 4/13/2023 8:32:06 AM
.OUTPUTS
    None
.NOTES
    Minimum OS Architecture Supported: Windows 10, Server 2016
    Release Notes: Renamed script and added Script Variable support
By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use.
    Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. 
    Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. 
    Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. 
    Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. 
    Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. 
    Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. 
    EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).
#>

[CmdletBinding()]
param (
    [Parameter()]
    [int]$FailedFor = "60",
    [Parameter()]
    [String]$FromCustomField,
    [Parameter()]
    [Switch]$IncludePaused = [System.Convert]::ToBoolean($env:includePausedReplications)
)
begin {

    if ($env:allowedToFailForxMinutes -and $env:allowedToFailForxMinutes -notlike "null") { $FailedFor = $env:allowedToFailForxMinutes }
    if ($env:retrieveAllowedFailureTimeFromCustomField -and $env:retrieveAllowedFailureTimeFromCustomField -notlike "null" ) { $FromCustomField = $env:retrieveAllowedFailureTimeFromCustomField }

    function Test-IsElevated {
        $id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
        $p = New-Object System.Security.Principal.WindowsPrincipal($id)
        $p.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
    }

    function Test-IsSystem {
        $id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
        return $id.Name -like "NT AUTHORITY*" -or $id.IsSystem
    }

    if (!(Test-IsElevated) -and !(Test-IsSystem)) {
        Write-Error -Message "Access Denied. Please run with Administrator privileges."
        exit 1
    }

    # This function is to make it easier to parse Ninja Custom Fields.
    function Get-NinjaProperty {
        [CmdletBinding()]
        Param(
            [Parameter(Mandatory = $True, ValueFromPipeline = $True)]
            [String]$Name,
            [Parameter()]
            [String]$Type,
            [Parameter()]
            [String]$DocumentName
        )

        # If we're requested to get the field value from a Ninja document we'll specify it here.
        $DocumentationParams = @{}
        if ($DocumentName) { $DocumentationParams["DocumentName"] = $DocumentName }

        # These two types require more information to parse.
        $NeedsOptions = "DropDown","MultiSelect"

        # Grabbing document values requires a slightly different command.
        if ($DocumentName) {
            # Secure fields are only readable when they're a device custom field
            if ($Type -Like "Secure") { throw "$Type is an invalid type! Please check here for valid types. https://ninjarmm.zendesk.com/hc/en-us/articles/16973443979789-Command-Line-Interface-CLI-Supported-Fields-and-Functionality" }

            # We'll redirect the error output to the success stream to make it easier to error out if nothing was found or something else went wrong.
            Write-Host "Retrieving value from Ninja Document..."
            $NinjaPropertyValue = Ninja-Property-Docs-Get -AttributeName $Name @DocumentationParams 2>&1

            # Certain fields require more information to parse.
            if ($NeedsOptions -contains $Type) {
                $NinjaPropertyOptions = Ninja-Property-Docs-Options -AttributeName $Name @DocumentationParams 2>&1
            }
        }
        else {
            # We'll redirect error output to the success stream to make it easier to error out if nothing was found or something else went wrong.
            $NinjaPropertyValue = Ninja-Property-Get -Name $Name 2>&1

            # Certain fields require more information to parse.
            if ($NeedsOptions -contains $Type) {
                $NinjaPropertyOptions = Ninja-Property-Options -Name $Name 2>&1
            }
        }

        # If we received some sort of error it should have an exception property and we'll exit the function with that error information.
        if ($NinjaPropertyValue.Exception) { throw $NinjaPropertyValue }
        if ($NinjaPropertyOptions.Exception) { throw $NinjaPropertyOptions }

        # This switch will compare the type given with the quoted string. If it matches, it'll parse it further; otherwise, the default option will be selected.
        switch ($Type) {
            "Attachment" {
                # Attachments come in a JSON format this will convert it into a PowerShell Object.
                $NinjaPropertyValue | ConvertFrom-Json
            }
            "Checkbox" {
                # Checkbox's come in as a string representing an integer. We'll need to cast that string into an integer and then convert it to a more traditional boolean.
                [System.Convert]::ToBoolean([int]$NinjaPropertyValue)
            }
            "Date or Date Time" {
                # In Ninja Date and Date/Time fields are in Unix Epoch time in the UTC timezone the below should convert it into local time as a datetime object.
                $UnixTimeStamp = $NinjaPropertyValue
                $UTC = (Get-Date "1970-01-01 00:00:00").AddSeconds($UnixTimeStamp)
                $TimeZone = [TimeZoneInfo]::Local
                [TimeZoneInfo]::ConvertTimeFromUtc($UTC, $TimeZone)
            }
            "Decimal" {
                # In ninja decimals are strings that represent a decimal this will cast it into a double data type.
                [double]$NinjaPropertyValue
            }
            "Device Dropdown" {
                # Device Drop-Downs Fields come in a JSON format this will convert it into a PowerShell Object.
                $NinjaPropertyValue | ConvertFrom-Json
            }
            "Device MultiSelect" {
                # Device Multi-Select Fields come in a JSON format this will convert it into a PowerShell Object.
                $NinjaPropertyValue | ConvertFrom-Json
            }
            "Dropdown" {
                # Drop-Down custom fields come in as a comma-separated list of GUIDs; we'll compare these with all the options and return just the option values selected instead of a GUID.
                $Options = $NinjaPropertyOptions -replace '=', ',' | ConvertFrom-Csv -Header "GUID", "Name"
                $Options | Where-Object { $_.GUID -eq $NinjaPropertyValue } | Select-Object -ExpandProperty Name
            }
            "Integer" {
                # Cast's the Ninja provided string into an integer.
                if($NinjaPropertyValue){
                    [int]$NinjaPropertyValue
                }else{
                    $NinjaPropertyValue
                }
            }
            "MultiSelect" {
                # Multi-Select custom fields come in as a comma-separated list of GUID's we'll compare these with all the options and return just the option values selected instead of a guid.
                $Options = $NinjaPropertyOptions -replace '=', ',' | ConvertFrom-Csv -Header "GUID", "Name"
                $Selection = ($NinjaPropertyValue -split ',').trim()

                foreach ($Item in $Selection) {
                    $Options | Where-Object { $_.GUID -eq $Item } | Select-Object -ExpandProperty Name
                }
            }
            "Organization Dropdown" {
                # Turns the Ninja provided JSON into a PowerShell Object.
                $NinjaPropertyValue | ConvertFrom-Json
            }
            "Organization Location Dropdown" {
                # Turns the Ninja provided JSON into a PowerShell Object.
                $NinjaPropertyValue | ConvertFrom-Json
            }
            "Organization Location MultiSelect" {
                # Turns the Ninja provided JSON into a PowerShell Object.
                $NinjaPropertyValue | ConvertFrom-Json
            }
            "Organization MultiSelect" {
                # Turns the Ninja provided JSON into a PowerShell Object.
                $NinjaPropertyValue | ConvertFrom-Json
            }
            "Time" {
                # Time fields are given as a number of seconds starting from midnight. This will convert it into a datetime object.
                $Seconds = $NinjaPropertyValue
                $UTC = ([timespan]::fromseconds($Seconds)).ToString("hh\:mm\:ss")
                $TimeZone = [TimeZoneInfo]::Local
                $ConvertedTime = [TimeZoneInfo]::ConvertTimeFromUtc($UTC, $TimeZone)

                Get-Date $ConvertedTime -DisplayHint Time
            }
            default {
                # If no type was given or not one that matches the above types just output what we retrieved.
                $NinjaPropertyValue
            }
        }
    }
}
process {
    if ($FromCustomField) {
        try{
            $CustomFieldValue = Get-NinjaProperty -Name $FromCustomField -Type "Integer"
        }catch{
            Write-Warning "$($_.ToString())"
        }

        if($CustomFieldValue){
            $FailedFor = $CustomFieldValue
        }else{
            Write-Warning "Custom Field $FromCustomField was empty?"
        }
    }

    if($FailedFor -gt 0){
        $FailedFor = $FailedFor * -1
    }

    $Threshold = (Get-Date).AddMinutes($FailedFor)
    Write-Host "Checking vm's that have not replicated prior to $Threshold."

    $Failed = New-Object System.Collections.Generic.List[string]
    $UnhealthyVMs = Get-VMReplication | Where-Object { $_.Health -notlike "Normal" -and $_.LastReplicationTime -lt $Threshold -and $_.State -notlike "Suspended" }
    $PausedVMs = Get-VMReplication | Where-Object { $_.LastReplicationTime -lt $Threshold -and $_.State -like "Suspended" }

    if ($UnhealthyVMs) {
        $Failed.Add($UnhealthyVMs)
    }
    
    if ($PausedVMs) {
        Write-Warning "Some of the vm's currently have replication paused!"

        if(-not $IncludePaused){
            Write-Warning "Please use 'Include Paused Replications' to include paused replications in the alert. Otherwise, they will be skipped."
        }
    }

    if ($PausedVMs -and $IncludePaused) {
        $Failed.Add($PausedVMs)
    }

    if ($Failed) {
        Write-Error "Hyper-V Replication is currently failing!"
        Get-VMReplication | Format-Table -Property VMName, PrimaryServer, State, Health, LastReplicationTime | Out-String | Write-Host
        exit 1
    }
    else {
        Write-Host "No failing replications detected prior to $Threshold."

        Get-VMReplication | Format-Table -Property VMName, PrimaryServer, State, Health, LastReplicationTime | Out-String | Write-Host
        exit 0
    }
}end {
    
    
    
}

 

Access over 300+ scripts in the NinjaOne Dojo

Get Access

Detailed breakdown

The script is a PowerShell utility designed to monitor the status of Hyper-V replication. It checks each VM’s replication status and health, alerting administrators if there are any issues. Key components of the script include:

  • Cmdlet binding and parameters: The script uses advanced functions, allowing parameters like -FailedFor, -FromCustomField, and -IncludePaused.
  • Environment variables and functions: It utilizes custom functions and environment variables to determine elevated permissions and retrieve custom field values.
  • Main process: The script assesses each VM’s replication health and time, comparing them against specified thresholds. If any VMs have not replicated within the designated timeframe or are in an abnormal state, it triggers an alert.

This script could be visually represented in a flowchart, detailing the steps from initialization, parameter setting, permission checking, to the final analysis and alerting.

Potential use cases

Imagine an IT administrator in a medium-sized enterprise with a robust virtualized environment using Hyper-V. They would deploy this script to regularly monitor VM replication status, quickly identifying and addressing any replication issues, thus ensuring business continuity.

Comparisons

Traditionally, monitoring Hyper-V replication involves manual checks or less sophisticated scripts. This script, however, automates the process and provides more comprehensive and customizable monitoring. It surpasses basic PowerShell commands or manual GUI checks in efficiency and scalability.

FAQs

Q: Can this script run on any version of PowerShell?
A: It requires PowerShell 5.1 or later.

Q: Is it necessary to run the script with administrator privileges?
A: Yes, the script checks for elevated privileges as it needs access to VM replication details.

Q: How can I customize the alert threshold?
A: Use the -FailedFor parameter to set a custom time frame in minutes.

Implications

While this script enhances Hyper-V replication monitoring, it also underscores the need for proactive IT security measures. Prompt detection and resolution of replication issues are vital in maintaining data integrity and availability.

Recommendations

  • Regularly run the script to ensure ongoing monitoring.
  • Adjust the -FailedFor parameter based on specific environment needs.
  • Ensure PowerShell 5.1 or later is installed and running with the necessary permissions.

Final thoughts

In the context of managing virtualized environments, tools like NinjaOne provide a comprehensive platform for monitoring and managing IT infrastructure. Incorporating a script like this into a larger suite of NinjaOne’s tools can enhance an organization’s ability to manage Hyper-V environments efficiently, ensuring reliability and performance.

Next Steps

Building an efficient and effective IT team requires a centralized solution that acts as your core service deliver tool. NinjaOne enables IT teams to monitor, manage, secure, and support all their devices, wherever they are, without the need for complex on-premises infrastructure.

Learn more about NinjaOne Remote Script Deployment, check out a live tour, or start your free trial of the NinjaOne platform.

Categories:

You might also like

NinjaOne Terms & Conditions

By clicking the “I Accept” button below, you indicate your acceptance of the following legal terms as well as our Terms of Use:

  • Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms.
  • Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party.
  • Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library belonging to or under the control of any other software provider.
  • Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations.
  • Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks.
  • Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script.
  • EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).