VMware Cloud Community
Baoth
Enthusiast
Enthusiast
Jump to solution

PowerCLI - SRM reporting - You cannot call a method on a null-valued expression

Hello all

Hoping someone might be able to help me please.

According to the Documentation Centre here, you can create a report of the Protected VM's using the below script:

1. List all protection groups associated with the SRM server.

$srmApi = $srm.ExtensionData

$protectionGroups = $srmApi.Protection.ListProtectionGroups()

2. Generate a report of the protected virtual machines.

$protectionGroups | % {

    $protectionGroup = $_

  

    $protectionGroupInfo = $protectionGroup.GetInfo()

  

    # The following command lists the virtual machines associated with a protection group

    $protectedVms = $protectionGroup.ListProtectedVms()

    # The result of the above call is an array of references to the virtual machines at the vSphere API

    # To populate the data from the vSphere connection, call the UpdateViewData method on each virtual machine view object

    $protectedVms | % { $_.Vm.UpdateViewData() }

    # After the data is populated, use it to generate a report

    $protectedVms | %{

        $output = "" | select VmName, PgName

        $output.VmName = $_.Vm.Name

        $output.PgName = $protectionGroupInfo.Name

        $output

    }

} | Format-Table @{Label="VM Name"; Expression={$_.VmName} }, @{Label="Protection group name"; Expression={$_.PgName} }

The problem I am having is in step 1, specifically this part: $protectionGroups = $srmApi.Protection.ListProtectionGroups()

I'm using PowerCLI version VMware-PowerCLI-6.3.0-3639347, and can successfully connect-viserver and subsequently connect-srmserver works too.

The first variable of $srmApi = $srm.ExtensionData is set successfully, but the second returns the error "You cannot call a method on a null-valued expression".

Here's the exact output from the CLI session:

PowerCLI C:\> $protectionGroups = $srmApi.Protection.ListProtectionGroups()

You cannot call a method on a null-valued expression.

At line:1 char:1

+ $protectionGroups = $srmApi.Protection.ListProtectionGroups()

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException

    + FullyQualifiedErrorId : InvokeMethodOnNull

PowerCLI C:\>

My end goal is to have a script that will create a list of all SRM protected VM's within the estate, but I would also like to have additional information for the VM's - like vCPU count, vRAM, hostname and OS version for example. I just can't even get over the first hurdle.

Thanks all.

50 Replies
Baoth
Enthusiast
Enthusiast
Jump to solution

Comes back empty:

PS C:\WINDOWS\system32> $srmApi.Protection

PS C:\WINDOWS\system32>

So does $srmAPI.

0 Kudos
LucD
Leadership
Leadership
Jump to solution

And what does Connect-SrmServer -Server <your-SRM-server> | Get-Member show?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Baoth
Enthusiast
Enthusiast
Jump to solution

I had to amend it slightly, as it couldn't find the server hostname (despite DNS resolving it successfully). But here's the output:

PS C:\WINDOWS\system32> Connect-SrmServer -SrmServerAddress <srm-ip-address> | Get-Member

   TypeName: VMware.VimAutomation.Srm.Impl.V1.SrmServerImpl

Name               MemberType Definition

----               ---------- ----------

BeginConnectionUse Method     void SrmServerInterop.BeginConnectionUse()

ConvertToVersion   Method     T ConvertToVersion[T](), T VersionedObjectInterop.ConvertToVersion[T]()

EndConnectionUse   Method     void SrmServerInterop.EndConnectionUse(bool force)

Equals             Method     bool Equals(System.Object obj)

GetClient          Method     void GetClient(), VMware.VimAutomation.Srm.Interop.V1.SrmClientInterop SrmServerIntero...

GetHashCode        Method     int GetHashCode()

GetType            Method     type GetType()

IsConvertableTo    Method     bool IsConvertableTo(type toType), bool VersionedObjectInterop.IsConvertableTo(type type)

LockUpdates        Method     void ExtensionData.LockUpdates()

ToString           Method     string ToString()

UnlockUpdates      Method     void ExtensionData.UnlockUpdates()

Build              Property   string Build {get;}

ExtensionData      Property   System.Object ExtensionData {get;}

Id                 Property   string Id {get;}

InstanceUuid       Property   string InstanceUuid {get;}

IsConnected        Property   bool IsConnected {get;}

IsInUse            Property   bool IsInUse {get;}

Name               Property   string Name {get;}

Port               Property   int Port {get;}

ProductLine        Property   string ProductLine {get;}

RefCount           Property   int RefCount {get;}

ServiceUri         Property   uri ServiceUri {get;}

SessionSecret      Property   string SessionSecret {get;}

Uid                Property   string Uid {get;}

User               Property   string User {get;}

Version            Property   string Version {get;}

0 Kudos
LucD
Leadership
Leadership
Jump to solution

That seems ot be ok.

Now try

$SrmConnection = Connect-SrmServer -Server <srm-ip-address>

$srmApi = $SrmConnection.ExtensionData

$srmApi | Get-Member

If that returns a list including the Protection property, do

$srmApi.Protection | Get-Member

If that list contains a method called ListProtectionGroups, do

$srmApi.Protection.ListProtectionGroups()


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Baoth
Enthusiast
Enthusiast
Jump to solution

Every part came back as described.

The final output was a MoRef, with multiple lines that looked like this:

SrmProtectionGroup-srm-vm-protection-group-<different-number-here>

0 Kudos
LucD
Leadership
Leadership
Jump to solution

Those are pointers, you can get the actual object with

ForEach-Object -Process {

   Get-View -Id $_

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Baoth
Enthusiast
Enthusiast
Jump to solution

Smiley Happy

A little bit beyond my understanding... sorry to ask more questions.

Do I just run that section of code following the previous one, or should I run them together or pipe one to the other please?

0 Kudos
LucD
Leadership
Leadership
Jump to solution

Like this

$SrmConnection = Connect-SrmServer -Server <srm-ip-address>

$srmApi = $SrmConnection.ExtensionData

$srmApi.Protection.ListProtectionGroups() |

ForEach-Object -Process {

   Get-View -Id $_

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Baoth
Enthusiast
Enthusiast
Jump to solution

Thanks. Here's the output (first section as its repeated multiple times):

Get-View : Cannot bind parameter 'Id'. Cannot convert the "VMware.VimAutomation.Srm.Views.SrmProtectionGroup" value

of type "VMware.VimAutomation.Srm.Views.SrmProtectionGroup" to type "VMware.Vim.ManagedObjectReference".

At line:8 char:17

+    Get-View -Id $_

+                 ~~

    + CategoryInfo          : InvalidArgument: (:) [Get-View], ParameterBindingException

    + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,VMware.VimAutomation.ViCore.Cmdlets.Commands.DotNetInter

   op.GetVIView

0 Kudos
LucD
Leadership
Leadership
Jump to solution

My bad (I'm obviously not a regular SRM user and your MoRef mention threw me off).
Try this instead

$SrmConnection = Connect-SrmServer -Server <srm-ip-address>

$srmApi = $SrmConnection.ExtensionData

$srmApi.Protection.ListProtectionGroups() |

ForEach-Object -Process {

   $_.GetInfo()

   $_.ListAssociatedVms()

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Baoth
Enthusiast
Enthusiast
Jump to solution

Don't worry about it - without your help I wouldn't be this far Smiley Happy

So that gets me to authenticate, and then shows the following output:

Name       Description                                     Type

----       -----------                                     ----

<group-name>       <description-here>  vr 

The output table isn't formatted in a readable way as such, but it does contain some of the groups we have configured. It didn't show any VM's within the groups.

0 Kudos
LucD
Leadership
Leadership
Jump to solution

So the line $_.ListAssociatedVms() didn't return anything?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
LucD
Leadership
Leadership
Jump to solution

Btw, this recaps most of what we have been doing, and I assume it is still valid.

See PowerCLI 5.5 R2 and the Site Recovery Manager API


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Baoth
Enthusiast
Enthusiast
Jump to solution

Didn't appear to, no. I've attached a screenshot to give a better idea what I'm running vs the output.

0 Kudos
vXav
Expert
Expert
Jump to solution

[EDIT] My bad, just saw your screenshot. It is vSphere replication (vr) Smiley Happy - (worth mentioning the guide though, it's good)

How is your replication handled? ListAssociatedVMs() only works for vSphere replication. Not ABR.

more info in the Site Recovery Manager API Developer's Guide

0 Kudos
Baoth
Enthusiast
Enthusiast
Jump to solution

Replication is via VR as far as I can tell.

Whilst we are on that subject, is there a way to do a get-vm, and filter the results by what is replicated, and how often its replicated please?

0 Kudos
vXav
Expert
Expert
Jump to solution

I use array based replication in my environment which is different from vSphere replication so I can't do any tests.

However I recommend you check out this github, the guy did an amazing job at wrapping the main operations into funcitons.

The annoying bit with the SRM module is that you get MoRef IDs which you must then use to get the actual VI object.

To give you an idea you could do something like this to get the replicated VMs as "VM" objects.

Function Get-ReplVMs {

$pg = $SRM.extensiondata.protection.listprotectiongroups()

$RepVM = $pg.listprotectedvms()

$VmID = $RepVM.vm.moref

Get-VM -id $VmID

}

Now that's a quick and dirty function to show you the different steps involved, don't take it too seriously Smiley Happy.

Because vSphere replication and ABR are quite different I suggest you do some tests and see for yourself how it handles cases where a VMs is unprotected, left with an ISO, deleted ...

Baoth
Enthusiast
Enthusiast
Jump to solution

That GitHub link was really useful, thanks.

The output looks like this:

VM Name     Protection group name

-------     ---------------------

<VM-name>  <PG-name>

The code I ran was is below, which is taken from ReadMe of the Git link:                 

Get-SrmProtectionGroup | %{
  $pg = $_
  Get-SrmProtectedVM -ProtectionGroup $pg } | %{
  $output = "" | select VmName, PgName
  $output.VmName = $_.Vm.Name
  $output.PgName = $pg.GetInfo().Name
  $output
  } | Format-Table @{Label="VM Name"; Expression={$_.VmName} },
  @{Label="Protection group name"; Expression={$_.PgName}
}

It's almost exactly what I need, but some of the VM names are longer than the table column is allowing - so they look like "myvmnam..." rather than "myvmname" for example.

Any ideas how I can format the table to expand as required please?  What about outputting the table to a file / csv?

This is taking it to the next stage, and would be ideal if it worked... I'd have thought it can be tweaked even further, to include the memory and CPU counts too for example, in the output table. I have used "get-vm $vmList | Select-object Name, Guest, UsedSpaceGB, ProvisionedSpaceGB, MemoryGB, NumCPU, Notes | Export-Csv C:\Users\<username>\Documents\srm_vm_details.csv", and that gives all the details of the VM's that have been requested.

I'd guess the line "$output = "" | select VmName, PgName" above could have the other bits added, but not sure how the rest of the code would have to be changed to accommodate the additional information.

0 Kudos
LucD
Leadership
Leadership
Jump to solution

Can you try this way?
It makes it a lot easier to add columns to the output, just add properties on the Select (like I did with NumCpu and MemoryGB.

Get-SrmProtectionGroup |

ForEach-Object -Process {

   $pgInfo = $_.GetInfo()

   Get-SrmProtectedVM -ProtectionGroup $pg |

   ForEach-Object -Process {

   Get-VM -Name  $_.Vm.Name |

  Select @{N = "VM Name"; E = {$_.Name} },

  NumCpu, MemoryGB,

   @{N = "Protection group name"; E = {$pgInfo.Name}}

   }

} | Export-Csv -Path .\report.csv -NoTypeInformation -UseCulture


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Baoth
Enthusiast
Enthusiast
Jump to solution

EDIT: Sorry, but the output isn't quite right having reviewed it. It's listed some of the VM's and their details, but it's listing 12 VM's and then starting the next line with the same 12 VM's.

Awesome!

Last request... promise! Smiley Happy

Can the current Protection Status be pulled into the same table?

For example, if I do a simple export from the GUI, the column headers are:

Virtual Machine, Protection Status, Recovery Resource Pool, Recovery Host, Recovery Folder, Recovery Network and Recovery Plans.

If the rest can be grabbed too... well. That would make my day :smileylaugh:.

0 Kudos