BMC Power Management Write Action Module Type

Fujitsu.Servers.PRIMERGY.OutOfBand.BmcPowerManagementWriteActionModuleType (WriteActionModuleType)

Element properties:

TypeWriteActionModuleType
IsolationAny
AccessibilityInternal
RunAsDefault
InputTypeSystem.BaseData

Member Modules:

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

Overrideable Parameters:

IDParameterTypeSelectorDisplay NameDescription
TimeoutSecondsint$Config/TimeoutSeconds$Timeout SecondsTimeout in Seconds for the Power Management Action
VerboseOutputbool$Config/VerboseOutput$Verbose OutputDisplay Verbose Output from task.

Source Code:

<WriteActionModuleType ID="Fujitsu.Servers.PRIMERGY.OutOfBand.BmcPowerManagementWriteActionModuleType" Accessibility="Internal" Batching="false">
<Configuration>
<IncludeSchemaTypes>
<SchemaType>Windows!Microsoft.Windows.PowerShellSchema</SchemaType>
</IncludeSchemaTypes>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="UserName" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="Password" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="IP" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="Port" type="xsd:integer"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="ServerAction" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="SkipCACheck" type="xsd:boolean"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="SkipCNCheck" type="xsd:boolean"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="0" name="UseRedfishSession" type="xsd:boolean" default="false"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="0" name="VerboseOutput" type="xsd:boolean" default="false"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="TimeoutSeconds" type="xsd:integer"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="0" name="StrictErrorHandling" type="xsd:boolean"/>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="TimeoutSeconds" Selector="$Config/TimeoutSeconds$" ParameterType="int"/>
<!--
<OverrideableParameter ID="UseRedfishSession" Selector="$Config/UseRedfishSession$" ParameterType="bool" />
-->
<OverrideableParameter ID="VerboseOutput" Selector="$Config/VerboseOutput$" ParameterType="bool"/>
</OverrideableParameters>
<ModuleImplementation Isolation="Any">
<Composite>
<MemberModules>
<WriteAction ID="WA" TypeID="Windows!Microsoft.Windows.PowerShellWriteAction">
<ScriptName>PowerManagementBmc.ps1</ScriptName>
<ScriptBody><Script>
##################################################################################
# #
# NOTICE #
# #
# COPYRIGHT 2015 - 2018 FUJITSU LIMITED #
# ALL RIGHTS RESERVED #
# #
# This computer program is CONFIDENTIAL and contains TRADE SECRETS of #
# FUJITSU LIMITED. The receipt or possession of this program does #
# not convey any rights to reproduce or disclose its contents, or to #
# manufacture, use, or sell anything that it may describe, in whole or #
# in part, without the specific written consent of FUJITSU LIMITED. #
# Any reproduction of this program without the express written consent #
# of FUJITSU LIMITED is a violation of the copyright laws and may #
# subject you to civil liability and criminal prosecution. #
# #
##################################################################################

#
# This script performs Out-of-Band Power Management for Fujitsu PRIMERGY Servers via the integrated Remote Management Controller (iRMC)
#
param(
[string]$UserName,
[string]$Password,
[string]$IP,
[int] $Port,
[string]$ServerAction,
[string]$SkipCACheck = "False",
[string]$SkipCNCheck = "False",
[string]$UseRedfishSession = "False",
[string]$VerboseOutput = "False",
[int] $TimeoutSeconds = 60
)

[IPAddress]$IPAddress = $null
if ([system.net.IPAddress]::tryparse($IP,[ref]$IPAddress)) {
if ($IPAddress.AddressFamily.ToString() -eq "Internetwork") {
$HostURL = "https://" +$IPAddress.ToString() +":$($Port)"
} elseif ($IPAddress.AddressFamily.ToString() -eq "Internetworkv6") {
$HostURL = "https://[" +$IPAddress.ToString() +"]:$($Port)"
}
} else {
Write-Warning ("Fujitsu Out-Of-Band Server Power Management ($($ServerAction)): Invalid IP Address '$($IP)'")
Exit -1
}

Function DebugOut
{
Param (
[string] $Text
)
if ($Text -and $Text.Length) {
$DateTime = Get-Date -format "yyyy-MM-dd HH:mm:ss"
if ($VerboseOutput -eq $True) {
Write-Host "[$($DateTime)] $($Text)"
} else {
Write-Verbose "[$($DateTime)] $($Text)"
}
}
}

Function DebugWarn
{
Param (
[string] $Text
)
$DateTime = Get-Date -format "yyyy-MM-dd HH:mm:ss"
DebugOut "[$($DateTime)] WARNING: $($Text)"
}

Function DebugErr
{
Param (
[int] $ErrNo = 4711,
[string] $Text
)
$DateTime = Get-Date -format "yyyy-MM-dd HH:mm:ss"
DebugOut "[$($DateTime)] ERROR ($($ErrNo)): $($Text)"
}

# we need to make multiple authenticated HTTP(S) requests...
[System.Net.NetworkCredential]$NetworkCredential = New-Object System.Net.NetworkCredential ($UserName, $Password)
[System.Net.ServicePointManager]::DefaultConnectionLimit = 1000
[System.Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls

[int]$DEFAULT_REQUEST_TIMEOUT = 30 # seconds
[int]$DEFAULT_RETRY_INCREMENT = 10 # seconds
[int]$MAX_REQUEST_RETRIES = 2

# Subset of possible HTTP error codes
[int]$HTTP_RC_CONTINUE = 100
[int]$HTTP_RC_OK = 200
[int]$HTTP_RC_CREATED = 201
[int]$HTTP_RC_ACCEPTED = 202
[int]$HTTP_RC_NO_CONTENT = 204
[int]$HTTP_RC_RESET_CONTENT = 205
[int]$HTTP_RC_PARTIAL_CONTENT = 206

[int]$HTTP_RC_MULTIPLE_CHOICES = 300
[int]$HTTP_RC_MOVED_PERMANENTLY = 301
[int]$HTTP_RC_MOVED_TEMPORARILY = 302
[int]$HTTP_RC_NOT_MODIFIED = 304

[int]$HTTP_RC_BAD_REQUEST = 400
[int]$HTTP_RC_UNAUTHORIZED = 401
[int]$HTTP_RC_FORBIDDEN = 403
[int]$HTTP_RC_NOT_FOUND = 404
[int]$HTTP_RC_METHOD_NOT_ALLOWED = 405
[int]$HTTP_RC_NOT_ACCEPTABLE = 406
[int]$HTTP_RC_REQ_TIMEOUT = 408

[int]$HTTP_RC_SERVER_ERROR = 500
[int]$HTTP_RC_NOT_IMPLEMENTED = 501
[int]$HTTP_RC_SERVICE_UNAVAILABLE = 503

[bool]$script:SSL_CA_ERROR = $False
[bool]$script:SSL_CN_ERROR = $False
[bool]$script:SSL_NO_CERT_ERROR = $False

[bool]$script:iRMCDetected = $False
[string]$script:WebServer = ""
[System.Net.HttpStatusCode]$script:httpStatusCode = [System.Net.HttpStatusCode]::OK


$SslCertificateValidator =
{
Param (
[System.Object] $obj,
[System.Security.Cryptography.X509Certificates.X509Certificate] $certificate,
[System.Security.Cryptography.X509Certificates.X509Chain] $chain,
[System.Net.Security.SslPolicyErrors] $errors
)

if ($errors -eq [System.Net.Security.SslPolicyErrors]::None) {
return $True
}

if (($errors -band [System.Net.Security.SslPolicyErrors]::RemoteCertificateNameMismatch) -and ($SkipCNCheck -eq $False)) {
return $False
}

if (($errors -band [System.Net.Security.SslPolicyErrors]::RemoteCertificateChainErrors) -and ($SkipCACheck -eq $False)) {
return $False
}

# No cert provided
if ($errors -band [System.Net.Security.SslPolicyErrors]::RemoteCertificateNotAvailable) {
return $False
}

# All checks passed
return $True
}

# Will return $Null on error
# Slightly stripped down version
Function DoWebRequest(
[String]$url,
[string]$Method = "GET",
[string]$AuthType = "Basic",
[System.Net.NetworkCredential]$Credentials = $NetworkCredential ,
[String]$RequestData = $Null,
[int] $RequestTimeout = $DEFAULT_REQUEST_TIMEOUT,
[int] $MaxRetries = $MAX_REQUEST_RETRIES,

[string]$ContentType = "application/json; charset=UTF-8", # default for Redfish
[string]$XAuthData = $Null,
[string]$Etag = $Null
)
{
#Write-Verbose "$($Method) request to '$($url)' Timeout=$($RequestTimeout) ..."
#if ( ![String]::IsNullOrEmpty($RequestData) ) {
# Write-Verbose "Request='$($RequestData)'"
#}

[bool]$ToggleProxy = $False
if ($MaxRetries -gt $MAX_REQUEST_RETRIES) { $MaxRetries = $MAX_REQUEST_RETRIES }
[int]$retries = 0;
for ($retries = 0; $retries -lt $MaxRetries; $retries++) {
try {
[string]$errorMsg = $Null

$script:SSL_CN_ERROR = $False
$script:SSL_CA_ERROR = $False
$script:SSL_NO_CERT_ERROR = $False

$webRequest = [System.Net.WebRequest]::Create($url)
if ($Credentials -ne $Null) {
if ($AuthType -eq "Basic") {
# Do not wait for the 401 response, send the credentials with the initial request
$AuthData = [Convert]::ToBase64String([Text.Encoding]::Default.GetBytes($Credentials.UserName + ':' + $Credentials.Password));
$webRequest.Headers.Add('Authorization', "Basic $AuthData")

$webRequest.Credentials = $Null
$webRequest.PreAuthenticate = $False
# $webRequest.UseDefaultCredentials = $False
$webRequest.KeepAlive = $False # make sure the connection is not re-used
} else {
$webRequest.Credentials = $Credentials
$webRequest.PreAuthenticate = $True
}
} else {
$webRequest.Credentials = $Null
$webRequest.PreAuthenticate = $False
}
# $webRequest.PreAuthenticate = $False
# $webRequest.UseDefaultCredentials = $false

$webRequest.Timeout = ($RequestTimeout *1000)
$webRequest.ReadWriteTimeout = ($RequestTimeout *1000)
$webRequest.Method = $Method
# $webRequest.Accept = "application/json"
$webRequest.Accept = "*/*"
$webRequest.KeepAlive = $False # make sure the connection is not re-used
$webRequest.AllowAutoRedirect = $False # Do not follow redirects

$webRequest.Headers.Add("OData-Version", "4.0")

# Add only if there is no regular credential
if ($XAuthData.Length -gt 0) {
$webRequest.Headers.Add("X-Auth-Token", $XAuthData)
}

# Add only if present
if ($Etag.Length -gt 0) {
$webRequest.Headers.Add("If-Match", $Etag)
}

# Discovery and Monitoring workflow scripts typically run without a proxy configured.
# Performance Collection workflow scripts typically run with proxy configuration
$Proxy = $WebRequest.Proxy
if ($Proxy) {
$ProxyBypassed = $Proxy.IsBypassed($url)
if ($ProxyBypassed) {
Write-Verbose "$IP - '$($url)' No Proxy (direct connection) will be used"
} else {
$ProxyAddress = $Proxy.GetProxy($url).AbsoluteUri
Write-Verbose "$IP - '$($url)' Proxy '$($ProxyAddress)' will be used"
}
} else {
Write-Verbose "$IP - '$($url)' No Proxy object (direct connection)"
}

if (!$ProxyBypassed -and $ToggleProxy ) {
DebugOut "$IP - '$($url)' (Re)Trying without Proxy..."
$webRequest.Proxy = $Null
$ToggleProxy = $False
}

try {
$webRequest.ServicePoint.ConnectionLimit = 128
$webRequest.ServicePoint.ConnectionLeaseTimeout = 0 # Close Connection after servicing a request
$webRequest.ServicePoint.MaxIdleTime = 1 # in MilliSeconds, close connection afterwards
$webRequest.ServerCertificateValidationCallback = $SslCertificateValidator

# Write-Host "$IP - '$url' HASH=$($webRequest.ServicePoint.GetHashCode()) ConnectionLimit=$($webRequest.ServicePoint.ConnectionLimit)"
} catch {
Write-Warning "$IP - '$url' - Could not set extended config Exception=$_"
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = $SslCertificateValidator
}

if ($RequestData.Length -gt 0) {
$webRequest.ContentType = $ContentType

[bool]$bSendError = $False
[System.Timespan]$reqTime = Measure-Command {
try {
$buffer = [System.Text.Encoding]::UTF8.GetBytes($RequestData)
$webRequest.ContentLength = $buffer.Length;
$requestStream = $webRequest.GetRequestStream()
if ($requestStream) {
$requestStream.Write($buffer, 0, $buffer.Length)
$requestStream.Flush()
$requestStream.Close()
}
} catch [System.Net.WebException] {
$errorMsg = $_.Exception.Message
$stackTrace = $_.Exception.StackTrace
$innerException = $_.Exception.InnerException
$bSendError = $True
} catch {
Write-Warning "$IP - '$url' could not send request data. Timeout was $($RequestTimeout) seconds. Exception=$_"
$bSendError = $True
}
}

if ($bSendError) {
# If the connection gets closed during early send we retry
# this is typically within a few seconds, otherwise the configured timeout would have expired
if ($reqTime -ne $Null -and [int]$reqTime.TotalSeconds -lt 5) {
[int]$retryDelay = (($retries +1) * $DEFAULT_RETRY_INCREMENT)
if ($errorMsg -ne $Null) { Write-Warning "$IP - $($Method) '$url' could not send request data within $($reqTime.TotalSeconds) seconds - will retry in $retryDelay seconds ($errorMsg)"}
else { Write-Warning "$IP - $($Method) '$url' could not send request data within $($reqTime.TotalSeconds) seconds - will retry in $retryDelay seconds (no details available)"}
if ($innerException -ne $Null) { Write-Warning "InnerException:`r`n$innerException" }
if ($stackTrace -ne $Null ) { Write-Warning "Stack Trace:`r`n$stackTrace" }
Start-Sleep -Seconds $retryDelay
continue
} else {
Write-Warning "$IP - $($Method) '$url' could not send request data within $($reqTime.TotalSeconds) seconds. Timeout was $($RequestTimeout) seconds"
return
}
}
}

[System.Net.HttpWebResponse] $webResponse = $Null

[System.Timespan]$resTime = Measure-Command {

try {
$webResponse= $webRequest.GetResponse()
} catch [System.Net.WebException] {
$webResponse = $_.Exception.Response
$errorMsg = $_.Exception.Message
$stackTrace = $_.Exception.StackTrace
$innerException = $_.Exception.InnerException
# Write-Warning "$IP - '$url' ... Web Exception: $_"
} catch {
$webResponse = $Null
# Write-Warning "$IP - '$url' ... Generic Exception: $_"
}
}

# No longer needed ...
$webRequest = $Null

if ($webResponse -ne $Null) {
$script:Location = $webResponse.GetResponseHeader("Location") # $webResponse.Headers.Get("Location")
$script:WebServer = $webResponse.GetResponseHeader("Server") # $webResponse.Headers.Get("Server")
$script:httpStatusCode = $($webResponse.StatusCode.value__)

[System.Net.WebHeaderCollection]$Headers = $webResponse.Headers
if ($Headers) {
[string]$Header = $Headers.Get("X-Auth-Token")
if ($Header.Length -gt 0) {
$script:AuthData = $Header
}

# POST/PUT etc. return created object in 'Location' header, also redirects
if ($Method -ne "GET") {
$Header = $Headers.Get("Location")
if ($Header.Length -gt 0) {
$script:Location = $Header
}
}
}

if ( $script:iRMCDetected -eq $False ){
if ($script:WebServer -match "iRMC") {
$script:iRMCDetected = $True
}
}
$responseStream = New-Object System.IO.StreamReader($webResponse.GetResponseStream())
$result = $responseStream.ReadToEnd()
$responseStream.Close()
$webResponse.Close()

$responseStream = $Null
$webResponse = $Null

switch ( [int]$script:httpStatusCode ) {
$HTTP_RC_OK { # 200
DebugOut "$IP - $($Method) '$url' request handled within $($resTime.TotalSeconds) seconds..."
return $result
}
$HTTP_RC_CREATED { # 201
DebugOut "$IP - $($Method) '$url' resource created within $($resTime.TotalSeconds) seconds (201)..."
return $result
}
$HTTP_RC_ACCEPTED { # 202
DebugOut "$IP - $($Method) '$url' request accepted within $($resTime.TotalSeconds) seconds (202)..."
return $result
}
$HTTP_RC_NO_CONTENT { # 204
DebugOut "$IP - $($Method) '$url' request handled within $($resTime.TotalSeconds) seconds (204 no content)..."
return $result
}
$HTTP_RC_MOVED_PERMANENTLY { # 301
DebugOut "$IP - '$url' permanently redirected to '$($script:Location)' (301)"
if ($script:Location -match "login") {
$script:httpStatusCode = [System.Net.HttpStatusCode]::Unauthorized
}
return
}
$HTTP_RC_MOVED_TEMPORARILY { # 302
DebugOut "$IP - '$url' temporary redirected to '$($script:Location)' (302)"
if ($script:Location -match "login") {
$script:httpStatusCode = [System.Net.HttpStatusCode]::Unauthorized
}
return
}
$HTTP_RC_UNAUTHORIZED { # 401
Write-Warning "$IP - $($Method) '$url' Unauthorized (401)..."
return
}
$HTTP_RC_FORBIDDEN { # 403
Write-Warning "$IP - $($Method) '$url' No permission (403)..."
return
}
$HTTP_RC_NOT_FOUND { # 404
return
}
$HTTP_RC_SERVER_ERROR { # 500
return
}
$HTTP_RC_NOT_IMPLEMENTED { # 501
return
}
}

# If we get here some other error occurred (e.g. 503 Service unavailable)
# If this was the first attempt and a proxy was active (e.g. performance collection workflow script), try again without proxy
if (!$ProxyBypassed -and $retries -eq 0) {
DebugOut "$IP - $($Method) '$url' iRMC reported HTTP Status Code ($([int]$script:httpStatusCode) / $($script:httpStatusCode)) - will retry without proxy"
$ToggleProxy = $True
continue
}

if ($retries -lt ($MAX_REQUEST_RETRIES)) {
[int]$retryDelay = (($retries +1) * $DEFAULT_RETRY_INCREMENT)
DebugOut "$IP - $($Method) '$url' iRMC reported HTTP Status Code (($([int]$script:httpStatusCode) / $($script:httpStatusCode)) - will retry in $($retryDelay) seconds"
Start-Sleep -Seconds $retryDelay
continue
} else {
DebugOut "$IP - $($Method) '$url' - iRMC reported final HTTP Status Code (($([int]$script:httpStatusCode) / $($script:httpStatusCode)), giving up after retries"
return
}

} else {

# Check for SSL related errors
if ($script:SSL_CN_ERROR -eq $True) {
Write-Warning "$IP - '$url' Certificate Name (CN) Mismatch ..."
return
} elseif ($script:SSL_CA_ERROR -eq $True) {
Write-Warning "$IP - '$url' Certificate Authority (CA) or Chain Error ..."
return
} elseif ($script:SSL_NO_CERT_ERROR -eq $True) {
Write-Warning "$IP - '$url' No Certificate present ..."
return
}

# no response (object), check for the timeout value.
# If the connection gets closed during early send/receive,
# this is typically within a few seconds, otherwise the configured timeout would have expired
if ($resTime -ne $Null -and [int]$resTime.TotalSeconds -lt 5) {
[int]$retryDelay = (($retries +1) * $DEFAULT_RETRY_INCREMENT)
if ($retries -ne 0) {
if ($errorMsg -ne $Null) { Write-Warning "$IP - $($Method) '$url' no response / connection closed within $($resTime.TotalSeconds) seconds - will retry in $retryDelay seconds ($errorMsg)"}
else { Write-Warning "$IP - $($Method) '$url' no response / connection closed within $($resTime.TotalSeconds) seconds - will retry in $retryDelay seconds (no details available)"}
if ($innerException -ne $Null) { Write-Warning "InnerException:`r`n$innerException" }
if ($stackTrace -ne $Null ) { Write-Warning "Stack Trace:`r`n$stackTrace" }
}
Start-Sleep -Seconds $retryDelay
} else {
Write-Host "$IP - $($Method) '$url' no response within $($resTime.TotalSeconds) seconds. Timeout was $($RequestTimeout) seconds"
return
}
}
} catch {
[int]$retryDelay = (($retries +1) * $DEFAULT_RETRY_INCREMENT)
Write-Warning "$IP - $($Method) '$url' Generic Exception. will retry in $retryDelay seconds. Exception=$_"
Start-Sleep -Seconds $retryDelay
}
}
Write-Host "$IP - $($Method) '$url' no response after $retries retries (last error: $errorMsg)"
}



Function CloseRedfishSession
{
# Close Redfish session if we opened one
if ( ![String]::IsNullOrEmpty($script:RedfishSession) ) {
try {
DebugOut "$IP - Delete Redfish session '$($script:RedfishSession)'"
(doWebRequest -url "$hostURL$($script:RedfishSession)" -Method "DELETE" -XAuthData $script:AuthData) | Out-Null
} catch {}
}
}

Function Redfish_Main {

DebugOut "$IP - ServerAction='$($ServerAction)' (Redfish Version)"

[int]$RequestTimeout = $DEFAULT_REQUEST_TIMEOUT
if ($TimeoutSeconds -lt $DEFAULT_REQUEST_TIMEOUT){
$RequestTimeout = $TimeoutSeconds
}

$ServiceRoot = $Null
DebugOut "$IP - Get Redfish Root Service Information..."
try {
# ServiceRoot is available unauthenticated
# Note: According to the specification the ServiceRoot should be available unauthenticated;
# but older firmware versions (e.g. iRMC S4 with firmware 8.4x) do not support this or do not know this URL.
# In order to properly detect these systems (and abort), use the provided/available credentials
#$ServiceRoot = (doWebRequest -url "$hostURL/redfish/v1" -Method "GET" -Credentials $Null -XAuthData $Null) | ConvertFrom-JSON
$ServiceRoot = (doWebRequest -url "$hostURL/redfish/v1" -Method "GET" -Credentials $NetworkCredential -XAuthData $Null) | ConvertFrom-JSON
if ($ServiceRoot) {
DebugOut "$IP - Name='$($ServiceRoot.Name)' Redfish Version='$($ServiceRoot.RedfishVersion)' UUID='$($ServiceRoot.UUID)'"
if ($ServiceRoot.'@odata.etag' -eq $Null -or $ServiceRoot.'@odata.etag' -eq '') {
DebugOut "$IP - Seems to be an old Redfish instrumentation, giving up..."
return
}
} else {
# Since this Monitor runs for discovered instances, this is serious
DebugWarn "$IP - Could not get Service Root, giving up."
return
}
} catch {
DebugWarn "$IP - Error getting Service Root, Exception: $_"
return
}

try {

$script:RedfishSession = $Null
if ($UseRedfishSession -eq $True) {
DebugOut "$IP - try to create a new Redfish session..."
$SessionEntry = (doWebRequest -url "$hostURL$($ServiceRoot.Links.Sessions.'@odata.id')" -Credentials $Null -XAuthData $Null -Method "POST" -RequestData "{'UserName':'$($UserName)','Password':'$($Password)'}" ) | ConvertFrom-JSON

if (!$SessionEntry) {
Write-Warning "$IP - Could not create session"
return
}

if ($SessionEntry.Error) {
Write-Warning "$IP - ERROR creating session: ErrorCode='$($SessionEntry.Error.code)' Message='$($SessionEntry.Error.message)'"
return
}

if ($SessionEntry.'@odata.id' -ne '') {
#DebugOut "`tRedfish Session for '$($SessionEntry.UserName)' Id=$($SessionEntry.Id) '$($SessionEntry.'@odata.id')'"
DebugOut "`tRedfish Session Id=$($SessionEntry.Id) '$($SessionEntry.'@odata.id')'"
$script:RedfishSession = $SessionEntry.'@odata.id'
} else {
#DebugWarn "`tRedfish Session for '$($SessionEntry.UserName)' Id=$($SessionEntry.Id) - no link"
DebugWarn "`tRedfish Session for '$($SessionEntry.UserName)' Id=$($SessionEntry.Id) - no link"
}
}

DebugOut "$IP - Get System(s) Information ..."
$Systems = $Null
if ($ServiceRoot -and $ServiceRoot.Systems.'@odata.id') {
$Systems = (doWebRequest -url "$hostURL$($ServiceRoot.Systems.'@odata.id')" -Method "GET" -Credentials $NetworkCredential -XAuthData $script:AuthData) | ConvertFrom-JSON
if ($Systems -and $Systems.'[email protected]' -gt 0) {
if ($Systems.'[email protected]' -gt 1) {
DebugOut "$IP - has Information for $($Systems.'[email protected]') Systems ..."
}

for ($SystemIdx = 0; $SystemIdx -lt $Systems.'[email protected]'; $SystemIdx++) {
# Note: Modeling multiple systems under one IP Address is currently not planned
if ($Systems.'[email protected]' -gt 1) {
DebugOut "$IP - System $($SystemIdx) : Information..."
} else {
DebugOut "$IP - System Information..."
}

$SystemRoot = (doWebRequest -url "$hostURL$($Systems.Members[$SystemIdx].'@odata.id')" -Method "GET" -Credentials $NetworkCredential -XAuthData $script:AuthData) | ConvertFrom-JSON
if ($SystemRoot) {
# Get iRMC Firmware Version info
if ($SystemRoot.Oem.ts_fujitsu) {
$FirmwareInventory = $SystemRoot.Oem.ts_fujitsu.FirmwareInventory
if ($FirmwareInventory -ne $Null -and $FirmwareInventory.'@odata.id' -ne '') {
$Inventory = (doWebRequest -url "$hostURL$($FirmwareInventory.'@odata.id')" -Method "GET" -Credentials $NetworkCredential -XAuthData $script:AuthData) | ConvertFrom-JSON
if ($Inventory) {
DebugOut "$IP - iRMC Firmware='$($Inventory.BMCFirmware)' BuildDate='$($Inventory.BMCFirmwareBuildDate)' Running='$($Inventory.BMCFirmwareRunning)' SDR Version='$($Inventory.SDRRVersion)' SDRRId='$($Inventory.SDRRId)' BIOS='$($Inventory.SystemBIOS)'"
}
}
}

DebugOut "$IP - is a $($SystemRoot.Manufacturer) '$($SystemRoot.Model)' Description='$($SystemRoot.Description)' AssetTag='$($SystemRoot.AssetTag)' Serial='$($SystemRoot.SerialNumber)' PartNumber='$($SystemRoot.PartNumber)'"
DebugOut "$IP - System HostName='$($SystemRoot.HostName)' UUID='$($SystemRoot.UUID)' Indicator LED is '$($SystemRoot.IndicatorLED)'"
DebugOut "$IP - System Status: Health='$($SystemRoot.Status.Health)' State='$($SystemRoot.Status.State)' HealthRollup='$($SystemRoot.Status.HealthRollup)' PowerState='$($SystemRoot.PowerState)'"

Write-Host "$IP - Current System Power State is '$($SystemRoot.PowerState)'"

# We need to validate the action against the currently allowed ones.
# See ResetType in Resource.json (Note: No PowerCycle defined in Standard Redfish enum)
&lt;#
"ResetType": {
"type": "string",
"enum": [
"On",
"ForceOff",
"GracefulShutdown",
"GracefulRestart",
"ForceRestart",
"Nmi",
"ForceOn",
"PushPowerButton"
],
"enumDescriptions": {
"On": "Turn the system on.",
"ForceOff": "Turn the system off immediately (non-graceful) shutdown.",
"GracefulShutdown": "Perform a graceful system shutdown and power off.",
"GracefulRestart": "Perform a graceful system shutdown followed by a restart of the system.",
"ForceRestart": "Perform an immediate (non-graceful) shutdown, followed by a restart of the system.",
"Nmi": "Generate a Diagnostic Interrupt (usually an NMI on x86 systems) to cease normal operations, perform diagnostic actions and typically halt the system.",
"ForceOn": "Turn the system on immediately.",
"PushPowerButton": "Simulate the pressing of the physical power button on this system."
}

#&gt;


# PowerCycle is available only as OEM action, not as standard Redfish action
$OemResetAction = $SystemRoot.Actions.Oem.'http://ts.fujitsu.com/redfish-schemas/v1/FTSSchema.v1_0_0#FTSComputerSystem.Reset'
if ($OemResetAction) {
DebugOut "$IP - OEM Reset Action '$($OemResetAction.Title)' Target='$($OemResetAction.Target)' "
$tmpStr = "$IP - Allowable OEM System Reset Action(s): "
for ($i=0; $i -lt $OemResetAction.'[email protected]'.Count; $i++) {
if ($i -ne 0) {$tmpStr += ", " }
$tmpStr += "'$($OemResetAction.'[email protected]'[$i])'"
}
DebugOut $tmpStr

if ($ServerAction -eq 'PowerCycle') {
$ResetType = 'PowerCycle'
for ($i=0; $i -lt $OemResetAction.'[email protected]'.Count; $i++) {
if ($ResetType -eq $OemResetAction.'[email protected]'[$i]) {
$ret = doWebRequest -url "$hostURL$($OemResetAction.Target)" -Credentials $NetworkCredential -Method "POST" -ContentType "application/json" -RequestData "{'FTSResetType':'PowerCycle'}"
Write-Host "$IP - Success performing ServerAction='$($ServerAction)'`rDetails: $($ret)"

CloseRedfishSession
exit 0
}
}
# if we get here, the PowerCycle was not allowed in the current state
Write-Host "$IP - $($ServerAction) is not an allowed OEM System ResetAction in the current state`r$($tmpStr)"
CloseRedfishSession
exit -1
}
}

$ResetAction = $SystemRoot.Actions.'#ComputerSystem.Reset'
if ($ResetAction) {
DebugOut "$IP - Standard Reset Action '$($ResetAction.Title)' Target='$($ResetAction.Target)' "
$tmpStr = "$IP - Allowable System Reset Action(s): "
for ($i=0; $i -lt $ResetAction.'[email protected]'.Count; $i++) {
if ($i -ne 0) {$tmpStr += ", " }
$tmpStr += "'$($ResetAction.'[email protected]'[$i])'"
}
DebugOut $tmpStr
}

$ResetType = ""
switch ($ServerAction) {
'PowerOn' { $ResetType = "On" }
'PowerOff' { $ResetType = "ForceOff" }
'Reset' { $ResetType = "ForceRestart" }
'Shutdown' { $ResetType = "GracefulShutdown" }
'Reboot' { $ResetType = "GracefulRestart" }
default { Write-Warning "Invalid Server Action='$($ServerAction)'"; return; }
}

$ResetAction = $SystemRoot.Actions.'#ComputerSystem.Reset'
if ($ResetAction) {
for ($i=0; $i -lt $ResetAction.'[email protected]'.Count; $i++) {
if ($ResetType -eq $ResetAction.'[email protected]'[$i]) {
$ret = doWebRequest -url "$hostURL$($ResetAction.Target)" -Credentials $NetworkCredential -Method "POST" -ContentType "application/json" -RequestData "{'ResetType':'$($ResetType)'}"
Write-Host "$IP - Success performing ServerAction='$($ServerAction)'`rDetails: $($ret)"

CloseRedfishSession
exit 0
}
}
# if we get here, the ResetAction was not allowed in the current state
Write-Host "$IP - $($ServerAction) is not an allowed Standard System ResetAction in the current state`r$($tmpStr)"
CloseRedfishSession
exit -1
}

} else {
DebugOut "$IP - Could not get System Root"
CloseRedfishSession
return
}
}
}
}

if ($UseRedfishSession -eq $True){
DebugOut "$IP - Delete Redfish session '$($script:RedfishSession)'"
(doWebRequest -url "$hostURL$($script:RedfishSession)" -Method "DELETE" -XAuthData $script:AuthData) | Out-Null
}

} catch {
DebugErr $SCRIPT_EVENT_NUMBER "$IP - Failed to $($ServerAction) the server: Exception=$_"
return
}
}


Function Legacy_Main {

DebugOut "$IP - ServerAction='$($ServerAction)' (Legacy Version)"

$PowerOn = @"
&lt;?xml version="1.0" encoding="UTF-8" standalone="yes" ?&gt;
&lt;CMDSEQ&gt;
&lt;CMD Context="SCCI" OC="PowerOnCabinet" OE="0" OI="0" Type="SET"&gt;
&lt;STATUS&gt;0&lt;/STATUS&gt;
&lt;/CMD&gt;
&lt;/CMDSEQ&gt;
"@

$PowerOff = @"
&lt;?xml version="1.0" encoding="UTF-8" standalone="yes" ?&gt;
&lt;CMDSEQ&gt;
&lt;CMD Context="SCCI" OC="PowerOffCabinet" OE="0" OI="0" Type="SET"&gt;
&lt;STATUS&gt;0&lt;/STATUS&gt;
&lt;/CMD&gt;
&lt;/CMDSEQ&gt;
"@

$PowerCycle = @"
&lt;?xml version="1.0" encoding="UTF-8" standalone="yes" ?&gt;
&lt;CMDSEQ&gt;
&lt;CMD Context="SCCI" OC="PowerOffOnCabinet" OE="0" OI="0" Type="SET"&gt;
&lt;STATUS&gt;0&lt;/STATUS&gt;
&lt;/CMD&gt;
&lt;/CMDSEQ&gt;
"@

$ResetServer = @"
&lt;?xml version="1.0" encoding="UTF-8" standalone="yes" ?&gt;
&lt;CMDSEQ&gt;
&lt;CMD Context="SCCI" OC="ResetServer" OE="0" OI="0" Type="SET"&gt;
&lt;STATUS&gt;0&lt;/STATUS&gt;
&lt;/CMD&gt;
&lt;/CMDSEQ&gt;
"@

$ShutdownServer = @"
&lt;?xml version="1.0" encoding="UTF-8" standalone="yes" ?&gt;
&lt;CMDSEQ&gt;
&lt;CMD Context="SCCI" OC="RequestShutdownAndOff" OE="0" OI="0" Type="SET"&gt;
&lt;STATUS&gt;0&lt;/STATUS&gt;
&lt;/CMD&gt;
&lt;/CMDSEQ&gt;
"@

$RebootServer = @"
&lt;?xml version="1.0" encoding="UTF-8" standalone="yes" ?&gt;
&lt;CMDSEQ&gt;
&lt;CMD Context="SCCI" OC="RequestShutdownAndReset" OE="0" OI="0" Type="SET"&gt;
&lt;STATUS&gt;0&lt;/STATUS&gt;
&lt;/CMD&gt;
&lt;/CMDSEQ&gt;
"@

$RequestURL = $HostURL +"/config"

[int]$RequestTimeout = $DEFAULT_REQUEST_TIMEOUT
if ($TimeoutSeconds -lt $DEFAULT_REQUEST_TIMEOUT){
$RequestTimeout = $TimeoutSeconds
}

switch ($ServerAction) {
'PowerOn' { $ret = doWebRequest -url $RequestURL -Credentials $NetworkCredential -Method "POST" -ContentType "application/x-www-form-urlencoded" -RequestData $PowerOn -RequestTimeout $RequestTimeout }
'PowerOff' { $ret = doWebRequest -url $RequestURL -Credentials $NetworkCredential -Method "POST" -ContentType "application/x-www-form-urlencoded" -RequestData $PowerOff -RequestTimeout $RequestTimeout }
'PowerCycle' { $ret = doWebRequest -url $RequestURL -Credentials $NetworkCredential -Method "POST" -ContentType "application/x-www-form-urlencoded" -RequestData $PowerCycle -RequestTimeout $RequestTimeout }
'Reset' { $ret = doWebRequest -url $RequestURL -Credentials $NetworkCredential -Method "POST" -ContentType "application/x-www-form-urlencoded" -RequestData $ResetServer -RequestTimeout $RequestTimeout }
'Shutdown' { $ret = doWebRequest -url $RequestURL -Credentials $NetworkCredential -Method "POST" -ContentType "application/x-www-form-urlencoded" -RequestData $ShutdownServer -RequestTimeout $RequestTimeout }
'Reboot' { $ret = doWebRequest -url $RequestURL -Credentials $NetworkCredential -Method "POST" -ContentType "application/x-www-form-urlencoded" -RequestData $RebootServer -RequestTimeout $RequestTimeout }
default { Write-Host "Invalid Server Action='$($ServerAction)'"; exit -1 }
}

if ($ret -ne $Null) {
try {
[xml]$x = [xml]$ret
if ($x -ne $Null -and $x.HasChildNodes) {
if ($x.Status.Value -eq 0) {
Write-Host "Success`rDetails:`r$ret"
exit 0
} else {
Write-Warning "Failed to $($ServerAction) $IP (returned status is not OK)`rDetails:`r$ret"
}
} else {
Write-Warning "Failed`rThe returned response from the iRMC is not a valid XML document`rDetails:`r$ret"
}
} catch {
Write-Warning "Failed`rThe returned response from the iRMC is not a valid XML document`rDetails:`r$ret"
}
} else {
Write-Host -ForegroundColor Red "$IP - Failed to $($ServerAction) the server (no response)"
}
# Throw "Failed to $($ServerAction) $IP"
exit -1
}

Function Main {

DebugOut "$IP - Port=$Port ServerAction='$($ServerAction)' TimeoutSeconds=$($TimeoutSeconds)"
DebugOut "$IP - SkipCACheck=$($SkipCACheck) SkipCNCheck=$($SkipCNCheck) UseRedfishSession=$($UseRedfishSession)"

Redfish_Main

# If we get here Redfish failed / is not available
Legacy_Main
}

Main
</Script></ScriptBody>
<SnapIns/>
<Parameters>
<Parameter>
<Name>UserName</Name>
<Value>$Config/UserName$</Value>
</Parameter>
<Parameter>
<Name>Password</Name>
<Value>$Config/Password$</Value>
</Parameter>
<Parameter>
<Name>IP</Name>
<Value>$Config/IP$</Value>
</Parameter>
<Parameter>
<Name>Port</Name>
<Value>$Config/Port$</Value>
</Parameter>
<Parameter>
<Name>ServerAction</Name>
<Value>$Config/ServerAction$</Value>
</Parameter>
<Parameter>
<Name>TimeoutSeconds</Name>
<Value>$Config/TimeoutSeconds$</Value>
</Parameter>
<Parameter>
<Name>SkipCACheck</Name>
<Value>$Config/SkipCACheck$</Value>
</Parameter>
<Parameter>
<Name>SkipCNCheck</Name>
<Value>$Config/SkipCNCheck$</Value>
</Parameter>
<Parameter>
<Name>UseRedfishSession</Name>
<Value>$Config/UseRedfishSession$</Value>
</Parameter>
<Parameter>
<Name>VerboseOutput</Name>
<Value>$Config/VerboseOutput$</Value>
</Parameter>
</Parameters>
<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
<StrictErrorHandling>$Config/StrictErrorHandling$</StrictErrorHandling>
</WriteAction>
</MemberModules>
<Composition>
<Node ID="WA"/>
</Composition>
</Composite>
</ModuleImplementation>
<InputType>System!System.BaseData</InputType>
</WriteActionModuleType>