Retounen yon valè ki soti nan Powershell invoke-command bay ajan SQL sèvè

Lè m ap kreye pwòp metodoloji mwen pou jere sovgad sou plizyè sèvè MS-SQL, mwen te pase anpil tan etidye mekanis pou pase valè nan Powershell pandan apèl aleka, kidonk mwen ekri yon rapèl pou tèt mwen si li itil. bay yon lòt moun.

Se konsa, ann kòmanse ak yon script senp epi kouri li lokalman:

$exitcode = $args[0]
Write-Host 'Out to host.'
Write-Output 'Out to output.'
Write-Host ('ExitCode: ' + $exitcode)
Write-Output $exitcode
$host.SetShouldExit($exitcode)

Pou kouri scripts, mwen pral sèvi ak dosye CMD sa a, mwen pa pral mete li chak fwa:

@Echo OFF
PowerShell .TestOutput1.ps1 1
ECHO ERRORLEVEL=%ERRORLEVEL%

Sou ekran an nou pral wè bagay sa yo:

Out to host.
Out to output.
ExitCode: 1
1
ERRORLEVEL=1


Koulye a, ann kouri menm script la atravè WSMAN (adistans):

Invoke-Command -ComputerName . -ScriptBlock { &'D:sqlagentTestOutput1.ps1' $args[0] } -ArgumentList $args[0]

Men rezilta a:

Out to host.
Out to output.
ExitCode: 2
2
ERRORLEVEL=0

Gwo, Errorlevel te disparèt yon kote, men nou bezwen jwenn valè a nan script la! Ann eseye konsepsyon sa a:

$res=Invoke-Command -ComputerName . -ScriptBlock { &'D:sqlagentTestOutput1.ps1' $args[0] } -ArgumentList $args[0]

Sa a se menm plis enteresan. Mesaj la nan Output te disparèt yon kote:

Out to host.
ExitCode: 2
ERRORLEVEL=0

Koulye a, kòm yon digresyon lirik, mwen pral sonje ke si andedan yon fonksyon Powershell ou ekri Write-Output oswa jis yon ekspresyon san yo pa asiyen li nan nenpòt varyab (e sa a implicite implique pwodiksyon nan kanal la Sòti), Lè sa a, menm lè w ap kouri lokalman, pa gen anyen ki pral parèt sou ekran an! Sa a se yon konsekans achitekti tiyo powershell la - chak fonksyon gen pwòp tiyo Sòti li yo, yo kreye yon etalaj pou li, ak tout bagay ki ale nan li konsidere kòm rezilta nan ekzekisyon fonksyon an, operatè Retounen an ajoute valè retounen nan menm bagay la. tiyo kòm dènye eleman epi transfere kontwòl nan fonksyon apèl la. Pou ilistre, ann kouri script sa a lokalman:

Function Write-Log {
  Param( [Parameter(Mandatory=$false, ValueFromPipeline=$true)] [String[]] $OutString = "`r`n" )
  Write-Output ("Function: "+$OutString)
  Return "ReturnValue"
}
Write-Output ("Main: "+"ParameterValue")
$res = Write-Log "ParameterValue"
$res.GetType()
$res.Length
$res | Foreach-Object { Write-Host ("Main: "+$_) }

Ak isit la se rezilta a:

Main: ParameterValue

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array
2
Main: Function: ParameterValue
Main: ReturnValue

Fonksyon prensipal la (kò script) tou gen pwòp tiyo Sòti li yo, epi si nou kouri premye script la soti nan CMD, redireksyon pwodiksyon an nan yon dosye,

PowerShell .TestOutput1.ps1 1 > TestOutput1.txt

Lè sa a, nou pral wè sou ekran an

ERRORLEVEL=1

ak nan dosye a

Out to host.
Out to output.
ExitCode: 1
1

si nou fè yon apèl menm jan an nan Powershell

PS D:sqlagent> .TestOutput1.ps1 1 > TestOutput1.txt

Lè sa a, li pral sou ekran an

Out to host.
ExitCode: 1

ak nan dosye a

Out to output.
1

Sa rive paske CMD lanse Powershell, ki, nan absans lòt enstriksyon, melanje de fil (Lame ak Sòti) epi li ba yo nan CMD a, ki voye tout sa li te resevwa nan yon dosye, ak nan ka lanse soti nan Powershell, de fil sa yo egziste separeman, ak redireksyon senbòl yo sèlman afekte Sòti a.

Retounen nan sijè prensipal la, se pou nou sonje ke modèl la objè .NET andedan powershell konplètman egziste nan yon òdinatè (yon sèl OS), lè w ap kouri kòd adistans atravè WSMAN, transfè a nan objè rive nan serializasyon XML, ki pote yon anpil nan enterè adisyonèl. nan rechèch nou an. Ann kontinye eksperyans nou yo nan kouri kòd sa a:

$res=Invoke-Command -ComputerName . -ScriptBlock { &'D:sqlagentTestOutput1.ps1' $args[0] } -ArgumentList $args[0]
$res.GetType()
$host.SetShouldExit($res)

Men sa nou genyen sou ekran an:

Out to host.

ExitCode: 3

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array
Не удается преобразовать аргумент "exitCode", со значением: "System.Object[]", для "SetShouldExit" в тип "System.Int32": "Не удается преобразовать значение "System.Object[]" типа "System.Object[]" в тип "System
.Int32"."
D:sqlagentTestOutput3.ps1:3 знак:1
+ $host.SetShouldExit($res)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodException
    + FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument

ERRORLEVEL=0

Gwo rezilta! Sa vle di ke lè w ap rele Invoke-Command, divizyon tiyo yo an de fil (Lame ak Sòti) kenbe, ki ban nou espwa pou siksè. Ann eseye kite yon sèl valè nan kouran Sòti a, pou ki nou pral chanje premye script ke nou kouri adistans:

$exitcode = $args[0]
Write-Host 'Out to host.'
#Write-Output 'Out to output.'
Write-Host ('ExitCode: ' + $exitcode)
Write-Output $exitcode
$host.SetShouldExit($exitcode)

Ann kouri li konsa:

$res=Invoke-Command -ComputerName . -ScriptBlock { &'D:sqlagentTestOutput1.ps1' $args[0] } -ArgumentList $args[0]
$host.SetShouldExit($res)

epi... WI, li sanble yon viktwa!

Out to host.
ExitCode: 4

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Int32                                    System.ValueType


ERRORLEVEL=4

Ann eseye konprann sa ki te pase. Nou rele Powershell lokalman, ki an vire rele Powershell sou òdinatè a aleka epi egzekite script nou an la. De kouran (Lame ak Sòti) ki soti nan machin aleka a te serialize epi yo te pase tounen, pandan y ap kouran Sòti a, ki gen yon sèl valè dijital ladan l, te konvèti nan kalite Int32 epi kòm sa yo te pase nan bò k ap resevwa a, ak bò k ap resevwa a te itilize li. kòm kòd sòti nan Powershell moun kap rele a.

Epi kòm yon chèk final, se pou nou kreye yon travay yon sèl etap sou sèvè SQL la ak kalite "sistèm operasyon (cmdexec)" ak tèks sa a:

PowerShell -NonInteractive -NoProfile "$res=Invoke-Command -ComputerName BACKUPSERVER -ConfigurationName SQLAgent -ScriptBlock {&'D:sqlagentTestOutput1.ps1' 6}; $host.SetShouldExit($res)"

HORAY! Travay la fini ak yon erè, tèks nan boutèy la:

Выполняется от имени пользователя: DOMAINagentuser. Out to host. ExitCode: 6.  Код завершения процесса 6.  Шаг завершился с ошибкой.

Konklizyon:

  • Evite itilize Write-Output ak espesifye ekspresyon san plasman. Ou dwe konnen si w deplase kòd sa a yon lòt kote nan script la ka pwodui rezilta inatandi.
  • Nan scripts ki gen entansyon pa pou lansman manyèl, men pou itilize nan mekanis automatisation ou yo, espesyalman pou apèl aleka atravè WINRM, fè manyen erè manyèl atravè Try/Catch, epi asire ke, nan nenpòt devlopman nan evènman, script sa a voye egzakteman yon valè kalite primitif. . Si ou vle jwenn Errorlevel klasik la, valè sa a dwe nimerik.

Sous: www.habr.com

Add nouvo kòmantè