Skip to content

Commit 5f70229

Browse files
committed
main
1 parent 6cf07b7 commit 5f70229

File tree

7 files changed

+204
-40
lines changed

7 files changed

+204
-40
lines changed

docs/document/Powershell/docs/File System/Units of Size.md renamed to docs/document/Powershell/docs/File System/File Size.md

File renamed without changes.

docs/document/Powershell/docs/Language/Control Flow.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ gci `
3131
> [!TIP]
3232
> Stop using backticks! They're ugly! Use hashtable splatting instead.
3333
>```ps1
34-
>$table = {
34+
>$table = @{
3535
> Filter = '*.mp4';
3636
> File = $true
3737
>}
38-
>gci -file @table
38+
>gci @table
3939
>```
4040
4141
## Multi-Line Piping

docs/document/Powershell/docs/Language/Function.md

Lines changed: 63 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -101,16 +101,6 @@ Foo -Foo foo -Bar bar
101101
Foo foo bar # it's the same # [!code highlight]
102102
```
103103

104-
### Default Parameter
105-
106-
```ps1
107-
function Foo {
108-
param (
109-
[string]$foo = "foo"
110-
)
111-
}
112-
```
113-
114104
### Flags
115105

116106
Defining flags that represents a toggle needs a special type called `switch`.
@@ -135,6 +125,32 @@ Manual assignment is also available:
135125
Foo -f:$false -b $true
136126
```
137127

128+
### Default Parameter
129+
130+
- Explicitly typed parameters can have implicit default value.
131+
- `switch` and `bool` is `$false` by default.
132+
- `string` is `[string]::Empty` by default.
133+
- Numeric types are zero value by default.
134+
- Parameters without type annotation are always typed as `object` which has the default value `$null`.
135+
- Can override default value by `=` in declaration.
136+
137+
```ps1
138+
139+
& { param([string]$name) $name -eq [string]::Empty } # True
140+
& { param($name) $name -eq $null } # True
141+
& { param([int]$age) $age -eq 0 } # True
142+
& { param([switch]$is) $is -eq $false } # True
143+
144+
function Foo {
145+
param (
146+
[string]$foo = "foo"
147+
)
148+
}
149+
```
150+
151+
> [!NOTE]
152+
> For overriding default parameter outside the function, see [$PSDefaultParameterValues](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_parameters_default_values?view=powershell-7.4#long-description)
153+
138154
### Required Parameter
139155

140156
All parameters are optional by default. Use `[Parameter(Mandatory=$true)]` to mark it as required.
@@ -196,14 +212,49 @@ But things will explode when we're dealing with a pipeline input which might bri
196212
The pipeline mechanism is essentially based on the `Enumerator` so if we collect all items into a new collection as parameter value, it can be a huge performance issue.
197213
So named blocks are essentially to defined a shared process logic for each object in the pipeline input, and other logic like initializationa and finalization.
198214

199-
> [!NOTE]
200-
> When no named block were specified, `end` block is used to represent the whole logic of a simple function.
215+
- `begin`: state initializationa for the pipeline iteration.
216+
- `process`: logic for each pipeline iteration.
217+
- `end`: final action for the completed pipeline iteration.
218+
- `clean`: a `finally` block to execute clean up no matter what happens.(PowerShell 7.3+)
201219

202220
```ps1
203221
function Foo {
204222
begin {}
205223
process {}
206224
end {}
225+
clean {}
226+
}
227+
```
228+
229+
> [!NOTE]
230+
> When no named block were specified, `end` block is used to represent the whole logic of a simple function.
231+
>```ps1
232+
>function Foo {
233+
> end {
234+
> echo hello
235+
> }
236+
>}
237+
># equivalent to
238+
>function Foo {
239+
> echo hello
240+
>}
241+
>```
242+
243+
## Filter Function
244+
245+
Filter is a special kind of function that implicitly accepts pipeline to perform transformation(select) or filtering(where).
246+
Filter is useful when you need to reuse the same logic for unknown pipeline manipulations, reducing hard coding.
247+
248+
```ps1
249+
filter Foo {
250+
"$_" # can transform
251+
}
252+
253+
# equivalent to
254+
function Foo {
255+
process {
256+
"$_"
257+
}
207258
}
208259
```
209260

docs/document/Powershell/docs/Language/Invocation.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ Call operator `&` can be used for invoking one of the following:
99

1010
- Command without any option.
1111
- A `.ps1` script file
12+
- External executable
1213
- Script block
1314

14-
**`&` is awared of the context of current session, it does not start a new process.**
15-
16-
It's more like a system execution
15+
> [!NOTE]
16+
> **`&` is awared of the context of current session, it does not start a new process when executing.**
1717
1818
```ps1
1919
& 'gps'

docs/document/Powershell/docs/Object Manipulation/Object Members.md

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,35 @@
22

33
## Member Inspection
44

5+
### Inspect from Pipeline
6+
7+
`Get-Member` can insepct objects from a pipeline input, which means by iterating them one by one.
8+
59
> [!TIP]
610
> Use `gm` alias for `Get-Member`.
711
12+
**Only members from a unique type in that pipeline input enumeration will be collected as the result.**
13+
814
```ps1
9-
ls | Get-Member
15+
(gci -file | select -first 1 | gm).Length # 53
16+
(gci -dir | select -first 1 | gm).Length # 47
17+
# assuming current directory has both directory and file
18+
(gci | gm).Length # 53 + 47 = 100
1019
```
1120

12-
When inspecting an array of objects, `gm` only returns members for distinct types.
21+
The whole array returned from `Get-Member` is `object[]`, each item inside is a `MemberDefinition`
1322

1423
```ps1
15-
@(123, '123') | gm | select -ExpandProperty TypeName -Unique
16-
# System.Int32
17-
# System.String
18-
19-
(@('123', 123) | Get-Member).Length # 82
20-
(@('123', 123, 123) | Get-Member).Length # still 82
21-
24+
(gci | gm) -is [object[]] # True
25+
(gci | gm | select -first 1) -is [MemberDefinition] # True
2226
```
2327

24-
`Get-Member` returns a `MemberDefinition[]` or a `MemberDefinition` with following properties.
28+
### Inspect from Object
29+
30+
To treat a whole collection as the object to be inspected, do not pipe it, pass it to `-InputObject` instead.
2531

26-
```cs
27-
class MemberDefinition
28-
{
29-
public string Definition { get; } // expression or value or signature of the member
30-
public System.Management.Automation.PSMemberTypes MemberType { get; } // type of member
31-
public string Name { get; } // member name
32-
public string TypeName { get; } // fullname of type or return type of the member
33-
}
32+
```ps1
33+
gm -InputObject (gci -file) # TypeName: System.Object[]
3434
```
3535

3636
## Member Types

docs/document/Powershell/docs/Object Manipulation/Select.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,26 @@ $partner['Status'] # Poisoned
118118
> [!NOTE]
119119
> `-ExpandProperty` can only take one property.
120120
121+
### Calculated Property
122+
123+
`Select-Object` can generate new NoteProperty to the `PSCustomObject` returned by specifying a HashTable with following shape:
124+
- `Name`(or `N`, `Lable`, `L`): the name of the new property.
125+
- `Expression`(`E`): the calculation logic for the new property represented as a script block.
126+
127+
```ps1
128+
$person = @{
129+
FirstName = 'John'
130+
LastName = 'Smith'
131+
}
132+
133+
# return a new PSCustomObject that has FirstName, LastName and FullName.
134+
$person | select *, @{ Name = 'FullName'; Expression = { "$($_.FirstName) $($_.LastName)" } }
135+
```
136+
137+
> [!NOTE]
138+
> All selected properties from a HashTable will be regenerated as `NoteProperty`.
139+
> Those selected properties are essentially `Keys` of the HashTable, not real properties.
140+
121141
## Take a Count
122142

123143
`Select-Object` can also take specific count of items from a collection, from start or end.

docs/document/Powershell/docs/Understanding Pipeline.md

Lines changed: 98 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#
1+
# Understanding Pipeline
22

33
Overview of pipeline in powershell:
44

@@ -9,6 +9,7 @@ Overview of pipeline in powershell:
99
## Pipeline Parameter Binding
1010

1111

12+
1213
## How Cmdlet Accept Pipeline Input
1314

1415
There's two solution when a pipeline input comes in as a fallback:
@@ -29,10 +30,6 @@ spps -Name (gci -File | foreach Name)
2930
gci -File | spps
3031
```
3132

32-
33-
> [!WARNING]
34-
> If multiple matches exist on ByPropertyName solution, powershell throws an error since these paramters might not be allowed to be used together.
35-
3633
ByValue is always tried first, and then use ByPropertyName, or it finally throws.
3734
A parameter accepts pipeline input does not necessarily have both solutions, it can have at least one of them.
3835

@@ -54,3 +51,99 @@ $table = @{ Name = 'foo'; Age = 18 }
5451

5552
This is simply because these types are more likely to be treated as a whole object, even when dictionaries are `IEnumerable<KeyValuePair<,>>`.
5653

54+
55+
## Enumerate Pipeline Items
56+
57+
You can use `$input` to refer to the enumerator passed to the function. This is another way to access pipeline input items but with more control.
58+
Another option is use `$_` to represent the current item in `process` block, this is way more limited but commonly used.
59+
60+
- `$input` represents a enumerator for pipeline input in `process` block.
61+
- `$input` represents the whole collection for pipeline input in `end` block.
62+
- `$input` will be consumed after being used once in either `process` or `end`. Use `Reset` to get it back.
63+
- You can't use `$input` in both `process` and `end`.
64+
65+
### Access Current Item
66+
67+
`$input.Current` have to manually invoke `MoveNext` before you access `Current` in `process` block since it's not a `while` loop.
68+
69+
```ps1
70+
function Test {
71+
begin {
72+
$input -is [System.Collections.IEnumerator] # True
73+
}
74+
75+
process {
76+
# $input.Current before MoveNext in each iteration is always $null
77+
# How weird!
78+
$input.Current -eq $null # True because we haven't start the enumeration!
79+
$input.MoveNext() | Out-Null # [!code highlight]
80+
$input.Current -eq $null # False
81+
}
82+
}
83+
84+
1,2,3 | Test
85+
```
86+
87+
> [!WARNING]
88+
> Before you read the following content, please keep in mind that `$input` behaves slightly different from general `IEnumerator` for `Reset`.
89+
90+
`$input` itself is a wrapper of current item in `process` block, invoke `Reset` to get it back to current value.
91+
92+
```ps1
93+
function Test {
94+
process {
95+
96+
}
97+
}
98+
99+
1,2,3 | Test
100+
```
101+
102+
## Implicit Pipeline Input
103+
104+
Function can accepts pipeline input without any specific parameter.
105+
Inside the `process` block, `$_` represents the current object from the pipeline input.
106+
107+
```ps1
108+
function Test {
109+
process {
110+
$_ -is [System.IO.FileInfo] # True
111+
}
112+
}
113+
114+
gci -file | Test
115+
```
116+
117+
> [!NOTE]
118+
> `$_` is only available in `process` block.
119+
120+
## Explicit Pipeline Input
121+
122+
If you write a custom function that have one or more parameters accept pipeline input, what is going on inside?
123+
124+
- In `begin` block, there's no value assigned to each `ByPropertyName` parameter, they remain default.
125+
- In `process` block, each
126+
127+
```ps1
128+
function Foo {
129+
param (
130+
[Parameter(ValueFromPipelineByPropertyName)]
131+
[string]$Name
132+
[Parameter(ValueFromPipelineByPropertyName)]
133+
[string]$Length
134+
)
135+
136+
begin {
137+
$Name -eq [string]::Empty # True
138+
$Length -eq 0 # True
139+
}
140+
141+
process {
142+
$Name
143+
$Length
144+
}
145+
}
146+
147+
gci -file | Foo
148+
```
149+

0 commit comments

Comments
 (0)