diff --git a/reference/7/Microsoft.PowerShell.Core/About/about_Operators.md b/reference/7/Microsoft.PowerShell.Core/About/about_Operators.md index 98e0be42b09f..da00a63d3fbe 100644 --- a/reference/7/Microsoft.PowerShell.Core/About/about_Operators.md +++ b/reference/7/Microsoft.PowerShell.Core/About/about_Operators.md @@ -13,21 +13,20 @@ Describes the operators that are supported by PowerShell. ## Long description -An operator is a language element that you can use in a command or -expression. PowerShell supports several types of operators to help you -manipulate values. +An operator is a language element that you can use in a command or expression. +PowerShell supports several types of operators to help you manipulate values. ### Arithmetic Operators Use arithmetic operators (`+`, `-`, `*`, `/`, `%`) to calculate values in a -command or expression. With these operators, you can add, subtract, -multiply, or divide values, and calculate the remainder (modulus) of a -division operation. +command or expression. With these operators, you can add, subtract, multiply, +or divide values, and calculate the remainder (modulus) of a division +operation. The addition operator concatenates elements. The multiplication operator -returns the specified number of copies of each element. You can use -arithmetic operators on any .NET type that implements them, such as: `Int`, -`String`, `DateTime`, `Hashtable`, and Arrays. +returns the specified number of copies of each element. You can use arithmetic +operators on any .NET type that implements them, such as: `Int`, `String`, +`DateTime`, `Hashtable`, and Arrays. For more information, see [about_Arithmetic_Operators](about_Arithmetic_Operators.md). @@ -41,9 +40,9 @@ For more information, see [about_Assignment_Operators](about_Assignment_Operator ### Comparison Operators -Use comparison operators (`-eq`, `-ne`, `-gt`, `-lt`, `-le`, `-ge`) to -compare values and test conditions. For example, you can compare two string -values to determine whether they are equal. +Use comparison operators (`-eq`, `-ne`, `-gt`, `-lt`, `-le`, `-ge`) to compare +values and test conditions. For example, you can compare two string values to +determine whether they are equal. The comparison operators also include operators that find or replace patterns in text. The (`-match`, `-notmatch`, `-replace`) operators use regular @@ -63,9 +62,9 @@ For more information, see [about_Comparison_Operators](about_Comparison_Operator ### Logical Operators Use logical operators (`-and`, `-or`, `-xor`, `-not`, `!`) to connect -conditional statements into a single complex conditional. For example, you -can use a logical `-and` operator to create an object filter with two -different conditions. +conditional statements into a single complex conditional. For example, you can +use a logical `-and` operator to create an object filter with two different +conditions. For more information, see [about_Logical_Operators](about_logical_operators.md). @@ -81,9 +80,9 @@ For more information, see [about_Redirection](about_Redirection.md) ### Split and Join Operators -The `-split` and `-join` operators divide and combine substrings. The -`-split` operator splits a string into substrings. The `-join` operator -concatenates multiple strings into a single string. +The `-split` and `-join` operators divide and combine substrings. The `-split` +operator splits a string into substrings. The `-join` operator concatenates +multiple strings into a single string. For more information, see [about_Split](about_Split.md) and [about_Join](about_Join.md). @@ -97,15 +96,15 @@ For more information, see [about_Type_Operators](about_Type_Operators.md). ### Unary Operators -Use unary operators to increment or decrement variables or object -properties and to set integers to positive or negative numbers. For -example, to increment the variable `$a` from `9` to `10`, you type `$a++`. +Use unary operators to increment or decrement variables or object properties +and to set integers to positive or negative numbers. For example, to increment +the variable `$a` from `9` to `10`, you type `$a++`. ### Special Operators Special operators have specific use-cases that do not fit into any other -operator group. For example, special operators allow you to -run commands, change a value's data type, or retrieve elements from an array. +operator group. For example, special operators allow you to run commands, +change a value's data type, or retrieve elements from an array. #### Array subexpression operator `@( )` @@ -265,8 +264,8 @@ $job = Start-Job -ScriptBlock {Get-Process -Name pwsh} Receive-Job $job -Wait ``` -If you want to run multiple commands, each in their own background process -but all on one line, simply place `&` between and after each of the commands. +If you want to run multiple commands, each in their own background process but +all on one line, simply place `&` between and after each of the commands. For more information on PowerShell jobs, see [about_Jobs](about_Jobs.md). @@ -304,8 +303,8 @@ variables that the script creates are added to the current scope. > distinguish the dot from the dot (`.`) symbol that represents the current > directory. -In the following example, the Sample.ps1 script in the current directory is -run in the current scope. +In the following example, the Sample.ps1 script in the current directory is run +in the current scope. ```powershell . .\sample.ps1 @@ -313,9 +312,9 @@ run in the current scope. #### Format operator `-f` -Formats strings by using the format method of string objects. Enter the -format string on the left side of the operator and the objects to be -formatted on the right side of the operator. +Formats strings by using the format method of string objects. Enter the format +string on the left side of the operator and the objects to be formatted on the +right side of the operator. ```powershell "{0} {1,-10} {2:N}" -f 1,"hello",[math]::pi @@ -330,10 +329,10 @@ method and [Composite Formatting](/dotnet/standard/base-types/composite-formatti #### Index operator `[ ]` -Selects objects from indexed collections, such as arrays and hash tables. -Array indexes are zero-based, so the first object is indexed as `[0]`. For -arrays (only), you can also use negative indexes to get the last values. -Hash tables are indexed by key value. +Selects objects from indexed collections, such as arrays and hash tables. Array +indexes are zero-based, so the first object is indexed as `[0]`. For arrays +(only), you can also use negative indexes to get the last values. Hash tables +are indexed by key value. ``` PS> $a = 1, 2, 3 @@ -369,15 +368,35 @@ Once upon a time... #### Pipeline operator `|` -Sends ("pipes") the output of the command that precedes it to the command -that follows it. When the output includes more than one object (a -"collection"), the pipeline operator sends the objects one at a time. +Sends ("pipes") the output of the command that precedes it to the command that +follows it. When the output includes more than one object (a "collection"), the +pipeline operator sends the objects one at a time. ```powershell Get-Process | Get-Member Get-PSSnapin | Where-Object {$_.vendor -ne "Microsoft"} ``` +#### Pipeline chain operators `&&` and `||` + +> [!NOTE] +> This is an experimental feature. For more information see +> [about_Experimental_Features](about_Experimental_Features.md). + +Conditionally execute the right-hand side pipeline based on the success of the +left-hand side pipeline. + +```powershell +# If Get-Process successfully finds a process called notepad, +# Stop-Process -Name notepad is called +Get-Process notepad && Stop-Process -Name notepad +``` + +```powershell +# If npm install fails, the node_modules directory is removed +npm install || Remove-Item -Recurse ./node_modules +``` + #### Property dereferences operator `.` Accesses the properties and methods of an object. @@ -470,6 +489,8 @@ For more information, see [about_If](about_If.md). [about_Type_Operators](about_Type_Operators.md) +[about_Pipeline_Chain_Operators](about_Pipeline_Chain_Operators.md) + [about_Split](about_Split.md) [about_Join](about_Join.md) diff --git a/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md b/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md new file mode 100644 index 000000000000..3ed9d02e88c1 --- /dev/null +++ b/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md @@ -0,0 +1,317 @@ +--- +ms.date: 09/30/2019 +schema: 2.0.0 +locale: en-us +keywords: powershell,cmdlet +title: about_Pipeline_Chain_Operators +--- + +# About Pipeline Chain Operators + +## Short description + +Describes chaining pipelines with the `&&` and `||` operators in PowerShell. + +## Long description + +> [!NOTE] +> This is an experimental feature. For more information see +> [about_Experimental_Features](about_Experimental_Features.md). + +Beginning in PowerShell 7, PowerShell implements the `&&` and `||` operators to +conditionally chain pipelines. These operators are known in PowerShell as +*pipeline chain operators*, and are similar to +[AND-OR lists](https://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_09_03) +in POSIX shells like bash, zsh and sh, as well as +[conditional processing symbols](/previous-versions/windows/it-pro/windows-xp/bb490954(v=technet.10)#using-multiple-commands-and-conditional-processing-symbols) +in the Windows Command Shell (cmd.exe). + +The `&&` operator executes the right-hand pipeline, if the left-hand pipeline +succeeded. Conversely, the `||` operator executes the right-hand pipeline if +the left-hand pipeline failed. + +These operators use the `$?` and `$LASTEXITCODE` variables to determine if a +pipeline failed. This allows you to use them with native commands and not just +with cmdlets or functions. For example: + +```powershell +# Create an SSH key pair - if successful copy the public key to clipboard +ssh-keygen -t rsa -b 2048 && Get-Content -Raw ~\.ssh\id_rsa.pub | clip +``` + +### Examples + +#### Two successful commands + +```powershell +Write-Output 'First' && Write-Output 'Second' +``` + +```Output +First +Second +``` + +#### First command fails, causing second not to be executed + +```powershell +Write-Error 'Bad' && Write-Output 'Second' +``` + +```Output +Write-Error 'Bad' && Write-Output 'Second' : Bad ++ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException ++ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException +``` + +#### First command succeeds, so the second command is not executed + +```powershell +Write-Output 'First' || Write-Output 'Second' +``` + +```Output +First +``` + +#### First command fails, so the second command is executed + +```powershell +Write-Error 'Bad' || Write-Output 'Second' +``` + +```Output +Write-Error 'Bad' && Write-Output 'Second' : Bad ++ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException ++ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException + +Second +``` + +Pipeline success is defined by the value of the `$?` variable, which PowerShell +automatically sets after executing a pipeline based on its execution status. +This means that pipeline chain operators have the following equivalence: + +```powershell +Test-Command '1' && Test-Command '2' +``` + +works the same as + +```powershell +Test-Command '1'; if ($?) { Test-Command '2' } +``` + +and + +```powershell +Test-Command '1' || Test-Command '2' +``` + +works the same as + +```powershell +Test-Command '1'; if (-not $?) { Test-Command '2' } +``` + +### Assignment from pipeline chains + +Assigning a variable from a pipeline chain takes the concatenation of all the +pipelines in the chain: + +```powershell +$result = Write-Output '1' && Write-Output '2' +$result +``` + +```Output +1 +2 +``` + +If a script-terminating error is thrown during assignment from a pipeline +chain, the assignment does not succeed: + +```powershell +try +{ + $result = Write-Output 'Value' && $(throw 'Bad') +} +catch +{ + # Do nothing, just squash the error +} + +"Result: $result" +``` + +```Output +Result: +``` + +### Operator syntax and precedence + +Unlike other operators, `&&` and `||` operate on pipelines, rather than on +expressions like `+` or `-and`, for example. + +`&&` and `||` have a lower precedence than piping (`|`) or redirection (`>`), +but a higher precedence than job operators (`&`), assignment (`=`) or +semicolons (`;`). This means that pipelines within a pipeline chain can be +individually redirected, and that entire pipeline chains can be backgrounded, +assigned to variables, or separated as statements. + +To use lower precedence syntax within a pipeline chain, +consider the use of parentheses `(...)` or a subexpression `$(...)`. +Note that enclosing an expression in parentheses or a subexpression +will set `$?` to true irrespective of the expression itself, +causing a different outcome in the pipeline chain. + +Like most other operators in PowerShell, `&&` and `||` are also *left-associative*, +meaning they group from the left. For example: + +```powershell +Get-ChildItem -Path ./file.txt || Write-Error "file.txt does not exist" && Get-Content -Raw ./file.txt +``` + +will group as: + +``` +[Get-ChildItem -Path ./file.txt || Write-Error "file.txt does not exist"] && Get-Content -Raw ./file.txt +``` + +being equivalent to: + +```powershell +Get-ChildItem -Path ./file.txt + +if (-not $?) { Write-Error "file.txt does not exist" } + +if ($?) { Get-Content -Raw ./file.txt } +``` + +### Error interaction + +Pipeline chain operators do not absorb errors. When a statement in a pipeline +chain throws a script-terminating error, the pipeline chain is terminated. + +For example: + +```powershell +$(throw 'Bad') || Write-Output '2' +``` + +```Output +Bad +At line:1 char:3 ++ $(throw 'Bad') || Write-Output '2' ++ ~~~~~~~~~~~ ++ CategoryInfo : OperationStopped: (Bad:String) [], RuntimeException ++ FullyQualifiedErrorId : Bad +``` + +Even when the error is caught, the pipeline chain is still terminated: + +```powershell +try +{ + $(throw 'Bad') || Write-Output '2' +} +catch +{ + Write-Output "Caught: $_" +} +Write-Output 'Done' +``` + +```Output +Caught: Bad +Done +``` + +If an error is non-terminating, or only terminates a pipeline, the pipeline +chain continues, respecting the value of `$?`: + +```powershell +function Test-NonTerminatingError +{ + [CmdletBinding()] + param() + + $exception = [System.Exception]::new('BAD') + $errorId = 'BAD' + $errorCategory = 'NotSpecified' + + $errorRecord = [System.Management.Automation.ErrorRecord]::new($exception, $errorId, $errorCategory, $null) + + $PSCmdlet.WriteError($errorRecord) +} + +Test-NonTerminatingError || Write-Output 'Second' +``` + +```Output +Test-NonTerminatingError : BAD +At line:1 char:1 ++ Test-NonTerminatingError || Write-Output 'Second' ++ ~~~~~~~~~~~~~~~~~~~~~~~~ ++ CategoryInfo : NotSpecified: (:) [Test-NonTerminatingError], Exception ++ FullyQualifiedErrorId : BAD,Test-NonTerminatingError + +Second +``` + +### Chaining pipelines rather than commands + +Pipeline chain operators, by their name, can be used to chain pipelines, rather +than just commands. This matches the behavior of other shells, but can make +*success* harder to determine: + +```powershell +function Test-NotTwo +{ + [CmdletBinding()] + param( + [Parameter(ValueFromPipeline)] + $Input + ) + + process + { + if ($Input -ne 2) + { + return $Input + } + + $exception = [System.Exception]::new('Input is 2') + $errorId = 'InputTwo' + $errorCategory = 'InvalidData' + + $errorRecord = [System.Management.Automation.ErrorRecord]::new($exception, $errorId, $errorCategory, $null) + + $PSCmdlet.WriteError($errorRecord) + } +} + +1,2,3 | Test-NotTwo && Write-Output 'All done!' +``` + +```Output +1 +Test-NotTwo : Input is 2 +At line:1 char:9 ++ 1,2,3 | Test-NotTwo && Write-Output 'All done!' ++ ~~~~~~~~~~~ ++ CategoryInfo : InvalidData: (:) [Test-NotTwo], Exception ++ FullyQualifiedErrorId : InputTwo,Test-NotTwo + +3 +``` + +Note that `Write-Output 'All done!'` is not executed, since `Test-NotTwo` is +deemed to have failed after throwing the non-terminating error. + +## See also + +- [about_Operators](about_Operators.md) +- [about_Automatic_Variables](about_Automatic_Variables.md) +- [about_pipelines](about_pipelines.md)