सवाल एक स्क्रिप्ट से तर्क के साथ एक दूसरी स्क्रिप्ट को आमंत्रित करें


मैं PowerShell के लिए अपेक्षाकृत नया हूं और एक स्क्रिप्ट है जो एक कॉन्फ़िगरेशन फ़ाइल पढ़ती है जिसके परिणामस्वरूप नाम मूल्य जोड़ों का एक सेट होता है जिसे मैं किसी दूसरी PowerShell स्क्रिप्ट में फ़ंक्शन के लिए तर्क के रूप में पास करना चाहता हूं।

मुझे नहीं पता कि इस कॉन्फ़िगरेशन फ़ाइल में डिज़ाइन समय पर कौन से पैरामीटर लगाए जाएंगे, इसलिए उस बिंदु पर जहां मुझे इस दूसरी PowerShell स्क्रिप्ट को आमंत्रित करने की आवश्यकता है, मैं मूल रूप से केवल एक चर है जिसमें इस दूसरी स्क्रिप्ट का पथ है, और दूसरा वेरिएबल जो पथ चर में पहचाने गए स्क्रिप्ट को पास करने के लिए तर्कों की एक सरणी है।

तो दूसरी स्क्रिप्ट ($ scriptPath) के पथ वाले चर के पास एक मान हो सकता है:

"c:\the\path\to\the\second\script.ps1"

वेरिएबल युक्त तर्क ($ argumentList) कुछ ऐसा दिख सकता है:

-ConfigFilename "doohickey.txt" -RootDirectory "c:\some\kind\of\path" -Max 11

मैं $ राज्य सूची से सभी तर्कों के साथ script.ps1 के निष्पादन के लिए इस स्थिति से कैसे प्राप्त करूं?

मैं इस दूसरी स्क्रिप्ट से किसी भी लिखित-होस्ट कमांड को कंसोल पर दिखाना चाहता हूं जिससे इस पहली स्क्रिप्ट को बुलाया जाता है।

मैंने डॉट-सोर्सिंग, इनवोक-कमांड, इनवोक-एक्सप्रेशन और स्टार्ट-जॉब की कोशिश की है, लेकिन मुझे ऐसा दृष्टिकोण नहीं मिला है जो त्रुटियों का उत्पादन नहीं करता है।

उदाहरण के लिए, मैंने सोचा कि सबसे आसान पहला मार्ग निम्नानुसार स्टार्ट-जॉब को आजमाया गया था:

Start-Job -FilePath $scriptPath -ArgumentList $argumentList

... लेकिन यह इस त्रुटि के साथ विफल रहता है:

System.Management.Automation.ValidationMetadataException:
Attribute cannot be added because it would cause the variable
ConfigFilename with value -ConfigFilename to become invalid.

... इस मामले में, "ConfigFilename" दूसरी स्क्रिप्ट द्वारा परिभाषित पैरा सूची में पहला पैरामीटर है, और मेरा आमंत्रण स्पष्ट रूप से "-ConfigFilename" पर अपना मान सेट करने का प्रयास कर रहा है, जिसका स्पष्ट रूप से नाम से पैरामीटर की पहचान करना है , इसका मूल्य निर्धारित नहीं है।

मैं क्या खो रहा हूँ?

संपादित करें:

ठीक है, यहां invokee.ps1 नाम की एक फ़ाइल में, टू-टू-स्क्रिप्ट स्क्रिप्ट का एक मॉक-अप है

Param(
[parameter(Mandatory=$true)]
[alias("rc")]
[string]
[ValidateScript( {Test-Path $_ -PathType Leaf} )]
$ConfigurationFilename,
[alias("e")]
[switch]
$Evaluate,
[array]
[Parameter(ValueFromRemainingArguments=$true)]
$remaining)

function sayHelloWorld()
{
    Write-Host "Hello, everybody, the config file is <$ConfigurationFilename>."
    if ($ExitOnErrors)
    {
        Write-Host "I should mention that I was told to evaluate things."
    }
    Write-Host "I currently live here: $gScriptDirectory"
    Write-Host "My remaining arguments are: $remaining"
    Set-Content .\hello.world.txt "It worked"
}

$gScriptPath = $MyInvocation.MyCommand.Path
$gScriptDirectory = (Split-Path $gScriptPath -Parent)
sayHelloWorld

... और यहां invokee.ps1 नाम की एक फ़ाइल में, कॉलिंग स्क्रिप्ट का एक मॉक-अप है:

function pokeTheInvokee()
{
    $scriptPath = (Join-Path -Path "." -ChildPath "invokee.ps1")
    $scriptPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($scriptPath)

    $configPath = (Join-Path -Path "." -ChildPath "invoker.ps1")
    $configPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($configPath)

    $argumentList = @()
    $argumentList += ("-ConfigurationFilename", "`"$configPath`"")
    $argumentList += , "-Evaluate"

    Write-Host "Attempting to invoke-expression with: `"$scriptPath`" $argumentList"
    Invoke-Expression "`"$scriptPath`" $argumentList"
    Invoke-Expression ".\invokee.ps1 -ConfigurationFilename `".\invoker.ps1`" -Evaluate
    Write-Host "Invokee invoked."
}

pokeTheInvokee

जब मैं invoker.ps1 चलाता हूं, यह वह त्रुटि है जिसे मैं वर्तमान में Invoke-Expression के पहले कॉल पर प्राप्त कर रहा हूं:

Invoke-Expression : You must provide a value expression on
the right-hand side of the '-' operator.

दूसरा कॉल ठीक काम करता है, लेकिन एक महत्वपूर्ण अंतर यह है कि पहला संस्करण उन तर्कों का उपयोग कर रहा है जिनके पथ में उनमें रिक्त स्थान हैं, और दूसरा नहीं है। क्या मैं इन पथों में रिक्त स्थान की उपस्थिति को मिटाना चाहता हूं?


44
2017-10-12 00:12


मूल


यदि आप अपनी प्रत्येक स्क्रिप्ट के लिए स्रोत प्रदान करते हैं तो यह भी मदद करेगा। उदाहरण के लिए, अपनी समस्या का वर्णन करने वाली पीओसी (अवधारणा का प्रमाण) परियोजना बनाएं। इसके बाद हम परीक्षण कर सकते हैं और इसके साथ खेल सकते हैं, और शायद किसी को कोई समाधान, या एक समाधान मिल जाएगा। - Neolisk
हाँ - मैं चित्रित करने के लिए एक मिनी संस्करण को गिनने की कोशिश कर रहा हूं। जल्द ही पोस्ट करेंगे ... - Hoobajoob


जवाब:


अहा। यह स्क्रिप्ट के रास्ते में रिक्त स्थान होने की एक साधारण समस्या साबित हुई।

इनवोक-एक्सप्रेशन लाइन को बदलना:

Invoke-Expression "& `"$scriptPath`" $argumentList"

... इसे लात मारने के लिए पर्याप्त था। आपकी मदद और प्रतिक्रिया के लिए Neolisk के लिए धन्यवाद!


41
2017-10-12 03:25



मुझे खुशी है कि आपने इसे हल किया है। अगर मेरा जवाब सहायक था, तो आप इसे ऊपर उठा सकते हैं। - Neolisk
अपने उत्तर में जोड़ने के लिए। पथ में रिक्त स्थान होने का मतलब है कि आपको उद्धरणों का उपयोग करना होगा। इनवोक-एक्सप्रेशन द्वारा कमांड के विपरीत कोट्स को एक स्ट्रिंग के रूप में माना जाता है। इसलिए, यदि आप स्ट्रिंग को निष्पादित करना चाहते हैं, तो आपको "कॉल ऑपरेटर" का उपयोग करने की आवश्यकता है, जो आपके उदाहरण की शुरुआत में एम्परसेंड प्रतीक है। यहाँ कॉल ऑपरेटर की परिभाषा है। - Aeropher


Invoke-Expression पूरी तरह से काम करना चाहिए, बस सुनिश्चित करें कि आप इसे सही तरीके से उपयोग कर रहे हैं। आपके मामले के लिए यह इस तरह दिखना चाहिए:

Invoke-Expression "$scriptPath $argumentList"

मैंने गेट-सर्विस के साथ इस दृष्टिकोण का परीक्षण किया और उम्मीद के अनुसार काम कर रहा है।


38
2017-10-12 00:52



Invoke-Expression "$ scriptPath $ argumentList" तुरंत लौटाता है और स्क्रिप्ट चलाने के लिए प्रकट नहीं होता है। अगर मैं इसे Invoke-Expression में बदलता हूं "powerhell $ scriptPath $ argumentList", PowerGui बस लटकता प्रतीत होता है। - Hoobajoob
@ होबाबोजोब: Invoke-Expression तुरंत वापस नहीं आता है, यह धैर्यपूर्वक तब तक प्रतीक्षा करता है जब तक कि आवंटित स्क्रिप्ट समाप्त नहीं हो जाती - मैंने अभी एक पीओसी परियोजना पर परीक्षण किया। आपके द्वारा लक्षित स्क्रिप्ट के साथ कुछ गड़बड़ होनी चाहिए। - Neolisk
एचएम - मैंने बैच फ़ाइलों, विजुअल स्टूडियो आईडीई, डॉस कमांड लाइन, और पावरहेल कंसोल सत्रों से इस दूसरी स्क्रिप्ट को कई अलग-अलग तरीकों से चलाया है, लेकिन यह पहली बार है जब मैंने इसे किसी अन्य पावरहेल स्क्रिप्ट से चलाने की कोशिश की है। स्क्रिप्ट में खुद की तरह की चीजें क्या हो सकती हैं जो इसे Invoke-Expression के माध्यम से सफलतापूर्वक लॉन्च करने से रोकती हैं? - Hoobajoob
यह केवल तभी काम करेगा जब तर्क सूची में ऑब्जेक्ट्स सभी प्रकार की स्ट्रिंग हैं, हालांकि सही है? - Backwards_Dave
@Backwards_Dave: $scriptPath तथा $argumentList यहाँ तार हैं। एक स्ट्रिंग में एक गैर स्ट्रिंग तर्क हो सकता है (एक स्ट्रिंग के रूप में लिखा गया है)। उम्मीद है कि यह आपके प्रश्न का उत्तर देगा। - Neolisk


बहुत सरल वास्तव में:

विधि 1:

Invoke-Expression $scriptPath $argumentList

विधि 2: 

& $scriptPath $argumentList

विधि 3:

$scriptPath $argumentList

यदि आपके पास जगहें हैं scriptPath, उनसे बचने के लिए मत भूलना `"$scriptPath`"


23
2018-01-23 03:42



विकल्पों के लिए धन्यवाद, मुझे वास्तव में किसी अन्य प्रश्न पर इस उत्तर द्वारा प्रदान किया गया अतिरिक्त विकल्प पसंद है। stackoverflow.com/a/33206405/3794873 - dragon788


यहां एक उत्तर है जो एक पीएस स्क्रिप्ट से एक और पीएस स्क्रिप्ट को कॉल करने के अधिक सामान्य प्रश्न को कवर करता है, जैसा कि आप कर सकते हैं यदि आप कई छोटी, संकीर्ण-उद्देश्य स्क्रिप्ट्स की अपनी स्क्रिप्ट लिख रहे थे।

मैंने पाया कि यह बस डॉट-सोर्सिंग का उपयोग करने का मामला था। यही है, आप बस करते हैं:

# This is Script-A.ps1

. ./Script-B.ps1 -SomeObject $variableFromScriptA -SomeOtherParam 1234;

मैंने सभी क्यू / ए को बहुत भ्रमित और जटिल पाया और अंत में उपरोक्त सरल विधि पर उतरा, जो वास्तव में एक और स्क्रिप्ट को कॉल करने जैसा है जैसे कि यह मूल लिपि में एक समारोह था, जो मुझे अधिक सहज लगता है।

डॉट-सोर्सिंग पूरी तरह से दूसरी स्क्रिप्ट को "आयात" कर सकती है:

. ./Script-B.ps1

अब यह है कि दो फाइलें विलय हो गई हैं।

आखिरकार, जो मैं वास्तव में याद कर रहा था वह धारणा है कि मुझे पुन: प्रयोज्य कार्यों का एक मॉड्यूल बनाना चाहिए।


6
2017-11-26 15:32





हम प्रयोग कर सकते हैं splatting इसके लिए:

& $command @args

कहा पे @args (स्वचालित चर $ args) पैरामीटर की सरणी में विभाजित है।

पीएस के तहत, 5.1


3
2017-08-19 14:06





मैंने Invoke-Expression cmdlet का उपयोग करने के स्वीकार्य समाधान की कोशिश की लेकिन यह मेरे लिए काम नहीं किया क्योंकि मेरे तर्कों पर उनकी जगह थी। मैंने तर्कों का विश्लेषण करने और रिक्त स्थान से बचने की कोशिश की लेकिन मैं इसे ठीक से काम नहीं कर सका और यह भी मेरी राय में एक गंदे काम था। तो कुछ प्रयोग करने के बाद, समस्या पर मेरा लेना यह है:

function Invoke-Script
{
    param
    (
        [Parameter(Mandatory = $true)]
        [string]
        $Script,

        [Parameter(Mandatory = $false)]
        [object[]]
        $ArgumentList
    )

    $ScriptBlock = [Scriptblock]::Create((Get-Content $Script -Raw))
    Invoke-Command -NoNewScope -ArgumentList $ArgumentList -ScriptBlock $ScriptBlock -Verbose
}

# example usage
Invoke-Script $scriptPath $argumentList

इस समाधान का एकमात्र दोष यह है कि आपको यह सुनिश्चित करने की आवश्यकता है कि आपकी स्क्रिप्ट में "स्क्रिप्ट" या "ArgumentList" पैरामीटर नहीं है।


2
2017-11-21 11:17





आप इसे SQL क्वेरी के रूप में निष्पादित कर सकते हैं। सबसे पहले, एक कमांड में अपना कमांड / एक्सप्रेशन और स्टोर बनाएं और निष्पादित करें / इनवॉक करें।

$command =  ".\yourExternalScriptFile.ps1" + " -param1 '$paramValue'"

यह बहुत आगे है, मुझे नहीं लगता कि इसे स्पष्टीकरण की आवश्यकता है। तो अब आपके आदेश को निष्पादित करने के लिए सेट है,

Invoke-Expression $command

मैं यहां अपवाद को पकड़ने की सिफारिश करता हूं


0
2017-08-03 10:19