Ngasilake nilai saka powershell invoke-command menyang agen SQL Server

Nalika nggawe metodologi dhewe kanggo ngatur serep ing macem-macem server MS-SQL, aku ngenteni akeh wektu kanggo sinau mekanisme kanggo ngirim nilai ing Powershell sajrone telpon remot, mula aku nulis pangeling kanggo aku yen ana gunane. marang wong liya.

Dadi, ayo miwiti nganggo skrip sing gampang lan mbukak sacara lokal:

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

Kanggo mbukak skrip, aku bakal nggunakake file CMD ing ngisor iki, aku ora bakal kalebu saben wektu:

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

Ing layar kita bakal weruh ing ngisor iki:

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


Saiki ayo mbukak skrip sing padha liwat WSMAN (remote):

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

Lan iki minangka asil kanggo sampeyan:

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

Apik, Errorlevel wis ilang nang endi wae, nanging kita kudu entuk nilai saka naskah! Ayo coba desain ing ngisor iki:

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

Iki malah luwih menarik. Pesen ing Output wis ilang nang endi wae:

Out to host.
ExitCode: 2
ERRORLEVEL=0

Saiki, minangka digression lyrical, aku bakal nyathet yen ing fungsi Powershell sampeyan nulis Write-Output utawa mung ekspresi tanpa nemtokake variabel apa wae (lan iki sacara implisit nuduhake output menyang saluran Output), banjur sanajan mlaku sacara lokal, ora bakal ditampilake ing layar! Iki minangka akibat saka arsitektur pipa powershell - saben fungsi duwe pipa Output dhewe, array digawe kanggo, lan kabeh sing mlebu dianggep minangka asil saka eksekusi fungsi, operator Return nambahake nilai bali menyang padha. pipeline minangka unsur pungkasan lan transfer kontrol kanggo fungsi nelpon. Kanggo ilustrasi, ayo mbukak skrip ing ngisor iki sacara lokal:

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

Lan iki asile:

Main: ParameterValue

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

Fungsi utama (badan skrip) uga duwe pipa Output dhewe, lan yen kita mbukak skrip pisanan saka CMD, ngarahake output menyang file,

PowerShell .TestOutput1.ps1 1 > TestOutput1.txt

banjur kita bakal weruh ing layar

ERRORLEVEL=1

lan ing file

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

yen kita nelpon padha saka powershell

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

banjur bakal ana ing layar

Out to host.
ExitCode: 1

lan ing file

Out to output.
1

Iki kedadeyan amarga CMD ngluncurake powershell, sing, yen ora ana instruksi liyane, nyampur rong benang (Host lan Output) lan menehi menyang CMD, sing ngirim kabeh sing ditampa menyang file, lan yen mlaku saka powershell. loro Utas iki ana dhewe, lan simbol pangalihan mung mengaruhi Output.

Bali menyang topik utama, supaya kita elinga yen model obyek .NET nang powershell kebak ana ing siji komputer (siji OS), nalika mbukak kode mbatalake liwat WSMAN, transfer obyek dumadi liwat serialization XML, kang ndadekke akèh kapentingan tambahan. kanggo riset kita. Ayo nerusake eksperimen kanthi mbukak kode ing ngisor iki:

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

Lan iki sing ana ing layar:

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

asil apik! Tegese nalika nelpon Invoke-Command, divisi pipa dadi rong benang (Host lan Output) dijaga, sing menehi pangarep-arep kanggo sukses. Ayo nyoba ninggalake mung siji nilai ing stream Output, sing bakal ngganti skrip pisanan sing ditindakake kanthi jarak jauh:

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

Ayo mlaku kaya iki:

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

lan ... YES, iku katon kaya kamenangan !

Out to host.
ExitCode: 4

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


ERRORLEVEL=4

Ayo coba ngerteni apa sing kedadeyan. Kita nelpon powershell sacara lokal, sing banjur diarani powershell ing komputer remot lan nglakokake skrip kita ing kana. Loro lepen (Host lan Output) saka mesin remot padha serialized lan liwati maneh, nalika stream Output, gadhah nilai digital siji ing, diowahi kanggo ngetik Int32 lan liwati menyang sisih panrima, lan sisih panrima digunakake. minangka kode metu saka powershell panelpon.

Lan minangka mriksa pungkasan, ayo nggawe proyek siji-langkah ing server SQL kanthi jinis "Sistem operasi (cmdexec)" kanthi teks ing ngisor iki:

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

HORAY! Tugas rampung kanthi kesalahan, teks ing log:

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

Kesimpulan:

  • Aja nggunakake Tulis-Output lan nemtokake ekspresi tanpa tugas. Elinga yen mindhah kode iki ing papan liya ing skrip bisa ngasilake asil sing ora dikarepake.
  • Ing skrip dimaksudaké ora kanggo Bukak manual, nanging kanggo nggunakake ing mekanisme otomatisasi Panjenengan, utamané kanggo telpon remot liwat WINRM, nindakake kesalahan manual nangani liwat Coba / Nyekel, lan mesthekake yen, ing sembarang pangembangan acara, script iki ngirim persis siji nilai jinis primitif. . Yen sampeyan pengin entuk Errorlevel klasik, nilai iki kudu numerik.

Source: www.habr.com

Add a comment