Hyper-V replica monitor

This topic contains 21 replies, has 4 voices, and was last updated by Profile photo of Daan Weda Daan Weda 1 week, 2 days ago.

  • Author
    Posts
  • #56143
    Profile photo of Bill M
    Bill M
    Participant

    Hi everyone,

    I have the following script to monitor Hyper-V replica on multiple clusters from same domain:

    function get_info{
    #Add some Styles to the Table
    $head = '
    BODY{
    font-family:Arial;
    font-size: 12px;
    background-color:#FFFFFF;
    }
    TABLE{
    border-width: 1px;
    border-style: solid;
    border-collapse: collapse;
    }
    TH{
    border-width: 1px;
    border-color: #0070A8;
    background-color: #006699;
    color: #FFFFFF;
    font-size: 15px;
    }
    TD{
    border-width: 1px;
    border-style: solid;
    border-color: #0070A8;
    color: #00496B;
    }
    '
    #Get Hyper-V Replica Status
    $replica_body = Get-VM –ComputerName (Get-ClusterNode –Cluster pcaxxclus204) | Where-Object { $_.Name -like '*FS*' } | Get-VMReplication |
    Select Name, State, Health, PrimaryServer
    $replica_body = Get-VM –ComputerName (Get-ClusterNode –Cluster pcxclus203) | Where-Object { $_.Name -like '*FS*' } | Get-VMReplication|
    Select Name, State, Health, PrimaryServer |
    ConvertTo-Html -Fragment -PreContent "Hyper-V Replica Status"

    The script displays a table with the status of hyper-v replica of servers from clusters containing FS in the name.
    My issue is that I am not able to display the status of servers which does not have replica enabled. How can I convert the text into a simple message in table 'replication is not enabled'
    Get-VMReplication : Replication is not enabled for virtual machine with name PCxxFS21.
    At C:\Users\a\script2.PS1:53 char:128
    + ... ike '*FS*' } | Get-VMReplication|
    + ~~~~~~~~~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (PCxxFS21:String) [Get-VMReplication], VirtualizationOperationFailedException
    + FullyQualifiedErrorId : ObjectNotFound,Microsoft.HyperV.PowerShell.Commands.GetVMReplicationCommand

    Can someone please help me with this?
    Thank you a lot!

  • #56185
    Profile photo of Don Jones
    Don Jones
    Keymaster

    Well, there's nothing to "convert," per se, you're getting an error. This is a little bit more complex than you might have realized.

    You need to start by going through your computers one at a time, in a ForEach loop. That will allow each one to fail, and for you to capture that failure. So you also need to trap that error – see "The Big Book of PowerShell Error Handling" for a quick tutorial, or read about_try_catch_finally in the shell. The basic logic is this:

    For each computer you want to query, run your command – with error handling enabled. If the command succeeds, the variable will have your output. If the command fails, you'll end up in a Catch{} block. You'll need to construct **an object that looks just like successful output**, having the same properties, with whatever failure text you want.

    I'll do a simpler example.

    Function Get-MyServiceInfo {
     $computers = @('SERVER1','SERVER2') # could also read from a file, AD, or whatever
     ForEach ($computer in $computers) {
      Try {
        $services = Get-Service -computername $computer -ErrorAction Stop | Select-Object -Prop Name,Status
      } Catch { 
        New-Object -Type PSObject -Prop @{'Name'='No services found or failure to connect';'Status'=' '}
      }
     }
    }
    
    Get-MyServiceInfo | ConvertTo-HTML
    

    You'll notice that I've factored my code into a function, and then I call that function and pass its results to ConvertTo-HTML. This makes my job a lot easier, as I can just output stuff to the pipeline from my function, rather than having to accumulate it all in an array or something. Each major thing that's happening – getting the info and converting to HTML – are self-contained in their own commands, this way.

    You'll see an expanded, similar approach in "Creating HTML Reports in PowerShell," which I heartily recommend. Both are free ebooks – see the "ebooks" menu on this site.

    I'll also suggest "Learn PowerShell Toolmaking in a Month of Lunches," which is not free. You're starting to head down a bad path with your coding approach, and it's probably a good time to get on board with PowerShell's rather unique way of doing things.

  • #56188
    Profile photo of Rob Simmers
    Rob Simmers
    Participant

    Take a look at this. I tried to answer both of your posts. You should concentrate on generating you PSObject output before exporting it to HTML. This code is NOT tested, but should get you close to what you're asking for:

    function Get-HyperVReplicaStatus {
    [CmdletBinding()]
    param (
        [string[]]$Cluster
    )
    begin{}
    process {
        $results = foreach ($Node in (Get-ClusterNode –Cluster $Cluster | Where-Object { $_.Name -like '*FS*' })) {
            Write-Verbose "Processing Nodes in Cluster {0}" -f $Cluster
            try {
                $VM = Get-VM –ComputerName $Node.Name
                try {
                    $VM | 
                    Get-VMReplication -ErrorAction Stop |
                    Select Name, 
                           State, 
                           Health, 
                           PrimaryServer, 
                           @{Name="Cluster";Expression={$Cluster}}
                }
                catch {
                    #Error occured with Get-VMReplication, so handle it
                    #and generate a PSObject with the Name and other props
                    #you want to return.  State is Disabled and the Health
                    #would be Get-VMReplication : Replication is not enabled for virtual machine with name PCxxFS21.
                    $VM |
                    Select Name,
                           @{Name="State";Expression={"Disabled"}},
                           @{Name="Health";Expression={$_}}
                           @{Name="PrimaryServer";Expression={$NULL}}
                           @{Name="Cluster";Expression={$Cluster}}
                }
            }
            catch {
                "Unable to get VM {0}. {1}" -f $Node.Name, $_
            }
             
            
        }
    }
    end{$results}
    
    } #Get-HyperVReplicaStatus
    
    
    #Add some Styles to the Table
    $head = @"
    BODY{
        font-family:Arial;
        font-size: 12px;
        background-color:#FFFFFF;
    }
    
    TABLE{
        border-width: 1px;
        border-style: solid;
        border-collapse: collapse;
    }
    
    TH{
        border-width: 1px;
        border-color: #0070A8;
        background-color: #006699;
        color: #FFFFFF;
        font-size: 15px;
    }
    
    TD{
        border-width: 1px;
        border-style: solid;
        border-color: #0070A8;
        color: #00496B;
    }
    "@
    
    $clusters = "Pxxclus4","Pxxc1","Lfdcl1"
    #OR $clusters = Get-Content C:\Clusters.txt
    $hyperVStatus = Get-HyperVReplicaStatus -Cluster $clusters
    $hyperVStatusHTML = $hyperVStatus | ConvertTo-Html -PreContent "Hyper-V Replica Status"
    $hyperVStatusHTML | Out-File "C:\Scripts\hyperVStatus.html"
    Invoke-Item "C:\Scripts\hyperVStatus.html"
    
  • #56335
    Profile photo of Bill M
    Bill M
    Participant

    Thank you for the replies. Going to study harder, the scripts require corrections

  • #56471
    Profile photo of Bill M
    Bill M
    Participant

    Still not working 🙁
    Not able to succeed in display the hyper-v replica in a HTLM format for all VMs which have FS in their name

  • #56854
    Profile photo of Daan Weda
    Daan Weda
    Participant

    Maybe you could approach this solution in a different way.
    Instead of working with output from a returned error, you could see if a machine is a replica by looking into the properties of the get-vm command. If you look into the error message then Get-VMReplication is expecting to be run against a machine that has replica settings enabled. If you use something like this:

    $VMS = Get-VM –ComputerName (Get-ClusterNode –Cluster pcaxxclus204) | Where-Object { $_.Name -like '*FS*' }
    $Replica=$VMS|where-object {$_.ReplicationState -ne "disabled"}
    $NoReplica=$VMS |where-object {$_.ReplicationState -eq "disabled"}

    From there you can work with the variables $Replica and $Noreplica, I did not test the code because I don't have a cluster at this moment but I think you get the idea.

  • #56861
    Profile photo of Bill M
    Bill M
    Participant

    Thank you for this. I figured it out to display.

    $VMS = Get-VM –ComputerName (Get-ClusterNode –Cluster pcaxxclus204) | Where-Object { $_.Name -like '*FS*' }
    $NoReplica=$VMS |where-object {$_.ReplicationState -eq "disabled"} | Out-GridView

    How can I get the results of the GridView into an email format?
    I want to get the output grid sent in an email.

    • #56969
      Profile photo of Daan Weda
      Daan Weda
      Participant

      I would use a Select-Object to select the objects which should be included in the mail.
      Then I would use the Send-MailMessage with a e-mail body something like this.
      Note, that the Send-MailMessage need more parameters of course like -SmtpServer and -From -To etc.
      Of course I have to see the results then in the e-mail to know if I need more formatting.

      $NoReplica=$VMS |where-object {$_.ReplicationState -eq "disabled"} |select-object Name,ReplicationHealth,ReplicationMode,ReplicationState

      $MessageBody = @"
      Put text for mail here and place input from script here: $NoReplica
      "@

      Send-MailMessage -Body $MessageBody -Subject Hyper-V Replica

  • #56908
    Profile photo of Bill M
    Bill M
    Participant

    How can I get the result for pcaxxcl* clusters in the same format?
    $VMS = Get-VM –ComputerName (Get-ClusterNode –Cluster pcaxxcl*) | Where-Object { $_.Name -like '*FS*' }
    $Replica=$VMS|where-object {$_.ReplicationState -ne "disabled"}
    $NoReplica=$VMS |where-object {$_.ReplicationState -eq "disabled"}
    fails in an error

    using $cluster and putting $cluster=cluser1, cluster2 not working

    • #56971
      Profile photo of Daan Weda
      Daan Weda
      Participant

      I guess that's because Get-Cluster is not accepting multiple values string.
      You could run the command in a for each loop and store your data in a Array and work from there.
      Something like this:

      $clusters= "cluser1","cluster2"

      $VMS=@()
      Foreach($cluster in $clusters)
      {
      $VMS += Get-VM –ComputerName (Get-ClusterNode –Cluster $cluster) |
      Where-Object { $_.Name -like '*FS*' }
      $Replica=$VMS|where-object {$_.ReplicationState -ne "disabled"}
      $NoReplica=$VMS |where-object {$_.ReplicationState -eq "disabled"}
      }

  • #57013
    Profile photo of Bill M
    Bill M
    Participant

    that's great. Thank you!
    How can it be sent to an email format? How to send the out-gridview display into an html format or in a text? the out-string is not displaying it properly.

  • #57014
    Profile photo of Bill M
    Bill M
    Participant

    Let's say I get a list with the format
    Name Host
    —- —-
    t12FS161
    lohjFS22
    sdsR03FS21

    I want under Host to have the HV node name on which the VM resides. How can I get this to display?

    • #57149
      Profile photo of Daan Weda
      Daan Weda
      Participant

      If that information is in the object you could use a format-list.

      Format-List -Property name,host
  • #57160
    Profile photo of Bill M
    Bill M
    Participant

    The information is not in the object, not sure how to get the name of the hyper-v node on which the VM resides

  • #57275
    Profile photo of Daan Weda
    Daan Weda
    Participant

    Depends which tools you are using, do you only work with Hyper-V or do you also use SCVMM?

    You can get it from the registry.

    (get-item "HKLM:\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters").GetValue("HostName")

    I think when you use SCVMM you can get it with Get-SCVMHost and then add it to your object.

  • #57758
    Profile photo of Bill M
    Bill M
    Participant

    It seems to be not that easy to do it. Has someone done this already? Getting the list of clusters and finding out the FS which have hyper-v replica enabled/disabled?

  • #57820
    Profile photo of Daan Weda
    Daan Weda
    Participant

    I wrote a quick example for you, did you try something like this?

    $clusters= "cluser1","cluster2"
    
    $VMS=@()
     Foreach($cluster in $clusters)
     {
     $VMS += Get-VM –ComputerName (Get-ClusterNode –Cluster $cluster) |
     Where-Object { $_.Name -like '*FS*' }
     }
     
     $Replicas=$VMS|where-object {$_.ReplicationState -ne "disabled"}
     $NoReplica=$VMS |where-object {$_.ReplicationState -eq "disabled"}
     
    
     $VMSReplica=@()
     Foreach($Replica in $Replicas)
     {
     $VMRunsOnMachine =  invoke-command -ComputerName $Replica -ScriptBlock{(get-item "HKLM:\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters").GetValue("HostName")} 
     $VMSReplica+= $Replica|select *, @{Name="HostVMRunning";Expression={$VMRunsOnMachine}}
    
     }
    
     Write-output $VMSReplica

    From there on you can work with the variable $VMSreplica.
    I can not test it at the moment will run some tests tomorrow and get back to you.

  • #57848
    Profile photo of Bill M
    Bill M
    Participant

    Thank you! The output returns a lot of info. Something like this:
    VMName : lDFS47
    VMId : caed1244-4132-4bc8-9c50-16e6633c8960
    Id : caed1244-4132-4bc8-9c50-16e6633c8960
    Name : u0FS47
    State : Off
    IntegrationServicesState :
    OperationalStatus : {Ok}
    PrimaryOperationalStatus : Ok
    SecondaryOperationalStatus :
    StatusDescriptions : {Operating normally}
    PrimaryStatusDescription : Operating normally
    SecondaryStatusDescription :
    Status : Operating normally
    Heartbeat :
    ReplicationState : WaitingForInitialReplication
    ReplicationHealth : Warning
    ReplicationMode : Replica
    CPUUsage : 0
    MemoryAssigned : 0
    MemoryDemand : 0
    MemoryStatus :
    SmartPagingFileInUse : False
    Uptime : 00:00:00
    IntegrationServicesVersion :
    ResourceMeteringEnabled : True
    ConfigurationLocation : C:\ClusterStorage\PClus43_FS2\Hyper-V Replica
    SnapshotFileLocation : C:\ClusterStorage\PClus43_FS2\Hyper-V Replica
    AutomaticStartAction : Nothing
    AutomaticStopAction : Save
    AutomaticStartDelay : 0
    SmartPagingFilePath : C:\ClusterStorage\PClus43_FS2\Hyper-V Replica
    NumaAligned :
    NumaNodesCount : 1
    NumaSocketCount : 1
    Key : Microsoft.HyperV.PowerShell.VirtualMachineObjectKey
    IsDeleted : False
    ComputerName : PCTHVOTH09
    Version : 5.0
    Notes : #CLUSTER-INVARIANT#:{ed308ee7-67cc-44c6-8271-342f8601c78f}
    Generation : 2
    Path : C:\ClusterStorage\PClus43_FS2\Hyper-V Replica
    CreationTime : 7/25/2016 6:09:15 AM
    IsClustered : True
    SizeOfSystemFiles : 112730
    ParentSnapshotId :
    ParentSnapshotName :
    MemoryStartup : 12884901888
    DynamicMemoryEnabled : False
    MemoryMinimum : 536870912
    MemoryMaximum : 1099511627776
    ProcessorCount : 4
    RemoteFxAdapter :
    NetworkAdapters : {Network Adapter}
    FibreChannelHostBusAdapters : {}
    ComPort1 : Microsoft.HyperV.PowerShell.VMComPort
    ComPort2 : Microsoft.HyperV.PowerShell.VMComPort
    FloppyDrive :
    DVDDrives : {}
    HardDrives : {Hard Drive on SCSI controller number 0 at location 0, Hard Drive on SCSI controller number 0 at location 6}
    VMIntegrationService : {Time Synchronization, Heartbeat, Key-Value Pair Exchange, Shutdown...}
    HostVMRunning :
    HostVM running is empty field. Let's see what we can get by editing it

    • #58102
      Profile photo of Daan Weda
      Daan Weda
      Participant

      Ok that's good news so you have almost al your data to work with.
      Did you already test just the invoke-command against one of your servers to see if you get anything back?
      This one works in my environment.

      invoke-command -ComputerName Computername -ScriptBlock{(get-item "HKLM:\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters").GetValue("HostName")}

      On which OS is the VM running?

  • #58271
    Profile photo of Bill M
    Bill M
    Participant

    most of the VMs are running under Windows Server 2012R2

  • #58471
    Profile photo of Daan Weda
    Daan Weda
    Participant

    Did you test the invoke-command against a server 2012R2?

You must be logged in to reply to this topic.