پاورشیل انووک کمانڈ سے ایس کیو ایل سرور ایجنٹ کو ویلیو واپس کرنا

متعدد MS-SQL سرورز پر بیک اپ کے انتظام کے لیے اپنا طریقہ کار بناتے وقت، میں نے ریموٹ کالز کے دوران Powershell میں اقدار کو منتقل کرنے کے طریقہ کار کا مطالعہ کرنے میں کافی وقت صرف کیا، اس لیے میں اپنے آپ کو ایک یاد دہانی لکھ رہا ہوں اگر یہ مفید ہو کسی اور کو.

تو، آئیے ایک سادہ اسکرپٹ کے ساتھ شروع کریں اور اسے مقامی طور پر چلائیں:

$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

مین فنکشن (اسکرپٹ باڈی) کی اپنی آؤٹ پٹ پائپ لائن بھی ہے، اور اگر ہم سی ایم ڈی سے پہلی اسکرپٹ چلاتے ہیں، آؤٹ پٹ کو فائل میں ری ڈائریکٹ کرتے ہوئے،

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

ایسا اس لیے ہوتا ہے کیونکہ سی ایم ڈی پاور شیل لانچ کرتا ہے، جو کہ دیگر ہدایات کی غیر موجودگی میں، دو تھریڈز (میزبان اور آؤٹ پٹ) کو ملا کر سی ایم ڈی کو دیتا ہے، جو اسے موصول ہونے والی ہر چیز کو فائل میں بھیج دیتا ہے، اور پاور شیل سے لانچ ہونے کی صورت میں، یہ دونوں تھریڈز الگ الگ موجود ہیں، اور علامت ری ڈائریکٹ صرف آؤٹ پٹ کو متاثر کرتی ہے۔

اصل موضوع کی طرف واپس آتے ہوئے، ہمیں یاد رکھنا چاہیے کہ پاور شیل کے اندر موجود .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 ٹائپ میں تبدیل کر دیا گیا اور اس طرح وصول کنندہ کی طرف منتقل کیا گیا، اور وصول کنندہ نے اسے استعمال کیا۔ کالر پاور شیل کے ایگزٹ کوڈ کے طور پر۔

اور حتمی جانچ کے طور پر، آئیے ایس کیو ایل سرور پر درج ذیل متن کے ساتھ "آپریٹنگ سسٹم (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 کے ذریعے ریموٹ کالز کے لیے، Try/Catch کے ذریعے دستی غلطی کو سنبھالیں، اور یقینی بنائیں کہ واقعات کی کسی بھی ترقی میں، یہ اسکرپٹ بالکل ایک قدیم قسم کی قدر بھیجتا ہے۔ . اگر آپ کلاسک ایرر لیول حاصل کرنا چاہتے ہیں تو یہ قدر عددی ہونی چاہیے۔

ماخذ: www.habr.com

نیا تبصرہ شامل کریں