Jak przekazać wartości logiczne do skryptu programu PowerShell z wiersza polecenia


104

Muszę wywołać skrypt PowerShell z pliku wsadowego. Jednym z argumentów skryptu jest wartość logiczna:

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -File .\RunScript.ps1 -Turn 1 -Unify $false

Polecenie kończy się niepowodzeniem z następującym błędem:

Cannot process argument transformation on parameter 'Unify'. Cannot convert value "System.String" to type "System.Boolean", parameters of this type only accept booleans or numbers, use $true, $false, 1 or 0 instead.

At line:0 char:1
+  <<<< <br/>
+ CategoryInfo          : InvalidData: (:) [RunScript.ps1], ParentContainsErrorRecordException <br/>
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,RunScript.ps1

Obecnie używam ciągu znaków do konwersji wartości boolowskiej w moim skrypcie. Ale jak mogę przekazać argumenty logiczne do programu PowerShell?

Odpowiedzi:


58

Wygląda na to, że program powershell.exe nie w pełni ocenia argumenty skryptu, gdy -Fileparametr jest używany. W szczególności $falseargument jest traktowany jako ciąg znaków, podobnie jak w poniższym przykładzie:

PS> function f( [bool]$b ) { $b }; f -b '$false'
f : Cannot process argument transformation on parameter 'b'. Cannot convert value 
"System.String" to type "System.Boolean", parameters of this type only accept 
booleans or numbers, use $true, $false, 1 or 0 instead.
At line:1 char:36
+ function f( [bool]$b ) { $b }; f -b <<<<  '$false'
    + CategoryInfo          : InvalidData: (:) [f], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,f

Zamiast używać -Filemożesz spróbować -Command, który oceni wywołanie jako skrypt:

CMD> powershell.exe -NoProfile -Command .\RunScript.ps1 -Turn 1 -Unify $false
Turn: 1
Unify: False

Jak sugeruje David , użycie argumentu przełączającego byłoby również bardziej idiomatyczne, upraszczając wywołanie, eliminując potrzebę jawnego przekazywania wartości boolowskiej:

CMD> powershell.exe -NoProfile -File .\RunScript.ps1 -Turn 1 -Unify
Turn: 1
Unify: True

6
Dla tych (jak ja), którzy muszą zachować parametr „-File” i nie mogą zmienić argumentu przełączającego, ale mają kontrolę nad wysyłanymi wartościami ciągu, najprostszym rozwiązaniem jest przekonwertowanie parametru na boolean using [System.Convert] :: ToBoolean ($ Unify); wartości ciągu muszą mieć wtedy wartość „True” lub „False”.
— Chris Haines

187

Bardziej przejrzystym zastosowaniem może być zamiast tego użycie parametrów przełącznika. Wtedy samo istnienie parametru Unify oznaczałoby, że został on ustawiony.

Tak jak to:

param (
  [int] $Turn,
  [switch] $Unify
)

21
To powinna być akceptowana odpowiedź. Aby pogłębić dyskusję, możesz ustawić wartość domyślną, jak każdy inny parametr, na przykład:[switch] $Unify = $false
— Mario Tacke

Przeoczyłem tę odpowiedź, ponieważ byłem pewien, że Boolean to najlepszy sposób. Nie jest. Przełącznik zawiera funkcjonalność wartości logicznej i zatrzymuje tego rodzaju błędy: „Nie można przekonwertować wartości„ False ”na typ„ System.Management.Automation.ParameterAttribute ”. Przełączniki działały dla mnie.
— TinyRacoon

2
@MarioTacke Jeśli nie określisz parametru switch podczas wywoływania skryptu, zostanie on automatycznie ustawiony na $false. Nie ma więc potrzeby jawnego ustawiania wartości domyślnej.
— doubleDown

Ta sugestia zadziałała bardzo dobrze; był w stanie zaktualizować jeden z parametrów z [bool] do [switch], co z powodzeniem umożliwiło mi przekazanie argumentu przez Harmonogram zadań.
— JustaDaKaje

12

To jest starsze pytanie, ale w rzeczywistości jest na nie odpowiedź w dokumentacji programu PowerShell. Miałem ten sam problem i tym razem RTFM faktycznie go rozwiązał. Prawie.

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_powershell_exe

Dokumentacja dotycząca parametru -File stwierdza, że ​​„W rzadkich przypadkach może być konieczne podanie wartości logicznej dla parametru przełącznika. Aby podać wartość logiczną parametru przełącznika w wartości parametru Plik, należy umieścić nazwę i wartość parametru w nawiasy klamrowe, takie jak: -File. \ Get-Script.ps1 {-All: $ False} "

Musiałem to napisać tak:

PowerShell.Exe -File MyFile.ps1 {-SomeBoolParameter:False}

Więc nie ma znaku „$” przed stwierdzeniem prawda / fałsz i to zadziałało dla mnie w PowerShell 4.0


1
Dziękuję za udostępnienie! Doskonale rozwiązał mój problem.
— Julia Schwarz

1
Wygląda na to, że odsyłacz w odpowiedzi miał zmienioną treść. Jednak znalazłem odpowiedź tutaj
— Slogmeister Extraordinaire

Aktualne łącze do dokumentacji about_powershell.exe lub po prostu zadzwonić powershell -h.
— Seth

Jestem zaskoczony, że to niezręczne obejście kiedykolwiek zadziałało - nie działa w programie Windows PowerShell w wersji 5.1 (ani z początkiem, ani bez niego $); Zauważ również, że nie jest to już konieczne w programie PowerShell Core . Poprosiłem o poprawienie dokumentacji; patrz github.com/MicrosoftDocs/PowerShell-Docs/issues/4964
— mklement0

11

Spróbuj ustawić typ parametru na [bool]:

param
(
    [int]$Turn = 0
    [bool]$Unity = $false
)

switch ($Unity)
{
    $true { "That was true."; break }
    default { "Whatever it was, it wasn't true."; break }
}

Ten przykład domyślne $Unitydo$false jeśli nie jest warunkiem wejścia.

Stosowanie

.\RunScript.ps1 -Turn 1 -Unity $false

1
Odpowiedź cesarza XLII i Twój komentarz dotyczący -Fileparametru powinny obejmować każdy aspekt pierwotnego pytania. Zostawię swoją odpowiedź, ponieważ ktoś może również uznać moją wskazówkę dotyczącą podania wartości domyślnej.
— Filburt

Dobra robota Filburt. Twoja odpowiedź sprawiła, że ​​sprawdziłem mój skrypt, który już domyślnie określił jako wymaganą wartość $ false (pisałem to kilka lat temu i zapomniałem o tym) - więc nie muszę nawet określać problematycznego parametru boolowskiego na wiersz poleceń teraz. Doskonale :)
— Zeek2

5

Myślę, że najlepszym sposobem na użycie / ustawienie wartości logicznej jako parametru jest użycie w skrypcie PS tak:

Param(
    [Parameter(Mandatory=$false)][ValidateSet("true", "false")][string]$deployApp="false"   
)

$deployAppBool = $false
switch($deployPmCmParse.ToLower()) {
    "true" { $deployAppBool = $true }
    default { $deployAppBool = $false }
}

Więc teraz możesz go używać w ten sposób:

.\myApp.ps1 -deployAppBool True
.\myApp.ps1 -deployAppBool TRUE
.\myApp.ps1 -deployAppBool true
.\myApp.ps1 -deployAppBool "true"
.\myApp.ps1 -deployAppBool false
#and etc...

Więc w argumentach z cmd możesz przekazać wartość logiczną jako prosty ciąg :).


2

W programie PowerShell parametry logiczne można zadeklarować, podając ich typ przed ich zmienną.

    function GetWeb() {
             param([bool] $includeTags)
    ........
    ........
    }

Możesz przypisać wartość, przekazując $ true | $ false

    GetWeb -includeTags $true

Po prostu przekazanie nazwanych argumentów wejściowych jawnie w ten sposób zadziałało. Dzięki Ahmed
— Steve Taylor

0

Aby podsumować i uzupełniać istniejące odpowiedzi , jak z Windows PowerShell v5.1 / PowerShell podstawowej 7.0.0-preview.4:

Odpowiedź Davida Mohundro słusznie wskazuje, że zamiast [bool]parametrów, których należy użyć[switch] parametrów w PowerShell , gdzie brak obecności w porównaniu z nazwą przełącznik ( -Unifyokreślony w porównaniu z nie określono) zakłada jej wartość , która sprawia, że oryginalny problem znika.


Jednak przy okazji możesz jeszcze zdać przełącznika wartość wyraźnie , szczególnie jeśli budowie wiersza polecenia programowo :


W programie PowerShell Core The oryginalny problem (opisany w odpowiedzi na cesarza XLII ) został ustalony .

To znaczy, aby $truejawnie przekazać [switch]parametr o nazwie -Unify, możesz teraz napisać:

pwsh -File .\RunScript.ps1 -Unify:$true  # !! ":" separates name and value, no space

Następujące wartości można stosować: $false, false,$true , true, ale pamiętać, że zdanie 0lub 1nie nie pracy.

Zwróć uwagę, jak nazwa przełącznika jest oddzielona od wartości :i nie może być między nimi żadnych spacji .

Uwaga: Jeśli deklarujesz [bool]parametr zamiast a [switch](czego generalnie nie powinieneś), musisz użyć tej samej składni; nawet jeśli-Unify $false powinno działać, obecnie nie - zobacz ten problem z GitHubem .


W Windows PowerShell , w oryginalnych problem nie ustąpi , i - biorąc pod uwagę, że Windows PowerShell nie jest już aktywnie rozwijany - jest mało prawdopodobne, aby uzyskać stałe.

  • Obejście sugerowane w odpowiedzi LarsWA - mimo że jest oparte na oficjalnym temacie pomocy w chwili pisania tego tekstu - nie działa w wersji 5.1

    • Ten problem z GitHubem wymaga poprawienia dokumentacji, a także zawiera polecenie testowe, które pokazuje nieskuteczność obejścia.
  • Używanie -Commandzamiast -Fileto jedyne skuteczne obejście :

:: # From cmd.exe
powershell -Command "& .\RunScript.ps1 -Unify:$true" 

Dzięki -Commandefektywnemu przekazaniu fragmentu kodu PowerShell , który jest następnie oceniany jak zwykle - i wewnątrz PowerShell przechodzi $truei $falsedziała (ale nie true i false, jak teraz jest również akceptowany z -File).

Ostrzeżenia :

  • Używanie -Commandmoże skutkować dodatkową interpretacją twoich argumentów, na przykład jeśli zawierają one $znaki. (z -Fileargumentami są literały ).

  • Użycie -Commandmoże skutkować innym kodem zakończenia .

Aby uzyskać szczegółowe informacje, zobacz tę odpowiedź i tę odpowiedź .


0

Coś podobnego miałem podczas przekazywania skryptu do funkcji za pomocą polecenia invoke. Uruchomiłem polecenie w pojedynczych cudzysłowach zamiast w podwójnych cudzysłowach, ponieważ staje się wtedy literałem ciągu.'Set-Mailbox $sourceUser -LitigationHoldEnabled $false -ElcProcessingDisabled $true';


0

Uruchamianie skryptów PowerShell na Linuksie z bash daje ten sam problem. Rozwiązałem to prawie tak samo, jak odpowiedź LarsWA:

Pracujący:

pwsh -f ./test.ps1 -bool:true

Nie działa:

pwsh -f ./test.ps1 -bool=1
pwsh -f ./test.ps1 -bool=true
pwsh -f ./test.ps1 -bool true
pwsh -f ./test.ps1 {-bool=true}
pwsh -f ./test.ps1 -bool=$true
pwsh -f ./test.ps1 -bool=\$true
pwsh -f ./test.ps1 -bool 1
pwsh -f ./test.ps1 -bool:1

-3

Możesz również użyć 0for Falselub 1for True. To faktycznie sugeruje, że w komunikacie o błędzie:

Nie można przetworzyć transformacji argumentów w parametrze „Unify”. Nie można przekonwertować wartości "System.String"na typ "System.Boolean", parametry tego typu przyjąć tylko wartości logicznych lub numerów, korzystanie $true, $false, 1 lub 0 zamiast.

Aby uzyskać więcej informacji, zapoznaj się z tym artykułem MSDN dotyczącym wartości logicznych i operatorów .


10
To nie działa. Oczekuje liczby całkowitej 1 lub 0, ale przepuszczenie jej -Fileinterpretuje ją jako łańcuch, więc kończy się niepowodzeniem z tym samym błędem.
— Erti-Chris Eelmaa

Ta odpowiedź jest błędna, ponieważ sugestia nie działa
— mjs
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.