Veeam VMware vCenter Failower Write Action module

Veeam.Virt.Extensions.VMware.PSWriteAction.FailoverVCtoHosts (WriteActionModuleType)

Element properties:

TypeWriteActionModuleType
IsolationAny
AccessibilityInternal
RunAsMicrosoft.SystemCenter.PrivilegedMonitoringAccount
InputTypeSystem.BaseData
OutputTypeMicrosoft.Windows.SerializedObjectData

Member Modules:

ID Module Type TypeId RunAs 
RunScript WriteAction Microsoft.Windows.PowerShellWriteAction Default

Overrideable Parameters:

IDParameterTypeSelectorDisplay NameDescription
TimeoutSecondsint$Config/TimeoutSeconds$TimeoutSecondsTimeoutSeconds

Source Code:

<WriteActionModuleType ID="Veeam.Virt.Extensions.VMware.PSWriteAction.FailoverVCtoHosts" Accessibility="Internal" RunAs="SC!Microsoft.SystemCenter.PrivilegedMonitoringAccount">
<Configuration>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="vCenterName" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="mode" type="xsd:int"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="force" type="xsd:int"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="TimeoutSeconds" type="xsd:int"/>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="TimeoutSeconds" Selector="$Config/TimeoutSeconds$" ParameterType="int"/>
</OverrideableParameters>
<ModuleImplementation>
<Composite>
<MemberModules>
<WriteAction ID="RunScript" TypeID="Windows!Microsoft.Windows.PowerShellWriteAction">
<ScriptName>vCenterFailover.ps1</ScriptName>
<ScriptBody><Script>Param($vcName, $login, $pwd, $mode, $force);

$eventId = 995;
$scriptName = "vCenterFailover.ps1";
$oAPI = New-Object -ComObject "MOM.ScriptAPI";

Function LogErrorMessage
{
Param ([string] $msgText);
echo $msgText;
$oAPI.logscriptevent($scriptName, $eventId, 1, $msgText);
}

Function LogWarningMessage
{
Param ([string] $msgText);
echo $msgText;
$oAPI.logscriptevent($scriptName, $eventId, 2, $msgText);
}

if ([string]::IsNullOrEmpty($vcName))
{
LogErrorMessage "Error: vCenter Name is empty";
return;
}
if ([string]::IsNullOrEmpty($login) -or [string]::IsNullOrEmpty($pwd))
{
LogErrorMessage "Error: username or password are empty. Check Run As Profile 'Veeam VMware Direct ESX(i) Connection Account'.";
return;
}
if (-not ($mode -eq 0 -or $mode -eq 1))
{
LogErrorMessage "Error: Mode parameter should be 0 or 1";
return;
}


Function Convert-VCenterConnectionToDirectEsxConnection
{
Param ([string]$vCenterComputerName = $(throw "The vCenterComputerName parameter is required."), [System.Management.Automation.PSCredential] $credential)

$vmWareServer = Get-VMwareServer $vCenterComputerName;

if( $vmWareServer -eq $null ){
#$oAPI.logscriptevent($scriptName, $eventId, 1, "Error: No VMware Server with name '{0}' found" -f $vCenterComputerName);
throw ("No VMware Server with name '{0}' found" -f $vCenterComputerName);
}

if( $vmWareServer.VirtPlatform -ne "vCenter" ){
throw "Specified VMware Server VirtualizationPlatform property must be a vCenter";
}

$failover = ($force -eq 1);

if(!$failover)
{
echo "Updating connection status for vCenter Server $vCenterComputerName ...";
$testConn = Test-VMwareServerConnection $vmWareServer.ServerName -Quiet;
$failover = !$testConn.Passed;
}

if($failover)
{
$vCenterMonitoredHosts = $vmWareServer.Topology | Where { $_.Type -eq "Host" -and $_.Monitored }
$groupedHosts = $vCenterMonitoredHosts | Group-Object MonitoringGroup;

if ($vCenterMonitoredHosts -ne $null) {
echo "The folowing host(s) currently monitored and will be added directly:";
$vCenterMonitoredHosts | % { echo (" &gt; {0}" -f $_.Name) }
$addResult = @();
try {
foreach ($grH in $groupedHosts) {
$mg = $grH.Name;
$hostColl = $grH.Group | % { $_.Name };
$addResult += Add-VMwareServer $hostColl -MonitoringGroup $mg -Credential $credential -Options AddDelayed;
}
}
catch [Exception] {
$errorMsg = $_.Exception.Message;
LogErrorMessage "Error adding host to monitoring: $errorMsg";
}

$sucNames = $addResult | ? {$_.Status -eq "AddSuccess"} | % {$_.VMwareServer};
$failNames = $addResult | ? {$_.Status -ne "AddSuccess"} | % {$_.VMwareServer};
$failedHostsMsg = "";
$failNames | % {
if ($_ -ne $null -and $_ -ne [String]::Empty) {
$failedHostsMsg += " &gt; $_`r`n";
}
}
if ($failedHostsMsg.Length -gt 0) {
LogWarningMessage "Following host(s) were not added to monitoring:`r`n$failedHostsMsg";
}

$vCenterMonitoredHosts = $vCenterMonitoredHosts | ? { $sucNames -contains $_.Name}


if($vCenterMonitoredHosts -ne $null) {
echo "Disabling monitoring for vCenter Server $vCenterComputerName";
Disable-Monitoring -VMwareServer $vmWareServer -Include $vCenterMonitoredHosts -Force;
}

$oAPI.logscriptevent($scriptName, $eventId, 0, "vCenter Server $vCenterComputerName is not available and will be failed over to direct ESX(i) host connections.");
}
else {
#### changed error description for Force vCenter connection failover task
echo "VMware vCenter Server $vcName will not be failed over to direct host connection. No ESX host connections avalable or connection has been already failed over to direct host connections";
$oAPI.logscriptevent($scriptName, $eventId, 0, "VMware vCenter Server $vcName will not be failed over to direct host connection. No ESX host connections avalable.");
}
}
else
{
echo "No action required - VMware vCenter Server $vcName is available";
$oAPI.logscriptevent($scriptName, $eventId, 0, "No action required - VMware vCenter Server $vcName is available");
}
}

Function Convert-DirectEsxConnectionToVCenterConnection
{
Param ([string]$vCenterComputerName = $(throw "The vCenterComputerName parameter is required."))

$vmWareServer = Get-VMwareServer $vCenterComputerName;

if( $vmWareServer -eq $null ){
throw ("vCenter Server '{0}' is not found" -f $vCenterComputerName);
}

if( $vmWareServer.VirtPlatform -ne "vCenter" ){
throw "Specified VMware Server VirtualizationPlatform property must be a vCenter";
}

$failback = ($force -eq 0);

if(!$failback)
{
echo "Updating connection status for vCenter Server $vCenterComputerName ...";
$testConn = Test-VMwareServerConnection $vmWareServer.ServerName -Quiet;
$failback = $testConn.Passed;
}

if($failback)
{
$standaloneEsxHosts = Get-VMwareServer | ?{ $_.VirtPlatform -eq "ESX" } | %{ $_.Topology } | ?{ $_.Type -eq "Host" } | %{ $_.MonitoringTarget }
$vCenterHosts = $vmWareServer.Topology | Where { $_.Type -eq "Host" -and $standaloneEsxHosts -contains $_.Name }

try
{
$esxHosts = $vCenterHosts | % {$_.Name}

if($esxHosts -ne $null) { #### added for Force vCenter connection failover task

foreach ($esx in $esxHosts) {
echo ("Removing ESX host {0} from monitoring" -f $esx);
}

Remove-VMwareServer $esxHosts;
}
else
{
#### added for Force vCenter connection failover task
echo "No failed over direct ESX host connections avalable or connection has been already failed back to a healthy vCenter connection";
$oAPI.logscriptevent($scriptName, $eventId, 0, "No failed over direct ESX host connections avalable or connection has been already failed back to a healthy vCenter connection");
}
}
catch [Exception] {
$errorMsg = $_.Exception.Message;
echo "Error removing host from monitoring: $errorMsg";
}

if($vCenterHosts -ne $null) {
echo "Enabling monitoring of vCenter Server $vCenterComputerName";
Enable-Monitoring -VMwareServer $vmWareServer -Include $vCenterHosts -Force;
$oAPI.logscriptevent($scriptName, $eventId, 0, "vCenter Server $vCenterComputerName is now available and will be failed back from direct ESX(i) host connections.");
}
}
else
{
echo "VMware vCenter Server $vcName is unavailable, failback operation cannot be performed, Veeam MP will continue to monitor Hosts via direct connections";
}

}

Function Import-ModuleIfNot
{
$moduleName = "Psves";
$moduleLoaded = $false;
$Error.Clear();
Import-Module $moduleName -ErrorAction:SilentlyContinue;
if ($Error.Count -ne 0)
{
$rkey = "HKLM:\SYSTEM\CurrentControlSet\Services\VeeamVE";
$rvalName = "ImagePath";
$rval = Get-ItemProperty -path:$rkey -name:$rvalName -ErrorAction:SilentlyContinue;
$modulePath = "";
if ($rval -ne $null)
{
$dbPath = $rval.ImagePath;
$vesPath = $dbPath.Replace('"', '');
$vesPath = $vesPath.Remove($vesPath.LastIndexOf("\"));
$vesPath = $vesPath.Remove($vesPath.LastIndexOf("\"));
$modulePath = $vesPath + "\VE Shell\Modules";
}
$Error.Clear();
Import-Module "$modulePath\$moduleName" -ErrorAction:SilentlyContinue;
}

if ($Error.Count -eq 0)
{
$moduleInf = Get-Module | ? {$_.Name -eq $moduleName};
if ($moduleInf -ne $null)
{
$moduleLoaded = $true;
}
}

return $moduleLoaded;
}

Function Invoke-Action
{
Param ([string]$vCenterComputerName, [string]$username, [string]$pass, [int]$direction)
# direction parameter possible values 0 or 1
# 0 Convert-VCenterConnectionToDirectEsxConnection
# 1 Convert-DirectEsxConnectionToVCenterConnection
$password = $pass | ConvertTo-SecureString -asPlainText -Force;
$credential = New-Object System.Management.Automation.PSCredential($username, $password)

if ( Import-ModuleIfNot )
{
$rkey = "HKLM:\SOFTWARE\Veeam\Veeam Virtualization Extensions for VMware\Manager";
$rvalName = "Port";
$rval = Get-ItemProperty -path:$rkey -name:$rvalName -ErrorAction:SilentlyContinue;
$port = "8084";
if ($rval -ne $null)
{
$port = $rval.Port;
}

Start-VEShellClient -ServerPort $port -ServerName localhost;
switch ($direction)
{
0 {
Convert-VCenterConnectionToDirectEsxConnection $vCenterComputerName $credential;
}
1 {
Convert-DirectEsxConnectionToVCenterConnection $vCenterComputerName;
}
default {
LogErrorMessage "Unknown direction parameter value, $direction";
}
}
}
else
{
LogErrorMessage "Psves module is not installed";
}
}

try {
Invoke-Action $vcName $login $pwd $mode;
}
catch [Exception] {
$errorMsg = $_.Exception.Message;
LogErrorMessage "Error: $errorMsg";
}</Script></ScriptBody>
<Parameters>
<Parameter>
<Name>vcName</Name>
<Value>$Config/vCenterName$</Value>
</Parameter>
<Parameter>
<Name>login</Name>
<Value>$RunAs[Name="VeeamVEBaseDisc!Veeam.Virt.Extensions.VMware.ESXMonitoringAccount"]/UserName$</Value>
</Parameter>
<Parameter>
<Name>pwd</Name>
<Value>$RunAs[Name="VeeamVEBaseDisc!Veeam.Virt.Extensions.VMware.ESXMonitoringAccount"]/Password$</Value>
</Parameter>
<Parameter>
<Name>mode</Name>
<Value>$Config/mode$</Value>
</Parameter>
<Parameter>
<Name>force</Name>
<Value>$Config/force$</Value>
</Parameter>
</Parameters>
<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
</WriteAction>
</MemberModules>
<Composition>
<Node ID="RunScript"/>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>Windows!Microsoft.Windows.SerializedObjectData</OutputType>
<InputType>System!System.BaseData</InputType>
</WriteActionModuleType>