VMware Cloud Community
RahmanK
Contributor
Contributor

PowerCLI cloning VMs to Resource Pools script fails

The script below is meant to clone VM templates to Resource Pools which -match parameter $environmentID.

However I get the error below. If i don't use parameter $environmentID the script works and clones to all Resource Pools within a Folder which I do not want.

Any help would be much appreciated.

ERROR

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

At C:\Scripts\Dev\devCloneEnvironmentContentPerResource.ps1:13 char:35

+         $envID = ($pool.Name.Split <<<< ("_"))[0].Substring(3)

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

    + FullyQualifiedErrorId : InvokeMethodOnNull

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

At C:\Scripts\Dev\devCloneEnvironmentContentPerResource.ps1:14 char:33

+         $networkID = ($pool.Name.Split <<<< ("_"))[1].Substring(0)

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

    + FullyQualifiedErrorId : InvokeMethodOnNull

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

At C:\Scripts\Dev\devCloneEnvironmentContentPerResource.ps1:15 char:37

+         $netID = ( ($pool.Name.Split <<<< ("_"))[2].Substring(3).Split(" ") )[0]

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

    + FullyQualifiedErrorId : InvokeMethodOnNull

SCRIPT

#

# Parameter Declarations

#

Param($folder_param, $resourcePool_param, $environmentID)

#

# Function Definitions

#

Function Get-PoolID ($pool)

{

        $envID = ($pool.Name.Split("_"))[0].Substring(3)

        $networkID = ($pool.Name.Split("_"))[1].Substring(0)

        $netID = ( ($pool.Name.Split("_"))[2].Substring(3).Split(" ") )[0]

  $poolID = New-Object PSObject

        Add-Member -InputObject $poolID -MemberType NoteProperty -Name "Env" -Value $envID

        Add-Member -InputObject $poolID -MemberType NoteProperty -Name "Net" -Value $netID

        Add-Member -InputObject $poolID -MemberType NoteProperty -Name "Network" -Value $networkID

        $poolID

#

# Usage Statement

#

If (!$folder_param -or !$resourcePool_param)

{

    "usage: CloneContent-Sandbox.ps1 -f targetFolder -r sourceResourcePool"

    Exit

}

#

# Retrieve Locations

#

$source = Get-Folder -Location 'Library' -Name 'Library Hosts' | Get-ResourcePool -Name $resourcePool_param

$sourceVM_list = Get-VM -Location $source | Sort

Write-Host -ForegroundColor "Yellow" ("Source found on " + ($sourceVM_list|Select -First 1).VMHost.Name.TrimEnd("company.com"))

$target = Get-Folder -Location "Production" -Name $folder_param

$vmhost_list = Get-VMHost -Location $target | Sort

If (!$source -or !$sourceVM_list -or !$target -or !$vmhost_list) { Exit }

#

# Main Script

#

Foreach ($vmhost in $vmhost_list)

{

    $pool_list = Get-ResourcePool -Location $vmhost | Where-Object { $_.Name -match $environmentID } | Sort

  

    Foreach ($pool in $pool_list)

    {      

        ""

  $pool.Name

        "-------------"

        $poolID = Get-PoolID $pool

      

  $process = @() # Added to consume return data from Wait-Task

        $tasks = @()

        Foreach ($sourceVM in $sourceVM_list)

        {

            $vm_name = $sourceVM.Name -replace "_bak.*",("_NET" + $poolID.Network + "_" + $poolID.Env)

            If ( !(Get-VM -Location $vmhost -Name $vm_name 2> $null) )

            {

                $tasks += (New-VM -VMHost $vmhost -ResourcePool $pool -VM $sourceVM -Name $vm_name -Confirm:$false -RunAsync)

                "  Cloning:  " + $vm_name

            }

        }

        If ($tasks)

        {

            # Wait-Task -Task $tasks

  $process = Wait-Task -Task $tasks

        }

    }

}

""

Reply
0 Kudos
6 Replies
LucD
Leadership
Leadership

Did you already check which ResourcePool is in $pool when the error is fired ?

Could you be hitting the hidden pool named Resources ?


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

Reply
0 Kudos
RahmanK
Contributor
Contributor

Hi LucD,

When running $pool_list = Get-ResourcePool -Location $vmhost | Where-Object { $_.Name -match $environmentID } | Sort

$pool returns as empty.

However when running $pool_list = Get-ResourcePool -Location $vmhost | Where-Object { $_.Name -match "501" } | Sort

$pool contains all ResourcePools with "501".

Seems as though I' am unable to run -match against an array.

Same issue occurs when I use {$_.Name -like "*$environmentID*"}. $pool returns empty.

Do you have any ideas how I would return any ResourcePools matching the items in $environmentID.

Thanks

Reply
0 Kudos
LucD
Leadership
Leadership

If you want to match against an array of names, you can use the -contains operator

$pool_list = Get-ResourcePool -Location $vmhost | Where-Object { $environmentID -contains $_.Name } | Sort


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

Reply
0 Kudos
RahmanK
Contributor
Contributor

The problem with -contains is it requires an exact match.

However $environmentID is only part of the ResourcePool name.

Reply
0 Kudos
LucD
Leadership
Leadership

Ok, then we use the RegEx 'or' operator (|)

Like this, that should allow multiple, partial matches.

# Assume $environmentId contains a number of strings

$regexEnvId = $environmentId -join '|'

$pool_list = Get-ResourcePool -Location $vmhost | Where-Object { $_.Name -match $regexEnvId } | Sort 


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

RahmanK
Contributor
Contributor

That did the trick.

Thanks for the help.

Reply
0 Kudos