Dychwelyd gwerth o orchymyn invoke powershell i asiant SQL Server

Wrth greu fy methodoleg fy hun ar gyfer rheoli copïau wrth gefn ar weinyddion MS-SQL lluosog, treuliais lawer o amser yn astudio'r mecanwaith ar gyfer pasio gwerthoedd yn Powershell yn ystod galwadau o bell, felly rwy'n ysgrifennu nodyn atgoffa ataf fy hun rhag ofn ei fod yn ddefnyddiol i rywun arall.

Felly, gadewch i ni ddechrau gyda sgript syml a'i rhedeg yn lleol:

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

I redeg sgriptiau, byddaf yn defnyddio'r ffeil CMD ganlynol, ni fyddaf yn ei chynnwys bob tro:

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

Ar y sgrin byddwn yn gweld y canlynol:

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


Nawr gadewch i ni redeg yr un sgript trwy WSMAN (o bell):

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

A dyma'r canlyniad:

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

Gwych, mae Errorlevel wedi diflannu yn rhywle, ond mae angen i ni gael y gwerth o'r sgript! Gadewch i ni roi cynnig ar y dyluniad canlynol:

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

Mae hyn hyd yn oed yn fwy diddorol. Mae'r neges yn Allbwn wedi diflannu yn rhywle:

Out to host.
ExitCode: 2
ERRORLEVEL=0

Nawr, fel digression telynegol, byddaf yn nodi, os y tu mewn i swyddogaeth Powershell rydych chi'n ysgrifennu Write-Output neu ddim ond mynegiant heb ei aseinio i unrhyw newidyn (ac mae hyn yn ymhlyg yn golygu allbwn i'r sianel Allbwn), yna hyd yn oed wrth redeg yn lleol, ni fydd dim yn cael ei arddangos ar y sgrin! Mae hyn yn ganlyniad i bensaernïaeth y biblinell cregyn pŵer - mae gan bob swyddogaeth ei biblinell Allbwn ei hun, mae amrywiaeth yn cael ei chreu ar ei chyfer, ac mae popeth sy'n mynd iddo yn cael ei ystyried yn ganlyniad gweithredu'r swyddogaeth, mae'r gweithredwr Dychwelyd yn ychwanegu'r gwerth dychwelyd i'r un peth piblinell fel yr elfen olaf ac yn trosglwyddo rheolaeth i'r swyddogaeth galw. I ddarlunio, gadewch i ni redeg y sgript ganlynol yn lleol:

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: "+$_) }

A dyma'r canlyniad:

Main: ParameterValue

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

Mae gan y brif swyddogaeth (corff sgript) hefyd ei biblinell Allbwn ei hun, ac os ydym yn rhedeg y sgript gyntaf o CMD, yn ailgyfeirio'r allbwn i ffeil,

PowerShell .TestOutput1.ps1 1 > TestOutput1.txt

yna byddwn yn gweld ar y sgrin

ERRORLEVEL=1

ac yn y ffeil

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

os gwnawn alwad debyg gan powershell

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

yna bydd ar y sgrin

Out to host.
ExitCode: 1

ac yn y ffeil

Out to output.
1

Mae hyn yn digwydd oherwydd bod y CMD yn lansio powershell, sydd, yn absenoldeb cyfarwyddiadau eraill, yn cymysgu dwy edefyn (Gwesteiwr ac Allbwn) ac yn eu rhoi i'r CMD, sy'n anfon popeth a gafodd i ffeil, ac yn achos lansio o powershell, mae'r ddau edefyn hyn yn bodoli ar wahân, ac mae'r ailgyfeiriadau symbol yn effeithio ar Allbwn yn unig.

Gan ddychwelyd at y prif bwnc, gadewch inni gofio bod y model gwrthrych .NET y tu mewn i powershell yn bodoli'n llawn o fewn un cyfrifiadur (un OS), wrth redeg cod o bell trwy WSMAN, mae trosglwyddo gwrthrychau yn digwydd trwy gyfresoli XML, sy'n dod â llawer o ddiddordeb ychwanegol i'n hymchwil. Gadewch i ni barhau â'n harbrofion trwy redeg y cod canlynol:

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

A dyma sydd gennym ar y sgrin:

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

Canlyniad gwych! Mae'n golygu, wrth alw Invoke-Command, bod rhaniad y piblinellau yn ddwy edefyn (Gwesteiwr ac Allbwn) yn cael ei gynnal, sy'n rhoi gobaith i ni am lwyddiant. Gadewch i ni geisio gadael dim ond un gwerth yn y ffrwd Allbwn, y byddwn yn newid y sgript gyntaf un rydyn ni'n ei rhedeg o bell ar ei chyfer:

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

Gadewch i ni ei redeg fel hyn:

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

ac... OES, mae'n edrych fel buddugoliaeth!

Out to host.
ExitCode: 4

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


ERRORLEVEL=4

Gadewch i ni geisio darganfod beth ddigwyddodd. Fe wnaethon ni alw powershell yn lleol, a oedd yn ei dro yn galw powershell ar y cyfrifiadur o bell ac yn gweithredu ein sgript yno. Cafodd dwy ffrwd (Gwesteiwr ac Allbwn) o'r peiriant anghysbell eu cyfresoli a'u pasio'n ôl, tra bod y ffrwd Allbwn, sydd ag un gwerth digidol ynddi, wedi'i throsi i fath Int32 ac felly'n cael ei throsglwyddo i'r ochr dderbyn, a'r ochr dderbyn yn ei defnyddio fel cod ymadael y powershell galwr.

Ac fel gwiriad terfynol, gadewch i ni greu swydd un cam ar y gweinydd SQL gyda'r math “System weithredu (cmdexec)” gyda'r testun canlynol:

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

HWRDD! Cwblhawyd y dasg gyda gwall, testun yn y log:

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

Casgliadau:

  • Osgoi defnyddio Ysgrifennu-Allbwn a nodi ymadroddion heb aseiniad. Byddwch yn ymwybodol y gallai symud y cod hwn i rywle arall yn y sgript arwain at ganlyniadau annisgwyl.
  • Mewn sgriptiau na fwriedir eu lansio â llaw, ond i'w defnyddio yn eich mecanweithiau awtomeiddio, yn enwedig ar gyfer galwadau o bell trwy WINRM, gwnewch drin gwallau â llaw trwy Try/Catch, a sicrhewch, wrth ddatblygu unrhyw ddigwyddiadau, bod y sgript hon yn anfon un gwerth math cyntefig yn union . Os ydych chi am gael y lefel Gwall clasurol, rhaid i'r gwerth hwn fod yn rhifol.

Ffynhonnell: hab.com

Ychwanegu sylw