పవర్‌షెల్ ఇన్‌వోక్-కమాండ్ నుండి 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

గొప్ప ఫలితం! ఇన్‌వోక్-కమాండ్‌కి కాల్ చేస్తున్నప్పుడు, పైప్‌లైన్‌ల విభజన రెండు థ్రెడ్‌లుగా (హోస్ట్ మరియు అవుట్‌పుట్) నిర్వహించబడుతుందని దీని అర్థం, ఇది మాకు విజయం కోసం ఆశను ఇస్తుంది. అవుట్‌పుట్ స్ట్రీమ్‌లో ఒక విలువను మాత్రమే వదిలివేయడానికి ప్రయత్నిద్దాం, దీని కోసం మనం రిమోట్‌గా అమలు చేసే మొదటి స్క్రిప్ట్‌ను మారుస్తాము:

$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)” రకంతో SQL సర్వర్‌లో ఒక-దశ ఉద్యోగాన్ని సృష్టిద్దాం:

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

ఒక వ్యాఖ్యను జోడించండి