Jirritorna valur minn powershell invoke-command lill-aġent SQL Server

Meta ħoloq il-metodoloġija tiegħi stess għall-ġestjoni tal-backups fuq servers MS-SQL multipli, qattajt ħafna ħin nistudja l-mekkaniżmu biex tgħaddi l-valuri f'Powershell waqt sejħiet mill-bogħod, għalhekk qed nikteb tfakkira lili nnifsi f'każ li jkun utli. lil xi ħadd ieħor.

Allura, ejja nibdew bi skript sempliċi u mexxih lokalment:

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

Biex tmexxi skripts, se nuża l-fajl CMD li ġej, mhux se ninkludih kull darba:

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

Fuq l-iskrin se naraw dan li ġej:

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


Issa ejja nħaddmu l-istess skript permezz ta' WSMAN (b'mod remot):

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

U hawn hu r-riżultat:

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

Kbir, Errorlevel sparixxa x'imkien, imma rridu nġibu l-valur mill-iskrittura! Ejja nippruvaw il-kostruzzjoni li ġejja:

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

Dan huwa saħansitra aktar interessanti. Il-messaġġ fl-Output sparixxa x'imkien:

Out to host.
ExitCode: 2
ERRORLEVEL=0

Issa, bħala digressjoni lirika, ser ninnota li jekk ġewwa funzjoni Powershell tikteb Write-Output jew sempliċiment espressjoni mingħajr ma tassenjaha għal xi varjabbli (u dan jimplika impliċitament output għall-kanal Output), allura anke meta taħdem lokalment, xejn mhu se jintwera fuq l-iskrin! Din hija konsegwenza tal-arkitettura tal-pipeline powershell - kull funzjoni għandha l-pipeline Output tagħha stess, tinħoloq firxa għaliha, u dak kollu li jidħol fih jitqies bħala r-riżultat tal-eżekuzzjoni tal-funzjoni, l-operatur Ritorn iżid il-valur tar-ritorn għall-istess pipeline bħala l-aħħar element u jittrasferixxi l-kontroll lill-funzjoni li ssejjaħ. Biex nagħtu eżempju, ejja nħaddmu l-iskrittura li ġejja lokalment:

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

U hawn hu r-riżultat:

Main: ParameterValue

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

Il-funzjoni ewlenija (korp tal-iskrittura) għandha wkoll il-pipeline tal-Output tagħha stess, u jekk inħaddmu l-ewwel skript minn CMD, nidderieġu l-output għal fajl,

PowerShell .TestOutput1.ps1 1 > TestOutput1.txt

imbagħad naraw fuq l-iskrin

ERRORLEVEL=1

u fil-fajl

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

jekk nagħmlu sejħa simili minn powershell

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

imbagħad ikun fuq l-iskrin

Out to host.
ExitCode: 1

u fil-fajl

Out to output.
1

Dan jiġri minħabba li s-CMD iniedi powershell, li, fin-nuqqas ta 'struzzjonijiet oħra, iħallat żewġ ħjut (Host u Output) u jagħtihom lis-CMD, li jibgħat dak kollu li rċieva f'fajl, u fil-każ li jaħdem minn powershell, dawn iż-żewġ ħjut jeżistu separatament, u r-ridirezzjonijiet tas-simbolu jaffettwaw biss l-Output.

Nirritornaw għas-suġġett ewlieni, ejjew niftakru li l-mudell ta 'oġġett .NET ġewwa powershell jeżisti bis-sħiħ fi ħdan kompjuter wieħed (OS wieħed), meta tħaddem kodiċi mill-bogħod permezz ta' WSMAN, it-trasferiment ta 'oġġetti jseħħ permezz ta' serialization XML, li jġib ħafna interess addizzjonali għar-riċerka tagħna. Ejja nkomplu bl-esperimenti tagħna billi nħaddmu l-kodiċi li ġej:

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

U dan huwa dak li għandna fuq l-iskrin:

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

Riżultat kbir! Dan ifisser li meta ssejjaħ Invoke-Command, tinżamm id-diviżjoni tal-pipelines f'żewġ ħjut (Host u Output), li tagħtina tama għas-suċċess. Ejja nippruvaw inħallu valur wieħed biss fil-fluss Output, li għalih se nibdlu l-ewwel skript li nħaddmu mill-bogħod:

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

Ejja nħaddmu hekk:

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

u... IVA, qisu rebħa!

Out to host.
ExitCode: 4

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


ERRORLEVEL=4

Ejja nippruvaw insemmu x'ġara. Aħna sejjaħ powershell lokalment, li mbagħad sejjaħ powershell fuq il-kompjuter remot u eżegwiti l-iskrittura tagħna hemmhekk. Żewġ flussi (Host u Output) mill-magna remota ġew serialized u mgħoddija lura, filwaqt li l-fluss tal-Output, li għandu valur diġitali wieħed fih, ġie kkonvertit għal tip Int32 u bħala tali għadda għan-naħa li tirċievi, u n-naħa li tirċievi użatha bħala l-kodiċi tal-ħruġ tal-powershell min iċempel.

U bħala kontroll finali, ejja noħolqu xogħol f'pass wieħed fuq is-server SQL bit-tip "Sistema operattiva (cmdexec)" bit-test li ġej:

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

HURA! Il-kompitu tlesta bi żball, test fil-ġurnal:

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

Konklużjonijiet:

  • Evita li tuża Write-Output u tispeċifika espressjonijiet mingħajr assenjazzjoni. Kun konxju li ċaqliq ta' dan il-kodiċi xi mkien ieħor fl-iskript jista' jipproduċi riżultati mhux mistennija.
  • Fi skripts maħsuba mhux għat-tnedija manwali, iżda għall-użu fil-mekkaniżmi ta' awtomazzjoni tiegħek, speċjalment għal sejħiet mill-bogħod permezz ta' WINRM, agħmel immaniġġjar manwali tal-iżbalji permezz Try/Catch, u żgura li, fi kwalunkwe żvilupp ta' avvenimenti, dan l-iskript jibgħat eżattament valur wieħed tat-tip primittiv . Jekk trid tikseb l-Errorlevel klassika, dan il-valur għandu jkun numeriku.

Sors: www.habr.com

Żid kumment