मैं PowerShell में एक फ़ंक्शन में कई पैरामीटर कैसे पास करूं?


438

यदि मेरे पास एक फ़ंक्शन है जो एक से अधिक स्ट्रिंग पैरामीटर को स्वीकार करता है, तो पहला पैरामीटर ऐसा लगता है कि सभी डेटा इसे सौंपा गया है, और शेष पैरामीटर खाली के रूप में पारित किए गए हैं।

एक त्वरित परीक्षण स्क्रिप्ट:

Function Test([string]$arg1, [string]$arg2)
{
    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

Test("ABC", "DEF")

उत्पन्न उत्पादन है

$arg1 value: ABC DEF
$arg2 value: 

सही आउटपुट होना चाहिए:

$arg1 value: ABC
$arg2 value: DEF

यह कई मशीनों पर v1 और v2 के बीच सुसंगत प्रतीत होता है, इसलिए जाहिर है, मैं कुछ गलत कर रहा हूं। क्या कोई इंगित कर सकता है कि वास्तव में क्या है?


3
आप बस इस तरह से फोन करें:Test "ABC" "DEF"
रणदीप दत्ता

जवाबों:


576

PowerShell (सभी संस्करणों) में फ़ंक्शन के लिए कॉल में पैरामीटर अंतरिक्ष-अलग हैं, अल्पविराम अलग नहीं हैं । इसके अलावा, कोष्ठक पूरी तरह से अस्वाभाविक हैं और Set-StrictModeसक्रिय होने पर PowerShell 2.0 (या बाद में) में पार्स त्रुटि का कारण होगा । कोष्ठक तर्कों का उपयोग केवल .NET विधियों में किया जाता है।

function foo($a, $b, $c) {
   "a: $a; b: $b; c: $c"
}

ps> foo 1 2 3
a: 1; b: 2; c: 3

20
सबसे महत्वपूर्ण बात जो अंत में मेरे दिमाग में 'स्टिक' करने में मदद करती है, यह अंतिम वाक्य है: "पैरंट्साइज़्ड तर्कों का उपयोग केवल नेट मेथड में किया जाता है।"
एशले

1
मैं पैरेन्थेसिस और कॉमा को अलग करके उपयोग करना पसंद करता हूं .. क्या शक्तियां में ऐसा करना संभव है?
सैम यि

8
@samyi No. (1,2,3)किसी फ़ंक्शन को पास करना प्रभावी रूप से एक सरणी के रूप में माना जाता है; एक ही तर्क। यदि आप OO विधि शैली तर्क का उपयोग करना चाहते हैं, तो मॉड्यूल का उपयोग करें:$m = new-module -ascustomobject { function Add($x,$y) { $x + $y } }; $m.Add(1,1)
x0n

4
Powershellएक शेल लैंग्वेज है और शेल लैंग्वेज के लिए टोकन सेपरेटर के रूप में स्पेस का इस्तेमाल करना आम बात है। मैं यह नहीं कहूंगा Powershellयहाँ अलग किया जा रहा है, यह सही तरह अन्य सिस्टम डिफ़ॉल्ट के गोले के साथ कतार में है cmd, sh, bash, आदि
बेंडर महानतम

270

सही उत्तर पहले ही प्रदान किया जा चुका है, लेकिन सूक्ष्मता को समझने के इच्छुक लोगों के लिए कुछ अतिरिक्त विवरणों को वारंट करने के लिए यह मुद्दा काफी प्रचलित है।

मैंने इसे केवल एक टिप्पणी के रूप में जोड़ा होगा, लेकिन मैं एक चित्रण को शामिल करना चाहता था - मैंने पॉवरहेल फ़ंक्शन पर अपने त्वरित संदर्भ चार्ट को बंद कर दिया। यह माना जाता है कि फ़ंक्शन f का हस्ताक्षर है f($a, $b, $c):

फ़ंक्शन कॉल का सिंटैक्स नुकसान

इस प्रकार, कोई अंतरिक्ष-पृथक स्थितीय मापदंडों या ऑर्डर-स्वतंत्र नामित मापदंडों के साथ एक फ़ंक्शन को कॉल कर सकता है । अन्य नुकसानों से पता चलता है कि आपको कॉमा, कोष्ठक, और सफेद स्थान का संज्ञान होना चाहिए ।

आगे पढ़ने के लिए, मेरा लेख डाउन द रैबिट होल: ए स्टडी इन पॉवरशेल पाइपलाइन, फ़ंक्शंस और पैरामीटर्स देखें । लेख में त्वरित संदर्भ / दीवार चार्ट के साथ-साथ लिंक भी है।


4
अधिक क्रिया वाक्यविन्यास के साथ स्पष्टीकरण प्रत्येक पैरामीटर को कॉल करता है और इसे एक मान प्रदान करता है जो वास्तव में इसे सीमेंट करता है। धन्यवाद!
कांस्टेंटाइनके

7
धन्यवाद, यह मुझे मानसिक रूप से समझ रहा था कि मैं क्या गलत कर रहा था। जब मैंने आखिरकार इसे सही किया तो मैं इस व्यवहार के स्पष्टीकरण के लिए भूखा था।
BSAFH

1
इसे उत्तर के रूप में पोस्ट करने के लिए धन्यवाद। यह जानना कि क्यों कुछ गलत करना उतना ही महत्वपूर्ण है जितना कि गलत।
गेविन वार्ड

4
यह एक बेहतर जवाब है। इसे और बढ़ाना चाहिए।
मार्क बर्टेनशॉ

53

यहाँ कुछ अच्छे उत्तर हैं, लेकिन मैं कुछ और बातें बताना चाहता था। फ़ंक्शन पैरामीटर वास्तव में एक जगह है जहां पावरशेल चमकता है। उदाहरण के लिए, आपके पास उन्नत कार्यों में या तो नाम या स्थितीय मानदंड हो सकते हैं:

function Get-Something
{
    Param
    (
         [Parameter(Mandatory=$true, Position=0)]
         [string] $Name,
         [Parameter(Mandatory=$true, Position=1)]
         [int] $Id
    )
}

तब आप या तो पैरामीटर नाम निर्दिष्ट करके इसे कॉल कर सकते थे, या आप केवल स्थितीय मापदंडों का उपयोग कर सकते थे, क्योंकि आपने उन्हें स्पष्ट रूप से परिभाषित किया था। तो इनमें से कोई भी काम करेगा:

Get-Something -Id 34 -Name "Blah"
Get-Something "Blah" 34

पहला उदाहरण काम करता है भले ही Nameदूसरा प्रदान किया गया हो, क्योंकि हमने स्पष्ट रूप से पैरामीटर नाम का उपयोग किया है। दूसरा उदाहरण स्थिति के आधार पर काम करता है, इसलिए Nameपहले होना आवश्यक है। जब संभव हो, मैं हमेशा पदों को परिभाषित करने की कोशिश करता हूं ताकि दोनों विकल्प उपलब्ध हों।

PowerShell में पैरामीटर सेट को परिभाषित करने की क्षमता भी है। यह विधि अधिभार के स्थान पर इसका उपयोग करता है, और फिर से काफी उपयोगी है:

function Get-Something
{
    [CmdletBinding(DefaultParameterSetName='Name')]
    Param
    (
         [Parameter(Mandatory=$true, Position=0, ParameterSetName='Name')]
         [string] $Name,
         [Parameter(Mandatory=$true, Position=0, ParameterSetName='Id')]
         [int] $Id
    )
}

अब फ़ंक्शन या तो एक नाम लेगा, या एक आईडी, लेकिन दोनों नहीं। आप उन्हें स्थिति में या नाम से उपयोग कर सकते हैं। चूंकि वे एक अलग प्रकार के हैं, इसलिए PowerShell यह पता लगाएगा। तो ये सभी काम करेंगे:

Get-Something "some name"
Get-Something 23
Get-Something -Name "some name"
Get-Something -Id 23

आप विभिन्न पैरामीटर सेट के लिए अतिरिक्त पैरामीटर भी असाइन कर सकते हैं। (यह स्पष्ट रूप से एक बहुत ही बुनियादी उदाहरण था।) फ़ंक्शन के अंदर, आप यह निर्धारित कर सकते हैं कि कौन सा पैरामीटर सेट $ PsCmdlet.ParameterSetName संपत्ति के साथ उपयोग किया गया था। उदाहरण के लिए:

if($PsCmdlet.ParameterSetName -eq "Name")
{
    Write-Host "Doing something with name here"
}

फिर, संबंधित पक्ष नोट पर, PowerShell में पैरामीटर सत्यापन भी है। यह मेरी पसंदीदा PowerShell सुविधाओं में से एक है, और यह आपके कार्यों के अंदर कोड को बहुत साफ करती है। आपके द्वारा उपयोग किए जा सकने वाले कई सत्यापन हैं। कुछ उदाहरण हैं:

function Get-Something
{
    Param
    (
         [Parameter(Mandatory=$true, Position=0)]
         [ValidatePattern('^Some.*')]
         [string] $Name,
         [Parameter(Mandatory=$true, Position=1)]
         [ValidateRange(10,100)]
         [int] $Id
    )
}

पहले उदाहरण में, ValidatePattern एक नियमित अभिव्यक्ति को स्वीकार करता है जो आपूर्ति किए गए पैरामीटर से आश्वासन देता है कि आप क्या अपेक्षा कर रहे हैं। यदि ऐसा नहीं होता है, तो एक सहज अपवाद को फेंक दिया जाता है, जो आपको बताता है कि क्या गलत है। तो उस उदाहरण में, 'समथिंग' ठीक काम करेगा, लेकिन 'समर' सत्यापन को पारित नहीं करेगा।

ValidateRange सुनिश्चित करता है कि पैरामीटर मान एक पूर्णांक के लिए अपेक्षित सीमा के बीच है। तो 10 या 99 काम करेगा, लेकिन 101 एक अपवाद फेंक देंगे।

एक अन्य उपयोगी वैलिडेटसेट है, जो आपको स्वीकार्य मूल्यों की एक सरणी को स्पष्ट रूप से परिभाषित करने की अनुमति देता है। यदि कुछ और दर्ज किया जाता है, तो एक अपवाद फेंक दिया जाएगा। वहाँ दूसरों के रूप में अच्छी तरह से कर रहे हैं, लेकिन शायद सबसे उपयोगी एक ValidateScript है। यह एक स्क्रिप्ट ब्लॉक लेता है जिसे $ सच्चे का मूल्यांकन करना चाहिए, इसलिए आकाश की सीमा है। उदाहरण के लिए:

function Get-Something
{
    Param
    (
         [Parameter(Mandatory=$true, Position=0)]
         [ValidateScript({ Test-Path $_ -PathType 'Leaf' })]
         [ValidateScript({ (Get-Item $_ | select -Expand Extension) -eq ".csv" })]
         [string] $Path
    )
}

इस उदाहरण में, हमें केवल $ पथ मौजूद नहीं होने का आश्वासन दिया गया है, लेकिन यह एक फ़ाइल है, (जैसा कि एक निर्देशिका के विपरीत है और इसमें एक .csv एक्सटेंशन है। ($ _ पैरामीटर को संदर्भित करता है, जब आपके स्क्रिप्टब्लॉक के अंदर होता है।) यदि आप उस स्तर की आवश्यकता है, तो आप बहुत बड़े, मल्टी-लाइन स्क्रिप्ट ब्लॉक में भी पास कर सकते हैं या कई स्क्रिप्टब्लॉक का उपयोग कर सकते हैं जैसे मैंने यहां किया था। यह अत्यंत उपयोगी है और अच्छे स्वच्छ कार्यों और सहज अपवादों के लिए बनाता है।


3
My_Function -NamedParamater "ParamValue"फ़ंक्शन कॉल शैली प्रदर्शित करने के लिए +1 । यह एक ऐसा पैटर्न है जिसे पठनीयता के लिए अधिक पीएस स्क्रिप्ट कोड का पालन करना चाहिए।
Mister_Tom

46

आप PowerShell फ़ंक्शन को कोष्ठक के बिना और अल्पविराम के बिना विभाजक के रूप में उपयोग करते हैं। प्रयोग करके देखें:

test "ABC" "DEF"

PowerShell में अल्पविराम (,) एक सरणी ऑपरेटर है, उदा

$a = "one", "two", "three"

यह $aतीन मानों के साथ एक सरणी पर सेट होता है।


16
Function Test([string]$arg1, [string]$arg2)
{
    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

Test "ABC" "DEF"

11

अगर आप C # / Java / C ++ / Ruby / Python / Pick-A-Language-From-This-Century डेवलपर हैं और आप अपने फ़ंक्शन को अल्पविराम से कॉल करना चाहते हैं, क्योंकि आपने हमेशा ऐसा किया है, तो आपको कुछ चाहिए इस तरह:

$myModule = New-Module -ascustomobject { 
    function test($arg1, $arg2) { 
        echo "arg1 = $arg1, and arg2 = $arg2"
    }
}

अब कॉल करें:

$myModule.test("ABC", "DEF")

और आप देखेंगे

arg1 = ABC, and arg2 = DEF

जावा, सी ++, रूबी, और पायथन इस सदी (केवल सी #) से नहीं हैं, जो ग्रेगोरियन कैलेंडर को मानते हैं (हालांकि कुछ दूसरों की तुलना में अधिक विकसित हुए हैं)।
पीटर मोर्टेंसन

हे। @PeterMortensen आपकी दलील यह है कि मुझे कहना चाहिए कि "इस सदी या पिछली एक भाषा को चुनें"? :-)
रयान

10

यदि आप नहीं जानते (या देखभाल) कि आप समारोह में कितने तर्क देंगे, तो आप भी बहुत सरल दृष्टिकोण का उपयोग कर सकते हैं;

कोड :

function FunctionName()
{
    Write-Host $args
}

यह सभी तर्कों को मुद्रित करेगा। उदाहरण के लिए:

FunctionName a b c 1 2 3

उत्पादन

a b c 1 2 3

मुझे यह विशेष रूप से उपयोगी लगता है जब ऐसे फ़ंक्शन बनाते हैं जो बाहरी आदेशों का उपयोग करते हैं जो कई अलग (और वैकल्पिक) पैरामीटर हो सकते हैं, लेकिन वाक्यविन्यास त्रुटियों पर प्रतिक्रिया प्रदान करने के लिए उक्त आदेश पर निर्भर करता है, आदि।

यहां एक और वास्तविक दुनिया का उदाहरण है (ट्रैसर्ट कमांड के लिए एक फ़ंक्शन बनाना, जिसे मुझे कटे हुए नाम को याद रखने से नफरत है);

कोड :

Function traceroute
{
    Start-Process -FilePath "$env:systemroot\system32\tracert.exe" -ArgumentList $args -NoNewWindow
}

7

अगर तुम कोशिश करो:

PS > Test("ABC", "GHI") ("DEF")

आपको मिला:

$arg1 value: ABC GHI
$arg2 value: DEF

तो आप देखते हैं कि कोष्ठक मापदंडों को अलग करता है


अगर तुम कोशिश करो:

PS > $var = "C"
PS > Test ("AB" + $var) "DEF"

आपको मिला:

$arg1 value: ABC
$arg2 value: DEF

अब आप कोष्ठकों की कुछ तात्कालिक उपयोगिता पा सकते हैं - एक स्थान अगले पैरामीटर के लिए विभाजक नहीं बनेगा - इसके बजाय आपके पास एक स्पष्ट कार्य है।


4
Parens अलग पैरामीटर नहीं है। वे सरणी को परिभाषित करते हैं।
n0rd

1
Parens एक सरणी को परिभाषित नहीं करते हैं, वे एक समूह को परिभाषित करते हैं, जो शक्तियां एक सरणी के रूप में व्याख्या कर सकती हैं। एरे को एक @प्रमुख चिन्ह से पहले एक संकेत ( ) के साथ परिभाषित किया जाता है , जैसे कि यह खाली सरणी @():; या यह संख्या दो संख्याओं के साथ @(1, 2):।
२०:१४ पर वर्टिगोरे

5

क्योंकि यह एक अक्सर देखा जाने वाला प्रश्न है, मैं यह उल्लेख करना चाहता हूं कि एक PowerShell फ़ंक्शन को स्वीकृत क्रियाओं ( क्रिया नाम के रूप में Verb-Noun ) का उपयोग करना चाहिए । नाम का क्रिया भाग उस क्रिया की पहचान करता है जो cmdlet करता है। नाम का संज्ञा भाग उस इकाई की पहचान करता है जिस पर कार्रवाई की जाती है। यह नियम उन्नत PowerShell उपयोगकर्ताओं के लिए आपके cmdlets के उपयोग को सरल करता है।

इसके अलावा, आप चीजों को निर्दिष्ट कर सकते हैं जैसे कि पैरामीटर अनिवार्य है और पैरामीटर की स्थिति :

function Test-Script
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$true, Position=0)]
        [string]$arg1,

        [Parameter(Mandatory=$true, Position=1)]
        [string]$arg2
    )

    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

फ़ंक्शन को पैरामीटर पास करने के लिए आप या तो स्थिति का उपयोग कर सकते हैं :

Test-Script "Hello" "World"

या आप पैरामीटर नाम निर्दिष्ट करते हैं :

Test-Script -arg1 "Hello" -arg2 "World"

आप कोष्ठकों का उपयोग नहीं करते की तरह तुम करते हो जब तुम सी # के भीतर एक समारोह कहते हैं।


मैं एक से अधिक पैरामीटर का उपयोग करते समय हमेशा पैरामीटर नामों को पारित करने की सलाह दूंगा, क्योंकि यह अधिक पठनीय है


FYI करें, स्वीकृत क्रिया सूची लिंक अब काम नहीं करता है, लेकिन अब यहाँ पाया जा सकता है - docs.microsoft.com/en-us/powershell/developer/cmdlet/…
कीथ लैंगमेड

@KeithLangmead धन्यवाद कीथ, मैंने अपना उत्तर भी अपडेट किया।
मार्टिन ब्रैंडल

1
"क्रिया-संज्ञा" क्रिया और संज्ञा दोनों के रूप में कैपिटल में है? शायद इसके बारे में अधिक स्पष्ट होने के लिए उत्तर बदलें?
पीटर मोर्टेंसन

@PeterMortensen उस उल्लेख के लिए धन्यवाद। मैंने अपना उत्तर अपडेट कर दिया।
मार्टिन ब्रैंडल

1
अच्छी तरह से, आप एक Get-Nodecmdlet बेनकाब पर विचार करें । यह हमारे लिए स्पष्ट होगा कि हमें आह्वान करना है Get-Node, नहीं Retrieve-Node, न ही Receive-Node, न ही .....
मार्टिन ब्रैंडल

4

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

परम उपयोग

इसके अलावा, इस साइट पर एक प्रश्न से एक उदाहरण है :

इसकी जांच - पड़ताल करें।


जवाब के लिए धन्यवाद। हालाँकि, मुझे फंक्शन को बुलाते समय समस्याएँ आ रही थीं। कोई बात नहीं अगर फ़ंक्शन को परम के साथ या इसके बिना घोषित किया गया था।
नासिर

3
Function Test([string]$arg1, [string]$arg2)
{
    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

Test("ABC") ("DEF")

परिणाम जैसा सामने आएगा वैसा ही होगा:

2

मैंने पहले कहा था:

सामान्य समस्या एकल रूप का उपयोग कर रही है $arg, जो गलत है। यह हमेशा की तरह बहुवचन होना चाहिए $args

समस्या यह नहीं है। वास्तव में, $argकुछ और भी हो सकता है। समस्या अल्पविराम और लघुकोष्ठक का उपयोग था।

मैं निम्नलिखित कोड चलाता हूं जो काम करता है और आउटपुट निम्न प्रकार है:

कोड:

Function Test([string]$var1, [string]$var2)
{
    Write-Host "`$var1 value: $var1"
    Write-Host "`$var2 value: $var2"
}

टेस्ट "एबीसी" "डीईएफ"

आउटपुट:

$var1 value: ABC
$var2 value: DEF

4
धन्यवाद, मेरे दोस्त, हालाँकि, आपको कुछ साल देर हो चुकी है :-) शीर्ष तीन जवाबों ने इस मुद्दे को पर्याप्त रूप से संबोधित किया था। क्या मुझे अनुत्तरित अनुभाग पर जाने और उन सवालों में से कुछ को आज़माने का सुझाव देना चाहिए?
नासिर


1

आप इस तरह से भी एक समारोह में मापदंडों को पारित कर सकते हैं:

function FunctionName()
{
    Param ([string]$ParamName);
    # Operations
}

3
यह एक फ़ंक्शन के लिए मापदंडों को परिभाषित करने वाला होगा, मूल प्रश्न यह था कि आप फ़ंक्शन को कॉल करते समय मापदंडों को कैसे निर्दिष्ट करें।
नासिर

1

मैं इसे यहाँ उल्लेख नहीं दिख रहा है, लेकिन splatting अपने तर्क एक उपयोगी विकल्प है और विशेष रूप से उपयोगी हो जाता है अगर आप बाहर तर्क एक कमांड को गतिशील रूप से (के रूप में प्रयोग करने के लिए विरोध का निर्माण कर रहे Invoke-Expression)। आप नामांकित तर्कों के लिए स्थितीय तर्कों और हैशटेबल्स के लिए सरणियों से बिखर सकते हैं। यहाँ कुछ उदाहरण हैं:

ऐरे के साथ स्प्लैट (स्थितिगत तर्क)

स्थिति-तर्क के साथ टेस्ट-कनेक्शन

Test-Connection www.google.com localhost

ऐरे स्प्लिटिंग के साथ

$argumentArray = 'www.google.com', 'localhost'
Test-Connection @argumentArray

ध्यान दें कि जब splatting, हम एक के @बजाय के साथ चपटा चर का संदर्भ देते हैं $। यह समान है जब एक हैशटेबल के रूप में अच्छी तरह से बिखरने का उपयोग किया जाता है।

हैशटेबल (नामित तर्क के साथ ब्याह)

नामित तर्क के साथ टेस्ट-कनेक्शन

Test-Connection -ComputerName www.google.com -Source localhost

हैशटेबल स्पलैटिंग के साथ

$argumentHash = @{
  ComputerName = 'www.google.com'
  Source = 'localhost'
}
Test-Connection @argumentHash

स्प्लैट पोजिशनल और नामित तर्क

टेस्ट-कनेक्शन दोनों स्थितीय और नामित तर्क के साथ

Test-Connection www.google.com localhost -Count 1

एक साथ ऐरे और हैशटैब को विभाजित करना

$argumentHash = @{
  Count = 1
}
$argumentArray = 'www.google.com', 'localhost'
Test-Connection @argumentHash @argumentArray
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.