Fujitsu PROPack Recovery Action

Fujitsu.PRIMERGY.PRO.RecoveryAction (WriteActionModuleType)

Fujitsu PRO Pack recovery action for corresponding PRO Tip implementation

Element properties:

TypeWriteActionModuleType
IsolationAny
AccessibilityInternal
RunAsDefault
InputTypeSystem.BaseData
OutputTypeMicrosoft.Windows.SerializedObjectData

Member Modules:

ID Module Type TypeId RunAs 
RecoveryAction WriteAction Microsoft.SystemCenter.VirtualMachineManager.PRO.V2.Recovery.RecoveryScriptModule Default

Overrideable Parameters:

IDParameterTypeSelectorDisplay NameDescription
EventDescriptionstring$Config/EventDescription$RecoveryActionRecovery action

Source Code:

<WriteActionModuleType ID="Fujitsu.PRIMERGY.PRO.RecoveryAction" Accessibility="Internal" Batching="false">
<Configuration>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="EventDescription" type="xsd:string"/>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="EventDescription" Selector="$Config/EventDescription$" ParameterType="string"/>
</OverrideableParameters>
<ModuleImplementation Isolation="Any">
<Composite>
<MemberModules>
<WriteAction ID="RecoveryAction" TypeID="PROV2Library!Microsoft.SystemCenter.VirtualMachineManager.PRO.V2.Recovery.RecoveryScriptModule">
<EventDescription>$Config/EventDescription$</EventDescription>
<ScriptBody><Script>
#get param
Param($Params);
set-psdebug -strict;
$erroractionpreference = "SilentlyContinue";

$Error.Clear();

# create Event source if it need
if ([system.diagnostics.eventlog]::SourceExists("FujitsuPROPack") -eq $False)
{
[system.diagnostics.EventLog]::CreateEventSource("FujitsuPROPack", "Application")
}

$STATE_RUNNING = "Running";
$STATE_SUCCESS = "Completed";
$STATE_CANCELING = "Canceling";
$STATE_WARNING = "SucceedWithInfo";
$STATE_ERROR = "Failed";

$MIGRATION_LIVE = "Live";
$MIGRATION_LIVEVSM = "LiveVSM";

$ClusterId = $null;

$global:MigrationMaximumVMs = 1;
$global:VMPriority = $FALSE;
$global:ConsiderAvailableSetsproperty = $FALSE;
$global:ConsiderShouldandShouldNotcustomsproperty = $FALSE;
$global:ConsiderPrefferedOwnersforVMs = $FALSE;

$global:MutexGlobalLog = $null;
$global:MutexGlobalConfig = $null;
$global:MutexGroup = $null;

# Logging functionality
$global:LogFileFullPath = "";
$global:IsLogEnabled = $FALSE;
$JobCount = 0;

# PROTip information
$protip = "";
$global:ProTipStatus = "Resolved";

$VMError = new-object collections.arraylist; # VM ID with error in process migrate will be ignored
$Jobs = new-object collections.arraylist; # the list of started job, contains only running and prolem jobs

# method: write to event log without PRO Tip
function Logging([string]$Message)
{
#write to log file
if( $global:IsLogEnabled -eq $TRUE)
{
$DateTime = Get-Date;
$message = "{0} {1} {2} : {3}" -f $DateTime.ToShortDateString(), $DateTime.ToLongTimeString(), $protip, $Message;
[bool]$wasCreatedLog = $true;
[bool]$requestInitialOwnershipLog = $true;
$MutexGlobalCreateLog = $false;

while($MutexGlobalCreateLog -ne $true)
{
try
{
$global:MutexGlobalLog = new-object -TypeName System.Threading.Mutex($requestInitialOwnershipLog, "FujitsuPRIMERGYPROPackv5.2Log",[ref]$wasCreatedLog);
if((EventLogError 120) -eq 1) { return; }
if (!($requestInitialOwnershipLog -and $wasCreatedLog))
{
$Result = $global:MutexGlobalLog.WaitOne();
$Error.Clear();
}
$MutexGlobalCreateLog = $true;
}
catch
{
$MutexGlobalCreateLog = $false;
}
}
Add-Content -Path $global:LogFileFullPath -Value $message;
# End of critical section
if($global:MutexGlobalLog -ne $null)
{
#LoggingAnotherFile "End of critical section of global mutex";
$global:MutexGlobalLog.ReleaseMutex();
$global:MutexGlobalLog = $null;
}
$Error.Clear();
}
};

# method: write to event log without PRO Tip
function EventLogInformation([int]$id, [string]$Message)
{
Write-EventLog -LogName "Application" -Source "FujitsuPROPack" -EventId $id -EntryType Information -Message $Message -Category 0;
Logging $Message;
$Error.Clear();
};

# method: write to event log Error without PRO Tip
function LoggingError([int]$MessageId, [string]$Message)
{
#write to log file
if( $global:IsLogEnabled -eq $TRUE)
{
$DateTime = Get-Date;
$message = "{0} {1} {2} : ErrorID='{3}' ErrorText='{4}'" -f $DateTime.ToShortDateString(), $DateTime.ToLongTimeString(), $protip, $MessageId, $Message;
Add-Content -Path $global:LogFileFullPath -Value $message;
$Error.Clear();
}
};

# method: initialize logging to file
function InitializeLogToFile($Debugging )
{
$LogFileName = "FujitsuPROPackRecovery.log";
$LogFileName1 = "FujitsuPROPackRecovery1.log";
$IniFileName = "SVIVMM-PROLog.ini";
$MaxLogFileSize = 10 * 1024 * 1024;

$folderPath = "{0}{1}" -f [environment]::GetEnvironmentVariable("Temp","Machine"), "\SVISCOM\SVISCOM-PRO\";
# Read ini file. Check if logging enabled and get max log file size.
$IniFilefullPath = $folderPath + $IniFileName;

if( test-path $IniFilefullPath )
{
$reader = [System.IO.File]::OpenText( $IniFilefullPath )
try
{
$line = $reader.ReadLine()
for(;;)
{
if ($line -eq $null) { break }
# process the line
if( $line -eq "[Recovery]" )
{
for(;;)
{
$line = $reader.ReadLine();

if( $line -match "^Size=(\d+)" )
{
$MaxLogFileSize = [int]$matches[1] * 1024 *1024;
}
elseif ( $line -eq "" )
{
continue;
}
else{
break;
}
}
continue;
}
$line = $reader.ReadLine();
}
}
finally
{
$reader.Close()
}
}

if( ($global:IsLogEnabled -eq $TRUE) -or ($Debugging.ToLower() -eq "yes") )
{
$global:IsLogEnabled = $TRUE;
# Check if log file is full
$global:LogFileFullPath = $folderPath + $LogFileName;

if( test-path $global:LogFileFullPath )
{
$var = Get-Item $global:LogFileFullPath
$file_size = $var.length
if( $var.length -gt $MaxLogFileSize )
{
$LogFileFullPath1 = $folderPath + $LogFileName1;
if( test-path $LogFileFullPath1 )
{
Remove-Item $LogFileFullPath1
}
Rename-Item $global:LogFileFullPath $LogFileFullPath1;
}
}
}
$Error.Clear();
};

function InitializeConfigLog()
{
$IniFileName = "SVIMM-PROConfig.ini";

$folderPath = "{0}{1}" -f [environment]::GetEnvironmentVariable("Temp","Machine"), "\SVISCOM\SVISCOM-PRO\";
# Read ini file. Check if logging enabled and get max log file size.
$IniFilefullPath = $folderPath + $IniFileName;

if( test-path $IniFilefullPath )
{
$reader = [System.IO.File]::OpenText( $IniFilefullPath )
try
{
$line = $reader.ReadLine()
for(;;)
{
if ($line -eq $null) { break }
# process the line
if( $line -eq "[Recovery]" )
{
for(;;)
{
$line = $reader.ReadLine();

if( $line -match "^MigrationMaximumVMs=(\d+)" )
{
$global:MigrationMaximumVMs = [int]$matches[1];
}
elseif( $line -match "^Trace=(On|on|Off|off)")
{
if( $matches[1].ToLower() -eq "on" )
{
$global:IsLogEnabled = $TRUE;
}

}
elseif( $line -match "^VMPriority=(On|on|Off|off)")
{
if( $matches[1].ToLower() -eq "on" )
{
$global:VMPriority = $TRUE;
}
}
elseif( $line -match "^ConsiderAvailableSetsproperty=(On|on|Off|off)")
{
if( $matches[1].ToLower() -eq "on" )
{
$global:ConsiderAvailableSetsproperty = $TRUE;
}
}
elseif( $line -match "^ConsiderShouldandShouldNotcustomsproperty=(On|on|Off|off)")
{
if( $matches[1].ToLower() -eq "on" )
{
$global:ConsiderShouldandShouldNotcustomsproperty = $TRUE;
}
}
elseif( $line -match "^ConsiderPrefferedOwnersforVMs=(On|on|Off|off)")
{
if( $matches[1].ToLower() -eq "on" )
{
$global:ConsiderPrefferedOwnersforVMs = $TRUE;
}
}
elseif ( $line -eq "" )
{
continue;
}
else{
break;
}
}
continue;
}
$line = $reader.ReadLine();
}
}
finally
{
$reader.Close()
}

}
$Error.Clear();
};





# method: allocate memory for array
function new-array
{
$args
};

# method: Check errors and write to event log
function EventLogError([int]$id)
{
$Return = 0;
if($Error.Count -ne 0)
{
$Message = $Error[0].ToString();
$arrayError = new-array $protip $Message;
LoggingError $id $Message;
Write-EventLog -LogName "Application" -Source "FujitsuPROPack" -EventId $id -EntryType Error -Message $Message -Category 0;
Set-SCPROTip -PROTipId $protip -LastError $Message -LastErrorOpsMgrString $arrayError -TipStatus Failed;
$Return = 1;
$Error.Clear();
}
return $Return;
};

# method: Check errors and write to event log and do not set PRO Tip state
function EventLogErrorNoProTip([int]$id)
{
$Return = 0;
if($Error.Count -ne 0)
{
$Message = $Error[0].ToString();
LoggingError $id $Message;
Write-EventLog -LogName "Application" -Source "FujitsuPROPack" -EventId $id -EntryType Error -Message $Message -Category 0;
$Return = 1;
$Error.Clear();
}
return $Return;
};

# method: write to event log without PRO Tip
function EventLogNoProTip([string]$type, [int]$id, [string]$Message)
{
Write-EventLog -LogName "Application" -Source "FujitsuPROPack" -EventId $id -EntryType $type -Message $Message -Category 0;
LoggingError $id $Message;
$Error.Clear();
};

# method: write to event log
function EventLog([string]$type, [int]$id, [string]$Message, [string]$statusProTip)
{
EventLogNoProTip $type $id $Message;
$arrayError = new-array $protip $Message;
Set-SCPROTip -PROTipId $protip -LastError $Message -LastErrorOpsMgrString $arrayError -TipStatus $statusProTip;
LoggingError $id $Message;
$Error.Clear();
};

# logging list of hosts
function LoggingVMs($VMs, $Text)
{
$Message = $Text + " : ";
foreach($item in $VMs)
{
$Message = $Message + $item.Name + "; ";
}
Logging $Message;
}

#get all vm from host
function GetVM($CurrentHost)
{
Logging "Get list of virtual machine";

# Reception VMs for host: ...
$AllVMs = @(Get-SCVirtualMachine -VMHost $CurrentHost);
if((EventLogErrorNoProTip 106) -eq 1) { return; }
LoggingVMs $AllVMs "Received VMs list for host ";

# Remove failed VMs from list
foreach($item in $VMError)
{
$NewVMs = @($AllVMs | where { $_.ID -ine $item } );
$AllVMs = $NewVMs;
}
LoggingVMs $AllVMs "Remove failed VMs from the list ";

# Searching running VMs for migrate
$VMs = @($AllVMs | where { $_.Status -ieq 'Running' } | where { $_.ExcludeFromPRO -ne $TRUE} | where {$_.IsPrimaryVM -ieq $False});
LoggingVMs $VMs "Searching running VMs for migrate";

# Remove VMs which was already started for migration but where Status is still running.
foreach($item in $Jobs)
{
$NewVMs = @($VMs | where {$_.ID -ne $item.VM.ID});
$VMs = $NewVMs;
}
LoggingVMs $VMs "Remove VMs which was already started to migration ";

# Sorting running VMs for migrate
if($global:VMPriority -eq $true)
{
$Message = "VM sorted by the VM priority";
$VMs = $VMs | Sort-Object -property @{Expression="HAVMPriority"; Descending=$true}, @{Expression="Memory"; Descending=$true} ;
Logging $Message;
}
else
{
$Message = "VM not sorted by the VM priority";
$VMs = $VMs | Sort-Object -property @{Expression="Memory"; Descending=$true} ;
Logging $Message;
}
LoggingVMs $VMs "Final list of VMs for migration on host";
return $VMs;
};

# check count of Live migrations
function CheckCountLiveMigration($HostsCandidateItem, $SourceHost)
{
Logging "Check count of Live and LiveVSM migration";

$TransferType = $HostsCandidateItem.TransferType;
$Message = "The current transfered type is '" + $HostsCandidateItem.TransferType + "' to the host: " + $HostsCandidateItem.Name;
Logging $Message;

# Check current transfered type, if it's Live or LiveVSM
if(($TransferType -ieq $MIGRATION_LIVE) -or ($TransferType -ieq $MIGRATION_LIVEVSM))
{
while(1)
{
$RunningJobsTarget = @();
$RunningJobsTarget1 = @();
$RunningJobsTarget2 = @();
$RunningJobsSource = @();
$RunningJobsSource1 = @();
$RunningJobsSource2 = @();

# Get all VMM running jobs
Logging "Get running virtual machine jobs";
$RunningJobs = Get-SCJob | where {"Running" -ieq $_.Status };

if($RunningJobs -eq $null -or $RunningJobs.Count -eq 0)
{return $true;}

$Message = "Running jobs cmdlet: " + $RunningJobs.CmdletName;
Logging $Message;
$Message = "Source: " + $RunningJobs.Source;
Logging $Message;
#get all jobs at target host
$RunningJobsTarget1 = $RunningJobs | where {$HostsCandidateItem.Name -ieq $_.Source };
$RunningJobsTarget2 = $RunningJobs | where {$HostsCandidateItem.Name -ieq $_.Target };
if(($RunningJobsTarget1 -ne $null)-and($RunningJobsTarget2 -ne $null))
{
$RunningJobsTarget = $RunningJobsTarget + $RunningJobsTarget1;
$RunningJobsTarget = $RunningJobsTarget + $RunningJobsTarget2;
}
elseif($RunningJobsTarget2 -eq $null)
{
$RunningJobsTarget = $RunningJobsTarget1;
}
else
{
$RunningJobsTarget = $RunningJobsTarget2;
}
#get all jobs at source host
$RunningJobsSource1 = $RunningJobs | where {$SourceHost.Name -ieq $_.Source };
$RunningJobsSource2 = $RunningJobs | where {$SourceHost.Name -ieq $_.Target };
if(($RunningJobsSource1 -ne $null)-and($RunningJobsSource2 -ne $null))
{
$RunningJobsSource = $RunningJobsSource + $RunningJobsSource1;
$RunningJobsSource = $RunningJobsSource + $RunningJobsSource2;
}
elseif($RunningJobsSource2 -eq $null)
{
$RunningJobsSource = $RunningJobsSource1;
}
else
{
$RunningJobsSource = $RunningJobsSource2;
}


if((EventLogErrorNoProTip 116) -eq 1) { continue; }

$RunJob = $RunningJobsTarget | where {"Move-SCVirtualMachine" -ieq $_.CmdletName};
$RunningJobsTarget = $RunJob;
$RunJob = $RunningJobsSource | where {"Move-SCVirtualMachine" -ieq $_.CmdletName};
$RunningJobsSource = $RunJob;
break;
}

# Logging Selection jobs
$Message = "Running jobs target cmdlet: " + $RunningJobsTarget.CmdletName;
Logging $Message;
$Message = "Description job target: " + $RunningJobsTarget.Description.Code;
Logging $Message;

$Message = "Running jobs source cmdlet: " + $RunningJobsSource.CmdletName;
Logging $Message;
$Message = "Description job source: " + $RunningJobsSource.Description.Code;
Logging $Message;

#get all LIVE running jobs at source and target
$RunningJobsTargetLive = $RunningJobsTarget | where {"MoveVMUsingCluster" -ieq $_.Description.Code };
$RunningJobsSourceLive = $RunningJobsSource | where {"MoveVMUsingCluster" -ieq $_.Description.Code };
$RunningJobsTargetVSM = $RunningJobsTarget | where {"LiveMigrateVMAndStorage" -ieq $_.Description.Code };
$RunningJobsSourceVSM = $RunningJobsSource | where {"LiveMigrateVMAndStorage" -ieq $_.Description.Code };

#jobs count equal 0
if(($RunningJobsTargetLive -eq $null -or $RunningJobsTargetLive.Count -eq 0) -and
($RunningJobsSourceLive -eq $null -or $RunningJobsSourceLive.Count -eq 0) -and
($RunningJobsTargetVSM -eq $null -or $RunningJobsTargetVSM.Count -eq 0) -and
($RunningJobsSourceVSM -eq $null -or $RunningJobsSourceVSM.Count -eq 0))
{
$Message = "Jobs count is equal 0";
Logging $Message;
return $true;
}
$CountRunningJobsTarget = $RunningJobsTargetLive.Count + $RunningJobsTargetVSM.Count;
$Message = "Number of migration on the target host " + $CountRunningJobsTarget;
Logging $Message;
$CountRunningJobsSource = $RunningJobsSourceLive.Count + $RunningJobsSourceVSM.Count;
$Message = "Number of migration on the source host " + $CountRunningJobsSource;
Logging $Message;

if($TransferType -ieq $MIGRATION_LIVE)
{
$HostsCandidate = Get-SCVMHost -ComputerName $HostsCandidateItem.Name;
if($CountRunningJobsSource -ge $SourceHost.LiveMigrationMaximum)
{
$Message = "Migration Live. Migration doesn't start. Lots of migration on the source host";
Logging $Message;
return $false;
}
elseif($CountRunningJobsTarget -ge $HostsCandidate.LiveMigrationMaximum)
{
$Message = "Migration Live. Migration doesn't start. Lots of migration on the target host";
Logging $Message;
return $false;
}
else
{
$Message = "Migration Live. Migration started";
Logging $Message;
return $true;
}
}
elseif($TransferType -ieq $MIGRATION_LIVEVSM)
{
$HostsCandidate = Get-SCVMHost -ComputerName $HostsCandidateItem.Name;
if($RunningJobsTargetVSM.Count -ge $HostsCandidate.LiveStorageMigrationMaximum)
{
$Message = "Migration LiveVSM. Migration doesn't start. Lots of migration LiveVSM on the target host";
Logging $Message;
return $false;
}
elseif($RunningJobsSourceVSM.Count -ge $SourceHost.LiveStorageMigrationMaximum)
{
$Message = "Migration LiveVSM. Migration doesn't start. Lots of migration LiveSVM on the source host";
Logging $Message;
return $false;
}
else
{
if($CountRunningJobsSource -ge $SourceHost.LiveMigrationMaximum)
{
$Message = "Migration LiveVSM. Migration doesn't start. Lots of migration on the source host";
Logging $Message;
return $false;
}
elseif($CountRunningJobsTarget -ge $HostsCandidate.LiveMigrationMaximum)
{
$Message = "Migration LiveVSM. Migration doesn't start. Lots of migration on the target host";
Logging $Message;
return $false;
}
else
{
$Message = "Migration LiveVSM. Migration started";
Logging $Message;
return $true;
}
}
}
}
# All other types of migration could be started unlimited.
return $true;
}

# Select hosts candidate and migration VM:
# VMitem - VM for migration
# SourceHost - source host for migration
# this method returned: 0 - success, 1 - there are no host for migration, 2 - error happaned, 3 - migrate job was not started, because the count of started live migration is maximum
function MigrateVM($VMcandidate, $SourceHost)
{
# Cycle of search of VM for migration
Logging "Cycle of search of VM for migration";
# the return value from this method by default
$Return = 2;
Logging $VMcandidate;

#select host for migration
$HostsCandidate = SelectHost $VMcandidate $SourceHost;
if(($HostsCandidate -ne $null) -or ($HostsCandidate.Count -eq 0) -or ($VMcandidate -ne $null))
{
Logging "Beginning of migration section"

# Migrate to host
foreach($HostsCandidateItem in $HostsCandidate)
{
# Get host object by host name
$Message = "Get host object by host name " + $HostsCandidateItem.Name;
Logging $Message;

# It's important. We need to have another object for Move-SCVirtualMachine method
$HostMigrate = Get-SCVMHost -ComputerName $HostsCandidateItem.Name;
if((EventLogErrorNoProTip 113) -eq 1) { continue; }
if($HostMigrate -eq $null) { continue; }

$MoveVMJob = $null;
# Migrate host by type
if((($isHostCluster -eq $false) -or
(($isHostCluster -eq $true) -and ($VMcandidate.IsHighlyAvailable -eq $false)) -or
(($isHostCluster -eq $true) -and ($HostsCandidateItem.HostCluster -eq $null))) -and ($HostsCandidateItem.TransferType -ine $MIGRATION_LIVE))
{
$Message = "Migrate host by type. Host " + $HostsCandidateItem.Name + " is non-clustered host or cluster with highly available or migrate "
Logging $Message;
$Message = "Host " + $HostsCandidateItem.Name + " has rating " + $HostsCandidateItem.Rating;
Logging $Message;
$VMPathsMigrate = @();

if(($HostsCandidateItem.PreferredVolume -ne $null) -and ($HostsCandidateItem.PreferredVolume -ne ""))
{
# Suitable folders on preferable volume '" + $HostsCandidateItem.PreferredVolume.ToString() + "' : ";
$Message = "Suitable folders on preferable volume '" + $HostsCandidateItem.PreferredVolume.ToString() + "' : ";
foreach($VMPath in $HostMigrate.VMPaths)
{
$PreferredVolume = $HostsCandidateItem.PreferredVolume.ToString();
if($VMPath.ToLower().StartsWith($PreferredVolume.ToLower()))
{
$VMPathsMigrate = $VMPathsMigrate + $VMPath;
$Message = $Message + $VMPath + "; ";
}
}
if($VMPathsMigrate.Count -eq 0)
{
foreach($VolumeItem in $HostMigrate.DiskVolumes.Name)
{
if($VolumeItem.ToLower().StartsWith($PreferredVolume.ToLower()))
{
$VMPathsMigrate = $VMPathsMigrate + $VolumeItem;
$Message = $Message + $VolumeItem + "; ";
}
}
}
Logging $Message
}
else
{
# There is no preferable volume.
Logging "There is no preferable volume."
if($HostMigrate.VMPaths.Count -ne 0)
{
# "Folder for migrate '" + $HostMigrate.VMPaths[0];
$Message = "Folder for migrate '" + $HostMigrate.VMPaths[0];
Logging $Message
$VMPathsMigrate = $VMPathsMigrate + $HostMigrate.VMPaths[0];
}
}
# There is not suitable folder
if( $VMPathsMigrate.Count -eq 0)
{
Logging "There is not suitable folder";
continue;
}
# Migration VM=" + $VMcandidate.Name + " to Host="+ $HostMigrate.Name + " in Folder=" + $VMPathsMigrate[0].ToString()
$Message = "Migration VM=" + $VMcandidate.Name + " to Host="+ $HostMigrate.Name + " in Folder=" + $VMPathsMigrate[0].ToString();
Logging $Message;

if(CheckCountLiveMigration $HostsCandidateItem $SourceHost)
{
$RetMoveMachine = Move-SCVirtualMachine -VMHost $HostMigrate -VM $VMcandidate -Path $VMPathsMigrate[0].ToString() -PROTipId $protip -RunAsynchronously -BlockLiveMigrationIfHostBusy -JobVariable "MoveVMJob" -StartVMOnTarget;
$MoveVMJob.Source;
if((EventLogErrorNoProTip 114) -eq 1) { return; }
$Return = 0;
}
else
{
$Return = 3;
}
}
# Migrate host by type. Host " + $HostsCandidateItem.Name + " is cluster without highly available."
else
{
$Message = "Migrate host by type. Host " + $HostsCandidateItem.Name + " is cluster without highly available.";
Logging $Message;
$Message = "Host " + $HostsCandidateItem.Name + " has rating " + $HostsCandidateItem.Rating;
Logging $Message;
# Migration VM=" + $VMcandidate.Name + " to Host="+ $HostMigrate.Name;
$Message = "Migration VM=" + $VMcandidate.Name + " to Host="+ $HostMigrate.Name;
Logging $Message;
if(CheckCountLiveMigration $HostsCandidateItem $SourceHost)
{
$RetMoveMachine = Move-SCVirtualMachine -VMHost $HostMigrate -VM $VMcandidate -PROTipId $protip -RunAsynchronously -JobVariable "MoveVMJob" -BlockLiveMigrationIfHostBusy -StartVMOnTarget;
$MoveVMJob.Source;
if((EventLogErrorNoProTip 115) -eq 1) { return; }
$Return = 0;
}
else
{
$Return = 3;
}
}

# Store Job for moving virtual machine
if($MoveVMJob -ne $null)
{
while(($MoveVMJob.Source -eq $null) -or($MoveVMJob.Target -eq $null))
{
if($MoveVMJob.Status -ieq "Failed")
{
$Message = "Completion of waiting. Migration current VM failed";
Logging $Message;
break;
}
$Message = "Waiting the source and target";
Logging $Message;
sleep -m 500;

}
# End of critical section
Logging "End of critical section";
if($global:MutexGroup -ne $null)
{
Logging "End of critical section for Group";
$global:MutexGroup.ReleaseMutex();
$global:MutexGroup = $null;
}
# Find job by VM ID
$job = $Jobs | where {$_.VM.ID -ieq $VMcandidate.ID};
# The job was found
if($job -eq $null)
{
Logging "Create new record for new job";
$job = New-Object PSObject -Property @{ job=$MoveVMJob; VM=$VMcandidate; VMLocation=$VMcandidate.Location; Hosts=@($HostMigrate.Name) };
$RetJobs = $Jobs.Add($job);
$Message = "Job started: " + $MoveVMJob.Name + " VM: " + $VMcandidate.Name + " Destination Host: " + $HostMigrate.Name;
Logging $Message;
}
else
{
Logging "Modify old record for job";
# The old job finished unsuccessful
$job.job = $MoveVMJob;
# Add host for next try to migrate
$job.Hosts = $job.Hosts + $HostMigrate.Name;
}
}
break;
} #foreach
# Migration attempts are finished.
Logging "Migration attempts are finished.";

# There are no hosts with valid rating to migrate of VM " + $VMcandidate.Name
# Because Return value didn't changed before
if($Return -eq 2)
{
$Message = "There are no hosts with valid rating to migrate of VM " + $VMcandidate.Name;
Logging $Message;
# End of critical section
if($global:MutexGroup -ne $null)
{
Logging "End of critical section for Group";
$global:MutexGroup.ReleaseMutex();
$global:MutexGroup = $null;
}
$RetErrors = $VMError.Add($VMcandidate.ID);
$global:ProTipStatus = "Failed";
$Return = 1;
}
# End of migration section
Logging "End of migration section";
#continue;
}# end if
return $Return;
};

# choose the most preferred host for migration
function SelectHost($VMitem, $SourceHost)
{
$ShouldMatch = new-object collections.arraylist;
$ShouldNotMatch = new-object collections.arraylist;
$FlagShouldMach = $false;

# Searching hosts for migrate VM " + $VMitem.Name
$Message = "Searching hosts for migrate VM " + $VMitem.Name;
Logging $Message;

# Get list of hosts in same group of hosts " + $SourceHost.Name
$hostsAll = Get-SCVMHost -VMHostGroup $SourceHost.VMHostGroup;
if((EventLogErrorNoProTip 107) -eq 1) { return ; }
LoggingHosts $hostsAll $VMitem.Name "All Hosts ";

#get should and not should custom property from hostGroup
if($global:ConsiderShouldandShouldNotcustomsproperty -eq $true)
{
$Message = "Get custom property from hostgroup";
Logging $Message;
$PlacementConfig = Get-SCPlacementConfiguration -VMHostGroup $SourceHost.VMHostGroup;
$CustomPlacementRule = Get-SCCustomPlacementRule -PlacementConfiguration $PlacementConfig;
foreach($custRule in $CustomPlacementRule)
{
if($custRule.RuleType -eq "ShouldMatch")
{
$Operation = $ShouldMatch.Add($custRule.CustomPropertyName);
$FlagShouldMach = $true;
}
elseif($custRule.RuleType -eq "ShouldNotMatch")
{
$Operation = $ShouldNotMatch.Add($custRule.CustomPropertyName);
$FlagShouldMach = $true;
}
}
}


# Remove hosts with active PRO Tips
$ActiveProtips = Get-SCPROTip | where { $_.Status -ne "Closed" -and $_.Status -ne "Dismissed" -and $_.Status -ne "Resolved" };
if((EventLogErrorNoProTip 108) -eq 1) { return ; }
$HostsWithProtips = new-object collections.arraylist;

#Choose hosts with protips
while($ActiveProtips.Count -gt 0)
{
$ap = $ActiveProtips[0];
$ActiveProtips = $ActiveProtips | where { $_.Source.Name -ine $ap.Source.Name};
$HostsWithProtips+=$ap.Source.Name;
}

#Delete hosts with active ProTips
foreach($item in $HostsWithProtips)
{
$Newhosts = @($hostsAll | where {$_.Name -ne $item});
$hostsAll = $Newhosts;
}
LoggingHosts $hostsAll $VMitem.Name "Hosts after remove hosts with active protips ";

#remove cluster(non-clustered)

if($isHostCluster)
{
#delete non clustered hosts
$RezHost = $hostsAll| where { $_.HostCluster.Id -eq $ClusterId};
$hostsAll = $RezHost;
}
else
{
#delete clustered hosts
$RezHost = $hostsAll| where { $_.HostCluster -eq $null};
$hostsAll = $RezHost;
}

LoggingHosts $hostsAll $VMitem.Name "Hosts after remove clustered or non-clustered ";

$HostsMigrate = @();
$HostsMigrate = $hostsAll;

if($HostsMigrate.Count -eq 0)
{
# There are no hosts with valid rating to migration VM " + $VMitem.Name;
$Message = "There are no hosts with valid rating to migration VM " + $VMitem.Value.Name;
EventLogNoProTip Warning 109 $Message;
return ;
}
# Remove hosts where we already try to migrate current VM
Logging "Remove hosts where we already try to migrate current VM";
$job = $Jobs | where {$_.VM.ID -ieq $VMitem.ID};
$newHosts = new-object collections.arraylist;
if($job -ne $null)
{
foreach($item in $job.Hosts)
{
$HostsSorted = $HostsMigrate | where {$_.Name -ne $item};
$HostsMigrate = $HostsSorted;
}
}
if($HostsMigrate.Count -eq 0)
{
# There are no hosts with valid rating to migration VM " + $VMitem.Name;
$Message = "There are no hosts with valid rating to migration VM " + $VMitem.Value.Name;
EventLogNoProTip Warning 110 $Message;
return ;
}
LoggingHosts $HostsMigrate $VMitem.Name "List of hosts to migration of VM after remove error hosts ";

# Exception list of hosts from candidate list for migration of VM " + + " by using a method Get-SCVMHostRating";
$Message = "Exception list of hosts from candidate list for migration of VM " + $VMitem.Name + " by using a method Get-SCVMHostRating";
Logging $Message;


$HostsCustomProperty = new-object collections.arraylist;

$Myhost = @{};
if($FlagShouldMach -eq $true)
{

foreach($thishost in $HostsMigrate)
{
if($thishost.CustomProperty.Count -gt 0)
{
$Myhost.Add($thishost.Name,$thishost.CustomProperty);
}
}
}


$HostsRatings = @(Get-SCVMHostRating -VM $VMitem -VMHost $HostsMigrate -IsMigration -PlacementGoal "Consolidate" -UseDefaultPath);
if((EventLogErrorNoProTip 111) -eq 1) { continue; }
$HostsRatings = @($HostsRatings | where {$_.Rating -ne 0 });

if($HostsRatings.Count -eq 0)
{
# There are no hosts with valid rating to migration VM " + $VMitem.Name;
$Message = "There are no hosts with valid rating to migration VM " + $VMitem.Value.Name;
EventLogNoProTip Warning 112 $Message;
return ;
}
LoggingHosts $HostsRatings $VMitem.Name "List of hosts with rating ";
if($global:ConsiderPrefferedOwnersforVMs -eq $true)
{
# Sort by two parameters(Rating and PrefferedOwners)
quicksort $HostsRatings 0 ($HostsRatings.Count-1) $VMItem.ClusterPreferredOwner;
LoggingHosts $HostsRatings $VMitem.Name "List of hosts after sorting by Rating and PrefferedOwners ";
}
else
{
$HostsRatings = @($HostsRatings | Sort-Object -property Rating -descending);
LoggingHosts $HostsRatings $VMitem.Name "List of hosts after sorting by Rating ";
}


if($global:ConsiderAvailableSetsproperty -eq $true)
{
$Message = "Sorting hosts by available sets";
# Sort by AvailableSets
if($VMitem.AvailabilitySetNames -ne $null)
{
$AvSetNames = @($VMitem.AvailabilitySetNames);
$RezHostRating = [System.Collections.ArrayList]$HostsRatings;
$CountHosts = $RezHostRating.Count;
$i=0;
while($i -lt $CountHosts)
{
$VMsHost = new-object collections.arraylist;
#Select all machines on the possible hosts
$VMsPossibleHosts = @(Get-SCVirtualMachine | where { $_.HostName -eq $RezHostRating[$i].Name } );
foreach($AvSetName in $AvSetNames)
{
#Check VM content AvailableSet
$VMsWithSets = @($VMsPossibleHosts | where { $_.AvailabilitySetNames -ieq $AvSetName } );
#If VM contain AvailableSet, then move to the end of host mas
if($VMsWithSets -ne $null)
{
#Move the host to the end of list
$TEMP = $RezHostRating[$i];
$RezHostRating.Remove($TEMP);
$RetAddHost = $RezHostRating.Add($TEMP);
$CountHosts = $CountHosts - 1;
$i--;
break;
}
}
$i++;
}
$HostsRatings = $RezHostRating;
}
else
{
$Message = "Vm doesn't have available sets";
}
}
else
{
$Message = "Doesn't sorting hosts by available sets";
}
Logging $Message;

if(($FlagShouldMach -eq $true)-and($Myhost.Count -ge 0) -and ($VMitem.CustomProperty -ne $null))
{
$Message = "Sorting hosts by should and not should custom property";
Logging $Message;
$HostsRatings = SortingShouldProperty $HostsRatings $VMitem.CustomProperty $Myhost $ShouldMatch $ShouldNotMatch;
}

$HostsSorted = $HostsRatings;
# Final list of hosts for migration VM" + $VMitem.Name + " : "
LoggingHosts $HostsSorted $VMitem.Name "Final list of hosts for migration VM ";


return $HostsSorted;
}


function SortingShouldProperty($HostsRatings, $VMCustProperty, $Myhost, $ShouldMatch, $ShouldNotMatch)
{
$ShouldHost = new-object collections.arraylist;
$ShouldNotHost = new-object collections.arraylist;

foreach($HostCustomProp in $Myhost.GetEnumerator())
{
$flag = $false;
foreach($snm in $ShouldNotMatch)
{
if($HostCustomProp.Value.ContainsKey($snm))
{
if($HostCustomProp.Value.$snm -eq $VMCustProperty.$snm)
{
$Operation = $ShouldNotHost.Add(([String]$HostCustomProp.Key));
$flag = $true;
break;
}
}
}
if($flag -eq $true)
{
continue;
}
foreach($sm in $ShouldMatch)
{
if($HostCustomProp.Value.ContainsKey($sm))
{
if($HostCustomProp.Value.$sm -eq $VMCustProperty.$sm)
{
$Operation = $ShouldHost.Add(([String]$HostCustomProp.Key));
break;
}
}
}
}

$SHR = new-object collections.arraylist;
$SHNR = new-object collections.arraylist;
$SR = new-object collections.arraylist;


foreach($hostRat in $HostsRatings)
{
if($ShouldHost.Contains($hostRat.Name))
{
$SHR += $hostRat;
}
elseif($ShouldNotHost.Contains($hostRat.Name))
{
$SHNR += $hostRat;
}
else
{
$SR += $hostRat;
}

}
$HostsRatings = $SHR + $SR + $SHNR;
return $HostsRatings;
}

# logging list of hosts for method select hosts
function LoggingHosts($AllHosts,$VMitemName, $Text)
{
$Message = $Text + $VMitemName + " : ";
foreach($HostItem in $AllHosts)
{
if($HostItem.Rating -eq $null)
{
$Message = $Message + $HostItem.Name+ " ; ";
}
else
{
$Message = $Message + $HostItem.Name +"-" + $HostItem.Rating+ " ; ";
}
}
Logging $Message;
}

# Compare two hosts by Id and $PreferredOwnerer(if necessary compare by rating)
function CompareHosts($value1,$value2,$PreferredOwner)
{
#get Id's of hosts compared
$Id_Value1 = ReturnId $value1 $PreferredOwner;
$Id_Value2 = ReturnId $value2 $PreferredOwner;
if($Id_Value1 -gt $Id_Value2)
{
return 1;
}
elseif($Id_Value1 -lt $Id_Value2)
{
return -1;
}
else
{
# Id's hosts the same
if($value1.Rating -gt $value2.Rating)
{
return -1;
}
if($value1.Rating -lt $value2.Rating)
{
return 1;
}
return 0;
}
}

# return id(use rating and check PrefferedOwners)
function ReturnId($MyHost,$PreferredOwner)
{
$id = 0;
$Check = $false;
$Rating = $MyHost.Rating;
# search check $PreferredOwnerer
foreach($val in $PreferredOwner)
{
if($val.Name -ieq $MyHost.Name)
{ $Check = $true; break; }
}
# take id
switch ($Check)
{
$true
{
if($Rating -gt 4) { $id = 1; }
elseif(($Rating -gt 3) -and ($Rating -le 4)) { $id = 2; }
elseif(($Rating -gt 2) -and ($Rating -le 3)) { $id = 3; }
elseif(($Rating -gt 1) -and ($Rating -le 2)) { $id = 5; }
elseif(($Rating -gt 0) -and ($Rating -le 1)) { $id = 7; }
}
$false
{
if($Rating -gt 4) { $id = 4; }
elseif(($Rating -gt 3) -and ($Rating -le 4)) { $id = 6; }
elseif(($Rating -gt 2) -and ($Rating -le 3)) { $id = 8; }
elseif(($Rating -gt 1) -and ($Rating -le 2)) { $id = 9; }
elseif(($Rating -gt 0) -and ($Rating -le 1)) { $id = 10; }
}
}
return $id;
};

# The quick sort of host candidate for migration by the Rating and Preferred Owner
function quicksort($HostsRatings, $left, $right,$PreferredOwner)
{
#get the middle element
$middle = ($left+$right) %2;
$MiddleValue = ($left+$right - $middle)/2;
# get the value of the middle element
$MiddleElem = $HostsRatings[$MiddleValue];
$i = $left;
$j = $right;
while($i -le $j)
{
while((CompareHosts $HostsRatings[$i] $MiddleElem $PreferredOwner) -lt 0)
{
$i++;
};
while((CompareHosts $HostsRatings[$j] $MiddleElem $PreferredOwner) -gt 0)
{
$j--;
};
# If the values are in the wrong order, swap them.
if( $i -le $j )
{
$temp = $HostsRatings[$i];
$HostsRatings[$i] = $HostsRatings[$j];
$HostsRatings[$j] = $temp;
$i++;
$j--;
}
}
# Apply the algorithm to the partitions we made, if any.
if($left -lt $j)
{
quicksort $HostsRatings $left $j $PreferredOwner;
}
if($i -lt $right)
{
quicksort $HostsRatings $i $right $PreferredOwner;
}
};

# check state of all running jobs, restore VM if migration finished unsuccessful.
function CheckJobsState($SourceHost)
{
$Message = "Check JobsState, jobs count: " + $Jobs.Count;
Logging $Message;
$RemoveJobs = new-object collections.arraylist; # the list of jobs which we need to remove after check
Logging "Circle by Jobs";
foreach($item in $Jobs)
{
# Job successful finished
if($item.job.Status -ieq $STATE_SUCCESS)
{
$Message = "Job finished successfull, VM: " + $item.VM.Name;
Logging $Message;
$RemoveJobs.Add($item);
}
# Job canceled by the user
elseif($item.job.Status -ieq $STATE_CANCELING)
{
$Message = "Job canceled by user, VM: " + $item.VM.Name;
Logging $Message;
$RemoveJobs.Add($item);
}
# Job finished with warning

elseif($item.job.Status -ieq $STATE_WARNING)
{
$Message = "Job finished with warning, VM: " + $item.VM.Name;
Logging $Message;

# Migration finished with warning, but VM is Running
if($item.VM.Status -ieq "Running")
{
Logging "VM is running after the migration";
$RemoveJobs.Add($item);
continue;
}
# Migrate VM from new host to the newest host
$ret = MigrateVM $item.VM $item.VM.VMHost;
# End of critical section
if($global:MutexGroup -ne $null)
{
Logging "End of critical section for Group";
$global:MutexGroup.ReleaseMutex();
$global:MutexGroup = $null;
}
# Check return value,
#if value 0 - migration started successfully
if($ret -eq 0)
{
Logging "Migration started successfully";
continue;
}
#if value 1 - there are no available host for migrate VM, we need to return VM to the source host
elseif($ret -eq 1)
{
# PRO Tips failed (in the Migrate methods)
Logging "All tries for migration VM finished with problems.";
$VMError.Add($item.VM.ID);
# $RemoveJobs.Add($item)
$Message = "Set Available For Placement flag to True for host: " + $SourceHost.Name;
Logging $Message;
$status = Set-SCVMHost -VMHost $SourceHost -AvailableForPlacement $true;
$Error.Clear();

MigrateVM $item.VM $item.VM.VMHost;
# Set Available For Placement flag to False for host: " + $SourceHost.Name;
$Message = "Set Available For Placement flag to False for host: " + $SourceHost.Name;
Logging $Message;
$status = Set-SCVMHost -VMHost $SourceHost -AvailableForPlacement $false;
$Error.Clear();
}
# error happaned
elseif($ret -eq 2)
{
Logging "The error happaned in MigrateVM.";
$global:ProTipStatus = "Failed";
$RemoveJobs.Add($item);
$Error.Clear();
}
# need to wait, we can't start a new one Live or Live VSM migration on the source host
elseif($ret -eq 3)
{
Sleep 1;
}
}
# Job finished with error
elseif($item.job.Status -ieq $STATE_ERROR)
{
$Message = "Job finished with error, VM: " + $item.VM.Name;
Logging $Message;
if($item.Vm.Status -ine $STATE_RUNNING)
{
# Repair VM " + $item.VM + " after problem in process migration
$Message = "Repair VM " + $item.VM.Name + " after problem in process migration. The last migraion finished with error too.";
Logging $Message;
Repair-SCVirtualMachine -VM $item.VM -Undo;
# The most popular situation when we can't repair VM and we need to ignore this VM anymore
if($Error.Count -ne 0)
{
$global:ProTipStatus = "Failed";
EventLogErrorNoProTip 150;
$VMError.Add($item.VM.ID);
$RemoveJobs.Add($item);
continue;
}
}
# Try to migrate from $objHost = $SourceHost to the newest host
$ret = MigrateVM $item.VM $SourceHost;

# Check return value,
#if value 0 - migration started successfully
if($ret -eq 0)
{
Logging "Migration started successfully";
continue;
}
#if value 1 - there are no available host for migrate VM, we need to return VM to the source host
elseif($ret -eq 1)
{
# PRO Tips failed (in the Migrate methods)
Logging "All tries for migration VM finished with problems.";
$VMError.Add($item.VM.ID);
$RemoveJobs.Add($item);
$Error.Clear();

# End of critical section
if($global:MutexGroup -ne $null)
{
Logging "End of critical section for Group";
$global:MutexGroup.ReleaseMutex();
$global:MutexGroup = $null;
}
}
# error happaned
elseif($ret -eq 2)
{
Logging "The error happaned in MigrateVM.";
$global:ProTipStatus = "Failed";
$RemoveJobs.Add($item);
$Error.Clear();
}
# need to wait, we can't start a new one Live or Live VSM migration on the source host
elseif($ret -eq 3)
{
Sleep 1;
}
}
# Job is running
elseif($item.job.Status -ieq $STATE_RUNNING)
{
$Message = "Job skipped with state: " + $item.job.Status;
Logging $Message;
}
# Unknown type of job, ignored it, because we don't know what should we do.
else
{
$Message = "Unknown type of job: " + $item.job.Status + ". It would be ignored";
Logging $Message;
$VMError.Add($item.VM);
$global:ProTipStatus = "Failed";
$RemoveJobs.Add($item);
}
}
# Remove jobs which we don't need to check anymore (Finished success, Unknows, and Canceled by the User
foreach($jobrem in $RemoveJobs)
{
$Jobs.Remove($jobrem);
}

}

# method: Main
function Main
{
#LoggingAnotherFile "1";
$hostName = $HostName;
$serverName = $VMMServer;
$protip = $PROTipID;

#$hostName = "tx150s6.HD6205.local";
#$serverName = "DC01.HD6205.local";
#$VMMServer = $serverName;
#$protip = "ddb4ad21-3d61-4154-a3c2-fbb772568b92";
#$eventId = 9;
#$eventSourceName = "FujitsuServerPROPack";
#$flagRecovery = 2;
#$debugging = "yes";

if($Params -ne $null)
{
$SubParams = $Params.Trim();
$SubParams = $SubParams.Split(':');
$flagRecovery = $SubParams[0].Trim();
$debugging = $SubParams[1].Trim();
}
$Error.Clear();

try
{
#LoggingAnotherFile "2";
# 0. Import Module if it need
if((Get-Module -Name "virtualmachinemanager") -eq $null)
{
Import-Module "virtualmachinemanager"
}


[bool]$wasCreatedConfig = $true;
[bool]$requestInitialOwnershipConfig = $true;
$MutexGlobalCreateConfig = $false;

while($MutexGlobalCreateConfig -ne $true)
{
try
{
#LoggingAnotherFile "Create global mutex for read log file";
$global:MutexGlobalConfig = new-object -TypeName System.Threading.Mutex($requestInitialOwnershipConfig, "FujitsuPRIMERGYPROPackv5.2Config",[ref]$wasCreatedConfig);
if((EventLogError 121) -eq 1) { return 121; }
if (!($requestInitialOwnershipConfig -and $wasCreatedConfig))
{
#LoggingAnotherFile "Wait global mutex";
$Result = $global:MutexGlobalConfig.WaitOne();
$Error.Clear();
#LoggingAnotherFile "End of wating global mutex";
}
$MutexGlobalCreateConfig = $true;
}
catch
{
#LoggingAnotherFile "FAILED MutexGlobalCreate";
$MutexGlobalCreateConfig = $false;
}
}
# Initialize config log
InitializeConfigLog;

# End of critical section
if($global:MutexGlobalConfig -ne $null)
{
#LoggingAnotherFile "End of critical section of global mutex";
$global:MutexGlobalConfig.ReleaseMutex();
$global:MutexGlobalConfig = $null;
}


[bool]$wasCreatedLog = $true;
[bool]$requestInitialOwnershipLog = $true;
$MutexGlobalCreateLog = $false;

while($MutexGlobalCreateLog -ne $true)
{
try
{
#LoggingAnotherFile "Create global mutex for read log file";
$global:MutexGlobalLog = new-object -TypeName System.Threading.Mutex($requestInitialOwnershipLog, "FujitsuPRIMERGYPROPackv5.2Log",[ref]$wasCreatedLog);
if((EventLogError 122) -eq 1) { return 122; }
if (!($requestInitialOwnershipLog -and $wasCreatedLog))
{
#LoggingAnotherFile "Wait global mutex";
$Result = $global:MutexGlobalLog.WaitOne();
$Error.Clear();
#LoggingAnotherFile "End of wating global mutex";
}
$MutexGlobalCreateLog = $true;
}
catch
{
#LoggingAnotherFile "FAILED MutexGlobalCreate";
$MutexGlobalCreateLog = $false;
}
}
# Initialize log file
InitializeLogToFile $debugging;

# End of critical section
if($global:MutexGlobalLog -ne $null)
{
#LoggingAnotherFile "End of critical section of global mutex";
$global:MutexGlobalLog.ReleaseMutex();
$global:MutexGlobalLog = $null;
}




# Logging input parameters
$Message = "Recovery script started. Host name: " + $hostName +
", Server name: " + $serverName +
", PRO Tip: " + $protip +
", Recovery flag: " + $flagRecovery +
", Debugging flag from MP: " + $debugging +
", Logging enabled: " + $global:IsLogEnabled;
Logging $Message;

# Set PROTip state to Running
Logging "Set PROTip state to Running";
$Error.Clear();
Set-SCPROTip -PROTipId $protip -TipStatus Running;
if((EventLogError 101) -eq 1) { return 0; }

if($global:MigrationMaximumVMs -le 0)
{
$Message = "MigrationMaximumVms set 1";
Logging $Message;
$global:MigrationMaximumVMs = 1;
}
# Check Recovery flag
Logging "Check Recovery flag"
if(($flagRecovery -ne "1") -and ($flagRecovery -ne "2"))
{
EventLog Error 102 "Invalid Recovery flag. Recovery flag value must be 1 or 2";
Set-SCPROTip -PROTipId $protip -TipStatus Failed;
return 0;
}

# Get VMM host object
Logging "Get VMM host object";
$objHost = Get-SCVMHost -computername $hostName -vmmserver $VMMServer;
if((EventLogError 103) -eq 1) { return 0; }
if($objHost -eq $null)
{
$Message = "VMM host: " + $hostName + " is not available.";
EventLog Error 103 $Message "Failed";
return 0;
}

$isHostCluster = $true;
if($objHost.HostCluster -eq $null )
{
$isHostCluster = $false;
}
else
{
$ClusterId = $objHost.HostCluster.ID;
}

# Set flag Available For Placement in False for host:
$Message = "Set flag Available For Placement to False for host: " + $objHost.Name;
Logging $Message;
$status = Set-SCVMHost -VMHost $objHost -AvailableForPlacement $false;
if((EventLogError 104) -eq 1) { return 0; }
if($status.AvailableForPlacement -ne $false)
{
$Message = "Can't modify property 'Available for placement' for host: " + $objHost.Name;
EventLog Error 105 $Message "Failed";
return 0;
}

# Recovery flag is 2
Logging "Recovery flag is 2";
if($flagRecovery -eq "2")
{
# Entred into migration section. Recovery flag is :
$Message = "Entered into migration section. Recovery flag is : " + $flagRecovery;
Logging $Message;
$Error.Clear();

# Migration cycle
$VMtotal = 0;
while(1)
{
# Beginning of critical section
Logging "Beginning of critical section";
$wasCreated = $true;
$requestInitialOwnership = $true;

$MutexGroupCreate = $false;
while($MutexGroupCreate -ne $true)
{
try
{
Logging "Create mutex group";
$MutexGroupName = "FujitsuPRIMERGYPROPackv5.2" + $objHost.VMHostGroup.Name;
$global:MutexGroup = new-object -TypeName System.Threading.Mutex($requestInitialOwnership, $MutexGroupName,[ref]$wasCreated);
if($Error.Count -ne 0)
{
$Error.Clear();
continue;
}
if (!($requestInitialOwnership -and $wasCreated))
{
Logging "Waiting for the host group mutex";
$Result = $global:MutexGroup.WaitOne();
$Error.Clear();
Logging "End of wating host group mutex";
}
$MutexGroupCreate = $true;
}
catch
{
#LoggingAnotherFile "FAILED MutexGroupCreate";
$MutexGroupCreate = $false;
}
}


# Get VMs for migration
$VMs = GetVM $objHost;
# Start migration if VMs are not empty
if(($VMs.Count -gt 0)-and($global:MigrationMaximumVMs -gt $Jobs.Count))
{
$VMtotal++;
MigrateVM $VMs[0] $objHost;
}
# Check jobs state
CheckJobsState $objHost;

# Nothing happened, need waiting
if($JobCount -eq $Jobs.Count)
{ Logging "New job did not appear so expect 1 second";
Sleep 1;
}
$JobCount = $Jobs.Count;

# All Vms were migrated
if(($VMs.Count -eq 0) -and ($Jobs.Count -eq 0))
{ break; }
}#while(1) - search VM for migrate

# There are no VMs for migration
if($VMtotal -eq 0)
{
EventLogInformation 117 "There are no VMs for migration.";
}
# Not all VMs were moved successfully
if($global:ProTipStatus -ieq "Failed")
{
Logging "Not all VMs were moved successfully"
$global:ProTipStatus = "Failed";
}
# All VMs were moved successfully
else
{
Logging "All VMs were moved successfully"
}

} # if migrate

# Set PROTip state to " + $ProTipStatus
$Message = "Set PROTip state to " + $global:ProTipStatus;
Logging $Message;
Set-SCPROTip -PROTipId $protip -TipStatus $global:ProTipStatus;
if((EventLogError 118) -eq 1) { return 0; }
} #try
catch
{
# Critical section
if((EventLogError 119) -eq 1) { return 0; }
}
finally
{
# End of critical section
if($global:MutexGlobalLog -ne $null)
{
Logging "End of critical section for Global";
$global:MutexGlobalLog.ReleaseMutex();
$global:MutexGlobalLog = $null;
}
if($global:MutexGlobalConfig -ne $null)
{
#LoggingAnotherFile "End of critical section of global mutex";
$global:MutexGlobalConfig.ReleaseMutex();
$global:MutexGlobalConfig = $null;
}
if($global:MutexGroup -ne $null)
{
Logging "End of critical section for Group";
$global:MutexGroup.ReleaseMutex();
$global:MutexGroup = $null;
}
}
# Recovery script finished
Logging "Recovery script finished";
return 0;
}
Main;
</Script></ScriptBody>
<TimeoutSeconds>6000</TimeoutSeconds>
</WriteAction>
</MemberModules>
<Composition>
<Node ID="RecoveryAction"/>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>Windows!Microsoft.Windows.SerializedObjectData</OutputType>
<InputType>System!System.BaseData</InputType>
</WriteActionModuleType>