பவர்ஷெல் இன்வோக்-கமாண்டிலிருந்து ஒரு மதிப்பை SQL சர்வர் ஏஜெண்டிற்குத் திருப்பி அனுப்புகிறது

பல MS-SQL சேவையகங்களில் காப்புப்பிரதிகளை நிர்வகிப்பதற்கான எனது சொந்த வழிமுறையை உருவாக்கும் போது, ​​தொலைநிலை அழைப்புகளின் போது பவர்ஷெல்லில் மதிப்புகளை அனுப்புவதற்கான வழிமுறையைப் படிப்பதில் நான் நிறைய நேரம் செலவிட்டேன், எனவே அது பயனுள்ளதாக இருந்தால் எனக்கு நினைவூட்டலை எழுதுகிறேன். வேறொருவருக்கு.

எனவே, ஒரு எளிய ஸ்கிரிப்டுடன் தொடங்கி அதை உள்ளூரில் இயக்கலாம்:

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

ஸ்கிரிப்ட்களை இயக்க, நான் பின்வரும் CMD கோப்பைப் பயன்படுத்துவேன், ஒவ்வொரு முறையும் அதைச் சேர்க்க மாட்டேன்:

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

திரையில் நாம் பின்வருவனவற்றைக் காண்போம்:

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


இப்போது அதே ஸ்கிரிப்டை WSMAN வழியாக இயக்குவோம் (தொலைவில்):

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

மற்றும் முடிவு இங்கே:

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

அருமை, பிழை நிலை எங்கோ மறைந்துவிட்டது, ஆனால் ஸ்கிரிப்ட்டிலிருந்து மதிப்பைப் பெற வேண்டும்! பின்வரும் வடிவமைப்பை முயற்சிப்போம்:

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

இது இன்னும் சுவாரஸ்யமானது. வெளியீட்டில் உள்ள செய்தி எங்கோ மறைந்துவிட்டது:

Out to host.
ExitCode: 2
ERRORLEVEL=0

இப்போது, ​​ஒரு பாடல் வரிவடிவமாக, பவர்ஷெல் செயல்பாட்டிற்குள் நீங்கள் எழுது-வெளியீடு அல்லது வெளிப்பாட்டை எந்த மாறிக்கும் ஒதுக்காமல் எழுதினால் (இது மறைமுகமாக அவுட்புட் சேனலுக்கான வெளியீட்டைக் குறிக்கிறது), பின்னர் உள்நாட்டில் இயங்கும் போது கூட, எதுவும் திரையில் காட்டப்படாது! இது பவர்ஷெல் பைப்லைன் கட்டமைப்பின் விளைவாகும் - ஒவ்வொரு செயல்பாட்டிற்கும் அதன் சொந்த வெளியீட்டு குழாய் உள்ளது, அதற்கென ஒரு வரிசை உருவாக்கப்படுகிறது, மேலும் அதில் செல்லும் அனைத்தும் செயல்பாட்டின் செயல்பாட்டின் விளைவாக கருதப்படுகிறது, ரிட்டர்ன் ஆபரேட்டர் அதே திரும்பும் மதிப்பை சேர்க்கிறது. பைப்லைன் கடைசி உறுப்பு மற்றும் அழைப்பு செயல்பாட்டிற்கு கட்டுப்பாட்டை மாற்றுகிறது. விளக்குவதற்கு, பின்வரும் ஸ்கிரிப்டை உள்ளூரில் இயக்குவோம்:

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

மற்றும் முடிவு இங்கே:

Main: ParameterValue

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

முக்கிய செயல்பாடு (ஸ்கிரிப்ட் பாடி) அதன் சொந்த வெளியீட்டு பைப்லைனையும் கொண்டுள்ளது, மேலும் CMD இலிருந்து முதல் ஸ்கிரிப்டை இயக்கினால், வெளியீட்டை ஒரு கோப்பிற்கு திருப்பி விடுகிறோம்,

PowerShell .TestOutput1.ps1 1 > TestOutput1.txt

பிறகு திரையில் பார்ப்போம்

ERRORLEVEL=1

மற்றும் கோப்பில்

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

நாம் பவர்ஷெல்லில் இருந்து இதே போன்ற அழைப்பை மேற்கொண்டால்

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

பின்னர் அது திரையில் இருக்கும்

Out to host.
ExitCode: 1

மற்றும் கோப்பில்

Out to output.
1

CMD பவர்ஷெல்லைத் தொடங்குவதால் இது நிகழ்கிறது, இது மற்ற அறிவுறுத்தல்கள் இல்லாத நிலையில், இரண்டு த்ரெட்களை (ஹோஸ்ட் மற்றும் அவுட்புட்) கலந்து CMDக்கு அளிக்கிறது, அது பெற்ற அனைத்தையும் ஒரு கோப்பிற்கு அனுப்புகிறது, மேலும் பவர்ஷெல்லிலிருந்து தொடங்கும் போது, இந்த இரண்டு இழைகளும் தனித்தனியாக உள்ளன, மேலும் குறியீடு வழிமாற்றுகள் வெளியீட்டை மட்டுமே பாதிக்கும்.

முக்கிய தலைப்புக்குத் திரும்புகையில், பவர்ஷெல்லுக்குள் உள்ள .NET ஆப்ஜெக்ட் மாதிரியானது ஒரு கணினியில் (ஒரு OS) முழுமையாக உள்ளது என்பதை நினைவில் கொள்வோம், WSMAN வழியாக குறியீட்டை தொலைவிலிருந்து இயக்கும்போது, ​​XML வரிசைப்படுத்தல் மூலம் பொருள்களின் பரிமாற்றம் நிகழ்கிறது, இது கூடுதல் ஆர்வத்தைத் தருகிறது. எங்கள் ஆராய்ச்சிக்கு. பின்வரும் குறியீட்டை இயக்குவதன் மூலம் எங்கள் சோதனைகளைத் தொடரலாம்:

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

திரையில் நாம் வைத்திருப்பது இதுதான்:

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

சிறந்த முடிவு! Invoke-Command ஐ அழைக்கும் போது, ​​பைப்லைன்களை இரண்டு இழைகளாக (ஹோஸ்ட் மற்றும் அவுட்புட்) பிரிப்பது பராமரிக்கப்படுகிறது, இது வெற்றிக்கான நம்பிக்கையை அளிக்கிறது. அவுட்புட் ஸ்ட்ரீமில் ஒரே ஒரு மதிப்பை மட்டும் விட்டுவிட முயற்சிப்போம், அதற்காக நாம் ரிமோட் மூலம் இயக்கும் முதல் ஸ்கிரிப்டை மாற்றுவோம்:

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

இதை இப்படி இயக்குவோம்:

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

மற்றும்... ஆம், இது ஒரு வெற்றி போல் தெரிகிறது!

Out to host.
ExitCode: 4

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


ERRORLEVEL=4

என்ன நடந்தது என்பதைக் கண்டுபிடிக்க முயற்சிப்போம். நாங்கள் உள்நாட்டில் பவர்ஷெல் என்று அழைத்தோம், அதை ரிமோட் கம்ப்யூட்டரில் பவர்ஷெல் என்று அழைத்தோம், மேலும் எங்கள் ஸ்கிரிப்டை அங்கு செயல்படுத்தினோம். ரிமோட் மெஷினில் இருந்து இரண்டு ஸ்ட்ரீம்கள் (ஹோஸ்ட் மற்றும் அவுட்புட்) வரிசைப்படுத்தப்பட்டு மீண்டும் அனுப்பப்பட்டன, அதே சமயம் அவுட்புட் ஸ்ட்ரீம், அதில் ஒரு டிஜிட்டல் மதிப்பைக் கொண்டு, Int32 வகையாக மாற்றப்பட்டு, பெறும் பக்கத்திற்கு அனுப்பப்பட்டது, மேலும் பெறும் பக்கம் அதைப் பயன்படுத்தியது. அழைப்பாளர் பவர்ஷெல்லின் வெளியேறும் குறியீடாக.

இறுதிச் சரிபார்ப்பாக, SQL சேவையகத்தில் பின்வரும் உரையுடன் "இயக்க முறைமை (cmdexec)" வகையுடன் ஒரு-படி வேலையை உருவாக்குவோம்:

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

ஹூரே! பணி பிழையுடன் முடிந்தது, பதிவில் உள்ள உரை:

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

முடிவுகளை:

  • எழுதுதல்-வெளியீட்டைப் பயன்படுத்துவதையும் ஒதுக்குதல் இல்லாமல் வெளிப்பாடுகளைக் குறிப்பிடுவதையும் தவிர்க்கவும். இந்தக் குறியீட்டை ஸ்கிரிப்ட்டில் வேறு இடத்திற்கு நகர்த்துவது எதிர்பாராத முடிவுகளைத் தரக்கூடும் என்பதை நினைவில் கொள்ளவும்.
  • ஸ்கிரிப்ட்களில், கைமுறையாகத் தொடங்குவதற்காக அல்ல, ஆனால் உங்கள் ஆட்டோமேஷன் பொறிமுறைகளில் பயன்படுத்த, குறிப்பாக WINRM வழியாக ரிமோட் அழைப்புகளுக்கு, முயற்சி/கேட்ச் மூலம் கைமுறையாகப் பிழையைக் கையாளவும், மேலும் நிகழ்வுகளின் எந்த வளர்ச்சியிலும், இந்த ஸ்கிரிப்ட் சரியாக ஒரு பழமையான வகை மதிப்பை அனுப்புகிறது என்பதை உறுதிப்படுத்தவும். . நீங்கள் கிளாசிக் பிழை அளவைப் பெற விரும்பினால், இந்த மதிப்பு எண்ணாக இருக்க வேண்டும்.

ஆதாரம்: www.habr.com

கருத்தைச் சேர்