Hoe geef ik meerdere parameters door aan een functie in PowerShell?

Als ik een functie heb die meer dan één stringparameter accepteert, lijkt het alsof de eerste parameter alle gegevens krijgt die eraan zijn toegewezen, en de overige parameters worden als leeg doorgegeven.

Een snel testscript:

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

De gegenereerde uitvoer is

$arg1 value: ABC DEF
$arg2 value: 

De juiste uitvoer moet zijn:

$arg1 value: ABC
$arg2 value: DEF

Dit lijkt consistent te zijn tussen v1 en v2 op meerdere machines, dus het is duidelijk dat ik iets verkeerd doe. Kan iemand aangeven wat precies?


Antwoord 1, autoriteit 100%

Parameters in aanroepen van functies in PowerShell (alle versies) zijn gescheiden door spaties, niet door komma’s gescheiden. De haakjes zijn ook volledig overbodig en veroorzaken een parseerfout in PowerShell 2.0 (of hoger) als Set-StrictMode-Version 2of hoger is actief. Argumenten tussen haakjes worden alleen gebruikt in .NET-methoden.

function foo($a, $b, $c) {
   "a: $a; b: $b; c: $c"
}
ps> foo 1 2 3
a: 1; b: 2; c: 3

Antwoord 2, autoriteit 47%

Het juiste antwoord is al gegeven, maar dit probleem lijkt wijdverbreid genoeg om wat aanvullende details te rechtvaardigen voor diegenen die de subtiliteiten willen begrijpen.

Ik zou dit alleen als opmerking hebben toegevoegd, maar ik wilde een illustratie toevoegen – ik heb dit van mijn snelle referentiegrafiek over PowerShell-functies gescheurd. Dit veronderstelt dat de handtekening van functie f f($a, $b, $c)is:

Syntaxisvalkuilen van een functieaanroep

Zo kan men een functie aanroepen met door spaties gescheiden positioneleparameters of orderonafhankelijke benoemdeparameters. De andere valkuilen laten zien dat je op de hoogte moet zijn van komma’s, haakjes, enwitruimte.

Zie voor meer informatie mijn artikel Down the Rabbit Hole: een onderzoek naar PowerShell-pijpleidingen, functies en parameters. Het artikel bevat ook een link naar de snelle referentie/muurkaart.


Antwoord 3, autoriteit 10%

Er zijn hier enkele goede antwoorden, maar ik wilde op een paar andere dingen wijzen. Functieparameters zijn eigenlijk een plek waar PowerShell uitblinkt. U kunt bijvoorbeeld benoemde of positionele parameters hebben in geavanceerde functies, zoals:

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

Dan zou je het ofwel kunnen aanroepen door de parameternaam op te geven, of je zou gewoon positionele parameters kunnen gebruiken, aangezien je ze expliciet hebt gedefinieerd. Dus een van deze zou werken:

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

Het eerste voorbeeld werkt ook al wordt Nameals tweede gegeven, omdat we expliciet de parameternaam hebben gebruikt. Het tweede voorbeeld werkt echter op basis van positie, dus Namezou de eerste moeten zijn. Waar mogelijk probeer ik altijd posities te definiëren, zodat beide opties beschikbaar zijn.

PowerShell heeft ook de mogelijkheid om parametersets te definiëren. Het gebruikt dit in plaats van overbelasting van de methode, en nogmaals, het is best handig:

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
    )
}

Nu zal de functie een naam of een id aannemen, maar niet beide. U kunt ze positioneel of op naam gebruiken. Omdat ze van een ander type zijn, zal PowerShell het uitzoeken. Dus al deze zouden werken:

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

U kunt ook extra parameters aan de verschillende parametersets toewijzen. (Dat was natuurlijk een vrij eenvoudig voorbeeld.) Binnen de functie kun je bepalen welke parameterset is gebruikt met de eigenschap $PsCmdlet.ParameterSetName. Bijvoorbeeld:

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

Vervolgens is er ook nog parametervalidatie in PowerShell. Dit is een van mijn favoriete PowerShell-functies en het maakt de code in je functies erg schoon. Er zijn talloze validaties die u kunt gebruiken. Een paar voorbeelden zijn:

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

In het eerste voorbeeld accepteert ValidatePattern een reguliere expressie die ervoor zorgt dat de opgegeven parameter overeenkomt met wat u verwacht. Als dit niet het geval is, wordt er een intuïtieve uitzondering gegenereerd die u precies vertelt wat er mis is. Dus in dat voorbeeld zou ‘Iets’ prima werken, maar ‘Zomer’ zou de validatie niet doorstaan.

ValidateRange zorgt ervoor dat de parameterwaarde binnen het bereik ligt dat u verwacht voor een geheel getal. Dus 10 of 99 zou werken, maar 101 zou een uitzondering veroorzaken.

Een andere nuttige is ValidateSet, waarmee u expliciet een reeks acceptabele waarden kunt definiëren. Als er iets anders wordt ingevoerd, wordt een uitzondering gegenereerd. Er zijn ook andere, maar waarschijnlijk de meest bruikbareis ValidateScript. Hiervoor is een scriptblok nodig dat moet worden geëvalueerd naar $true, dus de lucht is de limiet. Bijvoorbeeld:

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

In dit voorbeeld zijn we er zeker van dat $Path niet alleen bestaat, maar dat het een bestand is (in tegenstelling tot een map) en de extensie .csv heeft. ($_ verwijst naar de parameter, wanneer deze zich in je scriptblok bevindt.) Je kunt ook veel grotere scriptblokken met meerdere regels invoeren als dat niveau vereist is, of meerdere scriptblokken gebruiken zoals ik hier deed. Het is buitengewoon handig en zorgt voor mooie schone functies en intuïtieve uitzonderingen.


Antwoord 4, autoriteit 8%

Je roept PowerShell-functies aan zonder de haakjes en zonder de komma als scheidingsteken te gebruiken. Probeer het gebruik van:

test "ABC" "DEF"

In PowerShell is de komma (,) een array-operator, bijvoorbeeld

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

Het stelt $ain op een array met drie waarden.


Antwoord 5, autoriteit 3%

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

Antwoord 6, autoriteit 2%

Als je een C# / Java / C++ / Ruby / Python / Pick-A-Language-From-This-Century-ontwikkelaar bent en je wilt je functie met komma’s aanroepen, omdat je dat altijd hebt gedaan, je hebt zoiets als dit nodig:

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

Nu bellen:

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

en je zult zien

arg1 = ABC, and arg2 = DEF

Antwoord 7, autoriteit 2%

Als u niet weet (of er niet om geeft) hoeveel argumenten u aan de functie wilt doorgeven, kunt u ook een heel eenvoudige benadering gebruiken, zoals;

Code:

function FunctionName()
{
    Write-Host $args
}

Dat zou alle argumenten uitprinten. Bijvoorbeeld:

FunctionName a b c 1 2 3

Uitvoer

a b c 1 2 3

Ik vind dit vooral handig bij het maken van functies die externe commando’s gebruiken die veel verschillende (en optionele) parameters kunnen hebben, maar die op dat commando vertrouwen om feedback te geven over syntaxisfouten, enz.

Hier is nog een voorbeeld uit de praktijk (een functie maken voor het tracert-commando, waarvan ik er een hekel aan heb om de afgekapte naam te onthouden);

Code:

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

Antwoord 8

Omdat dit een veelgestelde vraag is, wil ik vermelden dat een PowerShell-functie goedgekeurde werkwoorden(Verb-Nounals functienaam).
Het werkwoordgedeelte van de naam identificeert de actie die de cmdlet uitvoert. Het zelfstandig naamwoord deel van de naam identificeert de entiteit waarop de actie wordt uitgevoerd. Deze regel vereenvoudigthet gebruik van uw cmdlets voor geavanceerde PowerShell-gebruikers.

U kunt ook dingen specificeren zoals of de parameter verplichtis en de positievan de parameter:

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"
}

Om de parameter aan de functie door te geven, kunt u de positiegebruiken:

Test-Script "Hello" "World"

Of u specificeertde parameter naam:

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

Je gebruikt geen haakjeszoals je doet wanneer je een functie aanroept in C#.


Ik zou aanraden om altijdde parameternamen door te geven als je meer dan één parameter gebruikt, omdat dit leesbaarderis.


Antwoord 9

Als je het probeert:

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

je krijgt:

$arg1 value: ABC GHI
$arg2 value: DEF

Je ziet dus dat de haakjes de parameters van elkaar scheiden


Als je het probeert:

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

je krijgt:

$arg1 value: ABC
$arg2 value: DEF

Nu zou je direct het nut van de haakjes kunnen vinden – een spatie wordt geen scheidingsteken voor de volgende parameter – in plaats daarvan heb je een eval-functie.


Antwoord 10

Ik weet niet wat je met de functie doet, maar kijk eens naar het gebruik van het trefwoord ‘param’. Het is een stuk krachtiger voor het doorgeven van parameters aan een functie en maakt het gebruiksvriendelijker. Hieronder staat een link naar een te ingewikkeld artikel van Microsoft hierover. Het is niet zo ingewikkeld als het artikel het doet klinken.

Paramgebruik

Hier is ook een voorbeeld van een vraagop deze site:

Bekijk het.


Antwoord 11

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

Antwoord 12

Ik heb eerder het volgende gezegd:

Het veelvoorkomende probleem is het gebruik van de enkelvoudsvorm $arg, wat niet klopt. Het moet altijd meervoud zijn als $args.

Het probleem is niet dat. In feite kan $argiets anders zijn. Het probleem was het gebruik van de komma en de haakjes.

Ik voer de volgende code uit die werkte en de uitvoer volgt:

Code:

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

Test “ABC” “DEF”

Uitvoer:

$var1 value: ABC
$var2 value: DEF

Antwoord 13

Function Test {
    Param([string]$arg1, [string]$arg2)
    Write-Host $arg1
    Write-Host $arg2
}

Dit is een correcte params-declaratie.

Zie about_Functions_Advanced_Parameters.

En het werkt inderdaad.


Antwoord 14

Ik zie het hier niet vermeld, maar splattinguw argumenten is een nuttig alternatief en wordt vooral handig als u de argumenten dynamisch aan een opdracht toevoegt (in tegenstelling tot het gebruik van Invoke-Expression). U kunt splatten met arrays voor positionele argumenten en hashtabellen voor benoemde argumenten. Hier zijn enkele voorbeelden:

Splat met arrays (positieargumenten)

Testverbinding met positionele argumenten

Test-Connection www.google.com localhost

Met array-splatting

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

Houd er rekening mee dat we bij splatting naar de splatted-variabele verwijzen met een @in plaats van een $. Het is hetzelfde als je een hashtabel gebruikt om ook te splatten.

Splat met hashtabel (benoemde argumenten)

Test-verbinding met benoemde argumenten

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

Met hashtable splatting

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

Splat positionele en benoemde argumenten tegelijkertijd

Testverbinding met zowel positionele als benoemde argumenten

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

Array en hashtabellen samen splatten

$argumentHash = @{
  Count = 1
}
$argumentArray = 'www.google.com', 'localhost'
Test-Connection @argumentHash @argumentArray

Antwoord 15

U kunt parametersook doorgeven in een functiezoals deze:

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

LEAVE A REPLY

Please enter your comment!
Please enter your name here

9 − 1 =

Other episodes