ಪವರ್‌ಶೆಲ್ ಇನ್ವೋಕ್-ಕಮಾಂಡ್‌ನಿಂದ 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

ಏನಾಯಿತು ಎಂಬುದನ್ನು ಕಂಡುಹಿಡಿಯಲು ಪ್ರಯತ್ನಿಸೋಣ. ನಾವು ಪವರ್‌ಶೆಲ್ ಅನ್ನು ಸ್ಥಳೀಯವಾಗಿ ಕರೆದಿದ್ದೇವೆ, ಅದು ರಿಮೋಟ್ ಕಂಪ್ಯೂಟರ್‌ನಲ್ಲಿ ಪವರ್‌ಶೆಲ್ ಎಂದು ಕರೆಯಲ್ಪಡುತ್ತದೆ ಮತ್ತು ಅಲ್ಲಿ ನಮ್ಮ ಸ್ಕ್ರಿಪ್ಟ್ ಅನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸಿತು. ರಿಮೋಟ್ ಯಂತ್ರದಿಂದ ಎರಡು ಸ್ಟ್ರೀಮ್‌ಗಳನ್ನು (ಹೋಸ್ಟ್ ಮತ್ತು ಔಟ್‌ಪುಟ್) ಧಾರಾವಾಹಿಯಾಗಿ ಮತ್ತು ಹಿಂದಕ್ಕೆ ರವಾನಿಸಲಾಗಿದೆ, ಆದರೆ ಔಟ್‌ಪುಟ್ ಸ್ಟ್ರೀಮ್, ಅದರಲ್ಲಿ ಒಂದೇ ಡಿಜಿಟಲ್ ಮೌಲ್ಯವನ್ನು ಹೊಂದಿದ್ದು, ಇಂಟ್ 32 ಎಂದು ಟೈಪ್ ಮಾಡಿ ಮತ್ತು ಸ್ವೀಕರಿಸುವ ಬದಿಗೆ ರವಾನಿಸಲಾಗಿದೆ ಮತ್ತು ಸ್ವೀಕರಿಸುವ ಭಾಗವು ಅದನ್ನು ಬಳಸುತ್ತದೆ. ಕಾಲರ್ ಪವರ್‌ಶೆಲ್‌ನ ನಿರ್ಗಮನ ಕೋಡ್‌ನಂತೆ.

ಮತ್ತು ಅಂತಿಮ ಪರಿಶೀಲನೆಯಾಗಿ, ಕೆಳಗಿನ ಪಠ್ಯದೊಂದಿಗೆ "ಆಪರೇಟಿಂಗ್ ಸಿಸ್ಟಮ್ (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

ಕಾಮೆಂಟ್ ಅನ್ನು ಸೇರಿಸಿ