Skip to content

Commit

Permalink
main
Browse files Browse the repository at this point in the history
  • Loading branch information
sharpchen committed Dec 3, 2024
1 parent 5f70229 commit 3810cd3
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 19 deletions.
2 changes: 0 additions & 2 deletions docs/document/Powershell/docs/1.Overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,3 @@
- All language syntax, pattern syntax and even strings are case-insensitive. (There's exception for file system on non-Windows platform)
- Everything is object, more than plain text in shell.
- Powershell formats the object value as a table if the object is not a primitive type. For primitive types, `Tostring()` will be used instead.
- Always handle both array and singular object.
- A powershell cmdlet always accepts an array or an single object as input parameter. And returns the result as an array or an object too.
101 changes: 94 additions & 7 deletions docs/document/Powershell/docs/Language/Array.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ $foo = @() # empty array

> [!NOTE]
> The default type of a array literal is `object[]`, you can annotate with a type.
> To create an empty array with fixed size, invoke `new()` constructor, this is also strongly typed.
> ```ps1
> [int[]]$foo = 1, 2, 3
> $bar = [int[]]::new(5)
> ```
> [!TIP]
Expand All @@ -28,17 +30,19 @@ $foo = @() # empty array
>```ps1
>(1,2,3).Length # 3
>
>$(1,2,3).Length # 3 this has different semantic but with same result
>
>(,(1,2,3)).Length # 3 # does spread items # [!code highlight]
>
>(,@(1,2,3)).Length # 1 # does not spread items # [!code highlight]
>
>((gci), (gci ..)).Length # 2 # [!code highlight]
> ```
### Collect from Expressions
### From Expression and Statement
`@()` actually collects from expressions, and all items from expressions will be flattened into a whole array.
So it can be another way to spread out arrays into one.
`@()` collects from expressions or statements like control flows that implicitly returns.
You can choose either flatten items from expressions or treat them as a sub-array.
- Use `;` to separate expressions for flatten arrays from them.
- Use `,` to separate expressions if you want them to be sub-array.
Expand All @@ -49,25 +53,54 @@ So it can be another way to spread out arrays into one.
@((ls), (ls ..)).Length # 2
@(ls; ls ..).Length # > 0
@(
if ($true) {
'yield this value to the array'
'yield this value again'
}
).Length # 2
```
## Access an Item
### From Enumerator

Powershell allows indexer syntax to access one or more items at a time.
Similar to expression, you can collect items from a `IEnumerator`.

```ps1
$foo = @{
Name = 'foo'
Age = 18
}
@($foo.GetEnumerator()).Length # 2, System.Collections.DictionaryEntry from the HashTable # [!code highlight]
```

## Access Item

Powershell allows indexer syntax to access one or more items at a time or use `Select-Object`.

```ps1
@(1,2,3)[0] # 1
@(1,2,3)[0, 2] # 1, 3
@(1,2,3) | select -index 1 # 2
@(1,2,3)[0, 1] # 1, 2 returns an array though
```

> [!NOTE]
> The default value of a array item is `$null`.
> Since it's a dynamic language, there's no error raised when index is out of the range.
## Concatenation

Generates new array from two concatenated.
Generates new array from two concatenated or with new item.

```ps1
((1,2,3) + (1,2,3)).Length # 6
(1,2,3) + 4 # 1,2,3,4
```

> [!NOTE]
> Can use `+=` when you operate on a array variable.
## Repetition

Use `*` to repeat the array content for certain times.
Expand All @@ -76,6 +109,12 @@ Use `*` to repeat the array content for certain times.
((1,2,3) * 3).Length # 9
```

A pratical usage of repetition is initialization with same value to the whole array.

```ps1
@(255) * 100 # Fill up array sized 100 with 255 to all elements
```

## Slicing

Use range operator to slice an array.
Expand Down Expand Up @@ -107,6 +146,54 @@ Separate different ranges by `+` to generate a range union.
(1..10)[0..2+4..5+7]
```

## Substration

To substract a collection from another collection, you can certainly use `LINQ` or use a simple pipeline.

```ps1
@(1,2,3) | where { @(1, 2) -notcontains $_ } # 3
```

## Null Checking

Checking null for collections is a quirk in PowerShell, `$arr -eq $null` checks all items instead of the whole array.

```ps1
$arr = 1,2,3
$arr -eq $null # empty array
$null -eq $arr # False, the result we expected # [!code highlight]
if ($arr) { 'array is not null and not empty' } # check both empty and null
```

## To List

PowerShell allows direct casting a array to an `ArrayList` or generic `List<T>`.

```ps1
using namespace System.Collections.Generic
[List[int]]@(1,2,3)
[System.Collections.ArrayList]@(1,2,3)
```

## Filtering & Transformation by Keyword Operators

Keyword operators has special functionalities on collections.
`-match`, `-notmatch`, `-replace`, `-split` handles for all items in the left operand collection, the result is always an array.

```ps1
# Returns items that matches the regex
@('John', 'Jane', 'Janet') -match 'Jane' # Jane, Janet.
(@('John', 'Jane', 'Janet') -notmatch 'Jane') -is [array] # True, only John matches and still an array.
@('John', 'Jane', 'Janet') -replace 'J','K' # Kohn Kane Kanet
'1,2,3','1,2,3' -split ',' # 1 2 3 1 2 3, strings
```

## Multi-Dim Array

You'll have to create Multi-Dim array from .NET type constructor only.
Expand Down
61 changes: 61 additions & 0 deletions docs/document/Powershell/docs/Language/HashTable.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,66 @@
# HashTable

HashTable is a dynamicly typed data structure in PowerShell, it implements `IDictionary` but is wrapped with the extended types system.
It's the native type and is unique to PowerShell itself.

```ps1
@{} -is [System.Collections.IDictionary] # True
```

## Creation

PowerShell has builtin syntax for creating a HashTable.
Inline declaration requires `;` to distinguish key-value pairs.

```ps1
$foo = @{
Name = 'foo'
Age = 18
}
$foo = @{ Name = 'foo'; Age = 18 }
```

### Ordered HashTable

`[ordered]` is a mark can be used when creating HashTable literal, it makes sure that all entries are ordered as in declaration and subsequent appending.

```ps1
([ordered]@{
C = 'C'
B = 'B'
A = 'A'
}).Keys # C B A
@{
C = 'C'
B = 'B'
A = 'A'
}.Keys # B C A
```

> [!NOTE]
> `[ordered]` can not be used as type, but it's indeed a `System.Collections.Specialized.OrderedDictionary`.
>```ps1
>([ordered]@{}).GetType().FullName # System.Collections.Specialized.OrderedDictionary
>```
## Access Values
You can access value of one or more keys by indexer.
```ps1
$foo['Name'] # foo
$foo['Name', 'Age'] # @('foo', 18)
```
`.` accessor would also works **as long as there's no duplicated Extended Property with the same name of the key you passed.**

```ps1
$foo.Name # foo
```

> [!TIP]
> Always use indexer to access value of a HashTable. `.` will prefer Extended Property that might be unexpected.
## Merging

```ps1
Expand Down
30 changes: 30 additions & 0 deletions docs/document/Powershell/docs/Language/String.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,40 @@ Use double `'` to escape `'` in a verbatim string.
> [!NOTE]
> See [about_Specical_Characters](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_special_characters?view=powershell-7.4)
## Arithmetic with Numerics

Powershell will try to convert the string on the right operand to the same type as left operand.
Exception will be raised if conversion failed.

```ps1
1 + '2' # 3
'2' + 1 # '21'
[DateTime]::Now + '00:00:15:00' # adds 15 minutes
```

## Split & Join

```ps1
'1,2,3' -split ',' # 1 2 3 as strings
(gci -file) -join ',' # ToString is invoked to evaluated objects to string.
```

## Match & Replace

```ps1
'Janet is a girl' -match 'Jane' # True
'Janet is a girl' -replace '^Janet', 'Jane'
```

## Format String

Template string syntax is the same as `C#`.
Standard numeric format like `:C`, `:X` are supported.

```ps1
'This is a {0} string' -f 'format'
```

## Repetition

Use `*` to repeat a string.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ The whole array returned from `Get-Member` is `object[]`, each item inside is a
### Inspect from Object

To treat a whole collection as the object to be inspected, do not pipe it, pass it to `-InputObject` instead.
Or magically wrap it as a single-item collection.

```ps1
gm -InputObject (gci -file) # TypeName: System.Object[]
,(gci -file) | gm
```

## Member Types
Expand Down
3 changes: 3 additions & 0 deletions docs/document/Powershell/docs/Type System/1.Overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Overview

- Intrinsic Members
27 changes: 17 additions & 10 deletions docs/document/Powershell/docs/Understanding Pipeline.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Overview of pipeline in powershell:



## How Cmdlet Accept Pipeline Input
## Pipeline Input Strategy

There's two solution when a pipeline input comes in as a fallback:

Expand All @@ -33,7 +33,7 @@ gci -File | spps
ByValue is always tried first, and then use ByPropertyName, or it finally throws.
A parameter accepts pipeline input does not necessarily have both solutions, it can have at least one of them.

## How PowerShell Enumerate Pipeline Input
## Pipeline Input as Enumerator

As we know, PowerShell can handle multiple objects from an enumerator from object that implements `IEnumerable` or `IEnumerable<T>`, or even duck typed with `GetEnumerator`.

Expand All @@ -43,28 +43,33 @@ While for types that are not linear collection, manually invoking `GetEnumerator
- HashTable has dynamic typing so we can't presume a uniformed calculation for our cmdlet
- `string` is `IEnumerable` but we surely don't expect the auto enumeration.

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

```ps1
$table = @{ Name = 'foo'; Age = 18 }
($table | measure).Count # 1
($table.GetEnumerator() | measure).Count # 2 # [!code highlight]
```

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


## Enumerate Pipeline Items

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.
You can use `$input` to refer to the enumerator passed to the function. This is one way to access pipeline input items but with more control.
Another option is use `$_` to represent the current item in `process` block, this is way more limited but commonly used.

> [!NOTE]
> `$_` and `$input` are isolated, they don't affects each other.
- `$input` represents a enumerator for pipeline input in `process` block.
- `$input` represents the whole collection for pipeline input in `end` block.
- `$input` will be consumed after being used once in either `process` or `end`. Use `Reset` to get it back.
- You can't use `$input` in both `process` and `end`.

### Access Current Item

`$input.Current` have to manually invoke `MoveNext` before you access `Current` in `process` block since it's not a `while` loop.
> We're not going to talk about `$_`, it's fairly simple. All the quirks is about `$input`.
`$input.Current` is `$null` by default, you'll have to manually invoke `MoveNext` before you access `Current` in `process` block since it's not a `while` loop.


```ps1
function Test {
Expand Down Expand Up @@ -122,7 +127,7 @@ gci -file | Test
If you write a custom function that have one or more parameters accept pipeline input, what is going on inside?

- In `begin` block, there's no value assigned to each `ByPropertyName` parameter, they remain default.
- In `process` block, each
- In `process` block, each `ByPropertyName` parameter represents the current property value extracted from the current pipeline input object.

```ps1
function Foo {
Expand All @@ -139,11 +144,13 @@ function Foo {
}
process {
$Name
$Length
$Name # Name of current pipeline item
$Length # Length of current pipeline item
}
}
gci -file | Foo
```

> [!TIP]
> `ByPropertyName` parameter can also be a array type, it all depends the implementation you want, it behaves the same.

0 comments on commit 3810cd3

Please sign in to comment.