├── .github ├── FUNDING.yml └── workflows │ └── powershell.yml ├── .gitignore ├── PowerFul Modules └── Pode │ ├── 01-public-examples.ps1 │ ├── 02-PasswordTool.ps1 │ ├── 03-passwordtool-videoexample.ps1 │ └── scripts │ └── password.ps1 ├── PowerShell Array └── PowerShell Array.ps1 ├── PowerShell Error Handling ├── 1-What causes error.ps1 ├── 2-Non terminating errors.ps1 ├── 3-Error Action preference.ps1 ├── 4-Error Handling with Try Catch.ps1 ├── 5-Try Finally.ps1 ├── 6-Investigating errors.ps1 ├── 7-typed exceptions.ps1 └── 8-application errors.ps1 ├── PowerShell Files └── Downloads │ └── PowerShell File Downloading.ps1 ├── PowerShell Function ├── Convert script into function │ ├── 1. Simple script.ps1 │ ├── 2. Script with parameters.ps1 │ ├── 3. Parameters and types.ps1 │ └── 4. Convert script into function.ps1 └── Parameters │ ├── 1Mandatory.ps1 │ ├── 2ParameterSetName.ps1 │ ├── 3Position.ps1 │ ├── 4ValueFromPipeline.ps1 │ ├── 5Validate.ps1 │ ├── 6Alias.ps1 │ └── data.psd1 ├── PowerShell Hashtable └── PowerShell Hashtable.ps1 ├── PowerShell Module ├── Building Module │ └── KpInfo │ │ ├── .gitignore │ │ ├── Install-Requirements.ps1 │ │ ├── README.md │ │ ├── Source │ │ ├── KpInfo.psd1 │ │ ├── Private │ │ │ └── Invoke-Request.ps1 │ │ └── Public │ │ │ ├── Get-CatFact.ps1 │ │ │ ├── Get-Quote.ps1 │ │ │ └── Get-Weather.ps1 │ │ └── Start-ModuleBuild.ps1 └── Module Manifest │ ├── cat.ps1 │ ├── mystuff.psd1 │ ├── mystuff.psm1 │ ├── quote.ps1 │ ├── weather.ps1 │ └── wrapper.ps1 ├── PowerShell PsCustomObject └── PowerShell PsCustomObject.ps1 ├── PowerShell Switch statement └── Powershell Switch statement.ps1 ├── PowerShell loops - For ├── PowerShell loops - For.ps1 └── for.drawio.png ├── Powershell If statement - controlling the flow of your code └── Powershell If statement.ps1 ├── README.md └── Shorts ├── Array ├── 1.ps1 ├── 2.ps1 ├── 3.ps1 └── 4.ps1 ├── For ├── 1.ps1 ├── 2.ps1 └── 3.ps1 ├── ForEach ├── 1.ps1 ├── 2.ps1 ├── 3.ps1 └── 4.ps1 ├── Generic-List ├── .vscode │ └── settings.json ├── 1.ps1 ├── 2.ps1 ├── 3.ps1 └── 4.ps1 ├── Help ├── 1.ps1 └── 2.ps1 ├── If ├── 1.ps1 ├── 2.ps1 └── 3.ps1 ├── Param ├── 1.ps1 ├── 2.ps1 ├── 3.ps1 └── 4.ps1 ├── Pipeline-User ├── 1.ps1 ├── 2.ps1 └── 3.ps1 └── Switch ├── 1.ps1 ├── 2.ps1 └── 3.ps1 /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [thekamilpro] 4 | buy_me_a_coffee: kamilpro 5 | patreon: # Replace with a single Patreon username 6 | open_collective: # Replace with a single Open Collective username 7 | ko_fi: # Replace with a single Ko-fi username 8 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 9 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 10 | liberapay: # Replace with a single Liberapay username 11 | issuehunt: # Replace with a single IssueHunt username 12 | otechie: # Replace with a single Otechie username 13 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 14 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 15 | -------------------------------------------------------------------------------- /.github/workflows/powershell.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | # 6 | # https://github.com/microsoft/action-psscriptanalyzer 7 | # For more information on PSScriptAnalyzer in general, see 8 | # https://github.com/PowerShell/PSScriptAnalyzer 9 | 10 | name: PSScriptAnalyzer 11 | 12 | on: 13 | push: 14 | branches: [ main ] 15 | pull_request: 16 | branches: [ main ] 17 | schedule: 18 | - cron: '25 15 * * 2' 19 | 20 | jobs: 21 | build: 22 | name: PSScriptAnalyzer 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v2 26 | 27 | - name: Run PSScriptAnalyzer 28 | uses: microsoft/psscriptanalyzer-action@2044ae068e37d0161fa2127de04c19633882f061 29 | with: 30 | # Check https://github.com/microsoft/action-psscriptanalyzer for more info about the options. 31 | # The below set up runs PSScriptAnalyzer to your entire repository and runs some basic security rules. 32 | path: .\ 33 | recurse: true 34 | # Include your own basic security rules. Removing this option will run all the rules 35 | includeRule: '"PSAvoidGlobalAliases", "PSAvoidUsingConvertToSecureStringWithPlainText"' 36 | output: results.sarif 37 | 38 | # Upload the SARIF file generated in the previous step 39 | - name: Upload SARIF results file 40 | uses: github/codeql-action/upload-sarif@v1 41 | with: 42 | sarif_file: results.sarif 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /PowerFul Modules/Pode/01-public-examples.ps1: -------------------------------------------------------------------------------- 1 | Import-Module -Name Pode, Pode.Web 2 | 3 | Start-PodeServer { 4 | Add-PodeEndpoint -Address localhost -Port 8080 -Protocol Http 5 | 6 | New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging -Levels @("Error", "Warning") 7 | New-PodeLoggingMethod -Terminal | Enable-PodeRequestLogging 8 | 9 | Use-PodeWebTemplates -Title 'Example' -Theme Dark 10 | 11 | $navDiv = New-PodeWebNavDivider 12 | $navPode = New-PodeWebNavLink -Name 'Pode' -Url 'https://badgerati.github.io/Pode/' -Icon 'help-circle' -NewTab 13 | $navPodeWeb = New-PodeWebNavLink -Name 'PodeWeb' -Url 'https://badgerati.github.io/Pode.Web/' -Icon 'help-circle' -NewTab 14 | $navYT = New-PodeWebNavLink -Name 'YouTube' -Url 'https://www.youtube.com/c/KamilPro' -Icon 'youtube' -NewTab 15 | $navGH = New-PodeWebNavLink -name 'GitHub' -Url 'https://github.com/kprocyszyn/About-PowerShell' -Icon 'github' -NewTab 16 | 17 | Set-PodeWebNavDefault -Items $navPode, $navDiv, $navPodeWeb, $navDiv, $navYT, $navDiv, $navGH 18 | 19 | Add-PodeWebPage -Name 'Services' -Icon 'Settings' -ScriptBlock { 20 | New-PodeWebContainer -Content @( 21 | New-PodeWebTable -Name 'Services' -DataColumn "Name" -SimpleFilter -ScriptBlock { 22 | foreach ($svc in (Get-Service)) { 23 | [ordered]@{ 24 | Name = $svc.Name 25 | Status = "$($svc.Status)" 26 | StartType = "$($svc.StartType)" 27 | Actions = @( 28 | New-PodeWebButton -Name 'Stop' -Icon 'Stop-Circle' -IconOnly -ScriptBlock { 29 | Stop-Service -Name ($WebEvent.Data.Value) -Force | Out-Null 30 | Show-PodeWebToast -Message "$($WebEvent.Data.Value) stopped" 31 | Sync-PodeWebTable -Id $ElementData.Parent.ID 32 | } 33 | New-PodeWebButton -Name 'Start' -Icon 'Play-Circle' -IconOnly -ScriptBlock { 34 | Start-Service -Name ($WebEvent.Data.Value) #| Out-Null 35 | Show-PodeWebToast -Message "$($WebEvent.Data.Value) started" 36 | Sync-PodeWebTable -Id $ElementData.Parent.ID 37 | } 38 | ) 39 | } 40 | } 41 | } 42 | ) 43 | } 44 | 45 | Add-PodeWebPage -Name 'Form' -ScriptBlock { 46 | New-PodeWebCard -Content @( 47 | New-PodeWebForm -Name 'Example' -ScriptBlock { 48 | $WebEvent.Data | Out-Default 49 | } -Content @( 50 | New-PodeWebTextbox -Name 'Name' -AutoComplete { 51 | return @('billy', 'bobby', 'alice', 'john', 'sarah', 'matt', 'zack', 'henry') 52 | } 53 | New-PodeWebTextbox -Name 'Password' -Type Password -PrependIcon Lock 54 | New-PodeWebTextbox -Name 'Date' -Type Date 55 | New-PodeWebTextbox -Name 'Time' -Type Time 56 | New-PodeWebDateTime -Name 'DateTime' -NoLabels 57 | New-PodeWebCredential -Name 'Credentials' -NoLabels 58 | New-PodeWebCheckbox -Name 'Checkboxes' -Options @('Terms', 'Privacy') -AsSwitch 59 | New-PodeWebRadio -Name 'Radios' -Options @('S', 'M', 'L') 60 | New-PodeWebSelect -Name 'Role' -Options @('User', 'Admin', 'Operations') -Multiple 61 | New-PodeWebRange -Name 'Cores' -Value 30 -ShowValue 62 | ) 63 | ) 64 | } 65 | 66 | Add-PodeWebPage -Name 'Processes' -ScriptBlock { 67 | New-PodeWebContainer -Content @( 68 | New-PodeWebChart -Name 'Top Processes' -Type Bar -AutoRefresh -ScriptBlock { 69 | Get-Process | 70 | Sort-Object -Property CPU -Descending | 71 | Select-Object -First 10 | 72 | ConvertTo-PodeWebChartData -LabelProperty ProcessName -DatasetProperty CPU, Handles 73 | } 74 | ) 75 | } 76 | } -------------------------------------------------------------------------------- /PowerFul Modules/Pode/02-PasswordTool.ps1: -------------------------------------------------------------------------------- 1 | Import-Module -Name Pode, Pode.Web 2 | Import-Module -Name "$PSScriptRoot\scripts\password.ps1" -Force 3 | 4 | Start-PodeServer { 5 | Add-PodeEndpoint -Address 0.0.0.0 -Port 8080 -Protocol Http -Force 6 | 7 | New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging -Levels @("Error", "Warning") 8 | 9 | Use-PodeWebTemplates -Title 'Passwords webapp' -Theme Dark 10 | 11 | $navDiv = New-PodeWebNavDivider 12 | $navPode = New-PodeWebNavLink -Name 'Pode' -Url 'https://badgerati.github.io/Pode/' -Icon 'server' -NewTab 13 | $navPodeWeb = New-PodeWebNavLink -Name 'PodeWeb' -Url 'https://badgerati.github.io/Pode.Web/' -Icon 'web-check' -NewTab 14 | $navYT = New-PodeWebNavLink -Name 'YouTube' -Url 'https://www.youtube.com/c/KamilPro' -Icon 'youtube' -NewTab 15 | $navGH = New-PodeWebNavLink -name 'GitHub' -Url 'https://github.com/kprocyszyn/About-PowerShell' -Icon 'github' -NewTab 16 | $navPwpush = New-PodeWebNavLink -name 'PwPush' -Url 'https://pwpush.com/' -Icon 'lock-check' -NewTab 17 | 18 | Set-PodeWebNavDefault -Items $navPode, $navDiv, $navPodeWeb, $navDiv, $navYT, $navDiv, $navGH, $navDiv, $navPwpush 19 | 20 | Add-PodeWebPage -Name 'Password Management' -NoTitle -ScriptBlock { 21 | New-PodeWebContainer -Content @( 22 | New-PodeWebForm -Name 'passwordform' -SubmitText "Generate Password" -ShowReset -ResetText "Reset form" -Content @( 23 | New-PodeWebRange -Name 'Length' -Min 12 -Max 100 -ShowValue -Value 30 24 | New-PodeWebCheckbox -Name 'Options' -Options @("upper", "lower", "numeric", "special") -DisplayOptions @("A-Z", "a-z", "0-9", "@#^&$") 25 | New-PodeWebTextbox -Name "secret" -DisplayName "Password" 26 | New-PodeWebTextbox -Name "Password link" -ReadOnly 27 | New-PodeWebButton -Name "Push password" -CssStyle @{"margin-bottom" = "0rem"} -ScriptBlock { 28 | if ( [string]::IsNullOrEmpty($WebEvent.Data.secret)) 29 | { 30 | Show-PodeWebToast -Message "Password field cannot be empty" -Title "Error" -Icon "alert-circle" 31 | return 32 | } 33 | $link = Submit-Password -text $WebEvent.Data.secret 34 | Update-PodeWebTextbox -Value $link -Name "Password link" 35 | } 36 | ) -ScriptBlock { 37 | 38 | if (!$WebEvent.Data.Options) 39 | { 40 | Show-PodeWebToast -Message "You must select at least one option" -Title "Error" 41 | } 42 | else 43 | { 44 | $np = New-Password -Data $WebEvent.Data 45 | Update-PodeWebTextbox -Value $np -Name "secret" 46 | } 47 | } 48 | ) 49 | } 50 | } -------------------------------------------------------------------------------- /PowerFul Modules/Pode/03-passwordtool-videoexample.ps1: -------------------------------------------------------------------------------- 1 | Import-Module -name pode, pode.web 2 | Import-Module -name "$PSScriptRoot\scripts\password.ps1" -force 3 | 4 | Start-PodeServer { 5 | 6 | Add-PodeEndpoint -Address 0.0.0.0 -Port 8080 -Protocol http -Force 7 | 8 | New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging -Levels @("Error", "Warning") 9 | 10 | Use-PodeWebTemplates -Title "Passwords webapp" -Theme Dark 11 | 12 | $navDiv = New-PodeWebNavDivider 13 | $navPode = New-PodeWebNavLink -Name 'Pode' -Url 'https://badgerati.github.io/Pode/' -Icon 'server' -NewTab 14 | $navPodeWeb = New-PodeWebNavLink -Name 'PodeWeb' -Url 'https://badgerati.github.io/Pode.Web/' -Icon 'web-check' -NewTab 15 | $navYT = New-PodeWebNavLink -Name 'YouTube' -Url 'https://www.youtube.com/c/KamilPro' -Icon 'youtube' -NewTab 16 | $navGH = New-PodeWebNavLink -name 'GitHub' -Url 'https://github.com/kprocyszyn/About-PowerShell' -Icon 'github' -NewTab 17 | $navPwpush = New-PodeWebNavLink -name 'PwPush' -Url 'https://pwpush.com/' -Icon 'lock-check' -NewTab 18 | 19 | Set-PodeWebNavDefault -Items $navPode, $navDiv, $navPodeWeb, $navDiv, $navYT, $navDiv, $navGH, $navDiv, $navPwpush 20 | 21 | Add-PodeWebPage -Name "Password management" -NoTitle -ScriptBlock { 22 | 23 | New-PodeWebContainer -Content @( 24 | New-PodeWebForm -Name "passwordform" -SubmitText "Generate Password" -ShowReset -ResetText "Reset form" -Content @( 25 | 26 | New-PodeWebRange -Name "Length" -Min 12 -Max 100 -ShowValue -Value 30 27 | New-PodeWebCheckbox -Name "Options" -Options @("upper", "lower", "numeric", "special") -DisplayOptions @("A-Z", "a-z", "0-9", "&^@") 28 | New-PodeWebTextbox -Name "secret" -DisplayName "Password" 29 | New-PodeWebTextbox -Name "Password Link" -ReadOnly 30 | New-PodeWebButton -Name "Push password" -CssStyle @{"margin-bottom" = "0rem"} -ScriptBlock { 31 | 32 | if ([string]::IsNullOrEmpty($WebEvent.Data.secret)) 33 | { 34 | Show-PodeWebToast "Password field cannot be empty" -Title "Error" 35 | return 36 | } 37 | $link = Submit-Password -text $WebEvent.Data.secret 38 | $link | Out-Default 39 | Update-PodeWebTextbox -Name "Password Link" -Value $link 40 | 41 | } 42 | 43 | ) -ScriptBlock { 44 | 45 | $WebEvent.Data | Out-Default 46 | 47 | if (!$WebEvent.Data.Options) 48 | { 49 | Show-PodeWebToast -Message "You must select an option" -Title "Error" 50 | } 51 | else 52 | { 53 | $np = New-Password -Data $WebEvent.Data 54 | Update-PodeWebTextBox -Value $np -Name "secret" 55 | } 56 | } 57 | ) 58 | } 59 | } -------------------------------------------------------------------------------- /PowerFul Modules/Pode/scripts/password.ps1: -------------------------------------------------------------------------------- 1 | function New-Password 2 | { 3 | param( 4 | [hashtable]$Data 5 | ) 6 | 7 | $params = @{ 8 | Length = $Data.Length 9 | upper = 0 10 | lower = 0 11 | numeric = 0 12 | special = 0 13 | } 14 | 15 | if ($Data.Options) 16 | { 17 | $options = $data.Options.Split(',') 18 | 19 | if ($options.Contains('upper')) 20 | { 21 | $params.upper = 1 22 | } 23 | 24 | if ($options.Contains('lower')) 25 | { 26 | $params.lower = 1 27 | } 28 | 29 | if ($options.Contains('numeric')) 30 | { 31 | $params.numeric = 1 32 | } 33 | 34 | if ($options.Contains('special')) 35 | { 36 | $params.special = 1 37 | } 38 | } 39 | 40 | return Get-RandomPassword @params 41 | } 42 | function Get-RandomPassword 43 | { 44 | #Script by: https://arminreiter.com/2021/07/3-ways-to-generate-passwords-in-powershell/ 45 | param ( 46 | [Parameter(Mandatory)] 47 | [ValidateRange(12, [int]::MaxValue)] 48 | [int] $length, 49 | [int] $upper = 0, 50 | [int] $lower = 0, 51 | [int] $numeric = 0, 52 | [int] $special = 0 53 | ) 54 | if ($upper + $lower + $numeric + $special -gt $length) 55 | { 56 | throw "number of upper/lower/numeric/special char must be lower or equal to length" 57 | } 58 | $uCharSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 59 | $lCharSet = "abcdefghijklmnopqrstuvwxyz" 60 | $nCharSet = "0123456789" 61 | $sCharSet = "/*-+,!?=()@;:._" 62 | $charSet = "" 63 | if ($upper -gt 0) { $charSet += $uCharSet } 64 | if ($lower -gt 0) { $charSet += $lCharSet } 65 | if ($numeric -gt 0) { $charSet += $nCharSet } 66 | if ($special -gt 0) { $charSet += $sCharSet } 67 | 68 | $charSet = $charSet.ToCharArray() 69 | $rng = New-Object System.Security.Cryptography.RNGCryptoServiceProvider 70 | $bytes = New-Object byte[]($length) 71 | $rng.GetBytes($bytes) 72 | 73 | $result = New-Object char[]($length) 74 | for ($i = 0 ; $i -lt $length ; $i++) 75 | { 76 | $result[$i] = $charSet[$bytes[$i] % $charSet.Length] 77 | } 78 | $password = (-join $result) 79 | $valid = $true 80 | if ($upper -gt ($password.ToCharArray() | Where-Object { $_ -cin $uCharSet.ToCharArray() }).Count) { $valid = $false } 81 | if ($lower -gt ($password.ToCharArray() | Where-Object { $_ -cin $lCharSet.ToCharArray() }).Count) { $valid = $false } 82 | if ($numeric -gt ($password.ToCharArray() | Where-Object { $_ -cin $nCharSet.ToCharArray() }).Count) { $valid = $false } 83 | if ($special -gt ($password.ToCharArray() | Where-Object { $_ -cin $sCharSet.ToCharArray() }).Count) { $valid = $false } 84 | 85 | if (!$valid) 86 | { 87 | $password = Get-RandomPassword $length $upper $lower $numeric $special 88 | } 89 | return $password 90 | } 91 | 92 | function Submit-Password 93 | { 94 | param ([string]$text) 95 | 96 | $url = "https://pwpush.com/p.json" 97 | $body = @{ 98 | password = @{ 99 | "payload" = $text 100 | "expire_after_days" = "2" 101 | "expire_after_views" = "10" 102 | "note" = "" 103 | "retrieval_step" = "true" 104 | "deletable_by_viewer" = "false" 105 | } 106 | } | ConvertTo-Json 107 | 108 | $response = Invoke-RestMethod -Method Post -Uri $url -Body $body -ContentType "application/json" 109 | return "https://pwpush.com/p/$($response.url_token)" 110 | } -------------------------------------------------------------------------------- /PowerShell Array/PowerShell Array.ps1: -------------------------------------------------------------------------------- 1 | # Link to the video: https://youtu.be/rvGd8kxXlVc 2 | 3 | # What is an array and why do I need it? 4 | <# 5 | Array is data structure that allows to collect multiple items under one collection 6 | so that these items can be accessed individually, iterated over or even changed. 7 | 8 | In other words, arrays allow us to stash bunch of values under one variable, 9 | and work with it. 10 | #> 11 | 12 | # How to create an empty array 13 | $stuff = @() 14 | $stuff 15 | "I've got lot's of stuff: $($stuff.Count)" 16 | 17 | # Create an array with some stuff 18 | $stuff = @("Fork", "Knife", "Salt") 19 | $stuff 20 | "Now really, I've got lot's of stuff: $($stuff.Count)" 21 | 22 | # Comma separating also works for creating an array 23 | $stuff = "Table", "Cup", "Coffe", "Milk" 24 | $stuff 25 | 26 | ############################### 27 | # Accessing items in an array # 28 | ############################### 29 | 30 | #Arrays are 0 based indexed 31 | $stuff[0] 32 | $stuff[2] 33 | $stuff[-1] 34 | $stuff[2,1,2,0] 35 | $stuff[0..2] 36 | $stuff[2..0] 37 | 38 | # Accessing items outside of an array is silent 39 | $stuff[20] 40 | [bool]$stuff[20] 41 | 42 | # Mixing different types in array 43 | $mix = @("Hi", 74, (Get-Date), "Bye") 44 | $mix 45 | 46 | # More often, we can store projects 47 | $people = @( 48 | [pscustomobject]@{Name = "John"; Email = "john@john.com"} 49 | [pscustomobject]@{Name = "Tony"; Email = "tony@tony.com"} 50 | [pscustomobject]@{Name = "Fiber"; Email = "fiber@optics.com"} 51 | ) 52 | $people 53 | $people[-1] 54 | $people.Email 55 | $people | Where-Object {$_.Name -eq "John"} 56 | $people.Where({$_.Name -eq "John"}).Email 57 | 58 | # Null will throw an error 59 | $IDidntCreateThis[3] 60 | 61 | ########### 62 | # Looping # 63 | ########### 64 | 65 | $domains = @('bbc.com', 'github.com', 'youtube.com', 'blah.blah') 66 | $ProgressPreference = 'SilentlyContinue' 67 | foreach ($domain in $domains) { 68 | $Result = Test-NetConnection -ComputerName $domain -InformationLevel Quiet 69 | "$domain is pinging: $Result" 70 | } 71 | 72 | $domains | ForEach-Object { 73 | $Result = Test-NetConnection -ComputerName $_ -InformationLevel Quiet 74 | "$_ is pinging: $Result" 75 | } 76 | 77 | $domains.ForEach{ 78 | $Result = Test-NetConnection -ComputerName $_ -InformationLevel Quiet 79 | "$_ is pinging: $Result"} 80 | 81 | 82 | for ($i = 0; $i -lt $domains.Count; $i++) { 83 | $Result = Test-NetConnection -ComputerName $domains[$i] -InformationLevel Quiet 84 | "$($domains[$i]) is pinging: $Result" 85 | } 86 | 87 | ################### 88 | # Updating values # 89 | ################### 90 | 91 | $Week = @("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday") 92 | $Week[2] #Now it is Wednesday 93 | $Week[2] = "Boo" 94 | $Week[2] 95 | $Week 96 | 97 | # Update out of index throws error 98 | $Week[8] = "Hi" 99 | 100 | ############# 101 | # Operators # 102 | ############# 103 | 104 | # Join 105 | $Week 106 | $Week -join "|" 107 | $Week -join $null 108 | 109 | # In 110 | "Tuesday" -in $Week 111 | 112 | # Match 113 | $Week -match "es" 114 | 115 | ################### 116 | # Adding to array # 117 | ################### 118 | 119 | # Arrays have by definition fixed size in memory, in other words 120 | # you shouldn't be able to add more items to it. 121 | # PowerShell however allows you to do that, hiding all complexity 122 | # by creating a new array, copying all existing item, adding new one 123 | # and finally removing old array. 124 | # If you plan to add items to your array, look at ArrayList and List below 125 | 126 | # Adding elements to array 127 | $Week 128 | $Week.Add("January") #this throws an error 129 | $Week += "January" 130 | $Week 131 | 132 | # Adding arrays together 133 | $ArrayA = 1..10 134 | $ArrayB = 11..20 135 | $ArrayA + $ArrayB 136 | 137 | ############# 138 | # ArrayList # 139 | ############# 140 | 141 | #Adding items to ArrayList 142 | $alist = [System.Collections.ArrayList]::new() #This is .Net framework 143 | $alist.Add("January") 144 | [void]$alist.Add("February") #Void stops prevents writing to console 145 | $alist 146 | 147 | # Removing from ArrayList 148 | $alist.Remove($alist[1]) 149 | $alist 150 | -------------------------------------------------------------------------------- /PowerShell Error Handling/1-What causes error.ps1: -------------------------------------------------------------------------------- 1 | function Start-Die 2 | { 3 | Throw "Aaaargh I've died" 4 | } 5 | Start-Die -------------------------------------------------------------------------------- /PowerShell Error Handling/2-Non terminating errors.ps1: -------------------------------------------------------------------------------- 1 | 2 | #Non terminating errors 3 | Write-Error "I just errored" 4 | Write-Host "I'm Here!" 5 | 6 | #We need to tell PowerShell to stop in case of error 7 | Write-Error "Another failure" -ErrorAction Stop 8 | Write-Host "I'm Here, again" 9 | 10 | -------------------------------------------------------------------------------- /PowerShell Error Handling/3-Error Action preference.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference 2 | 3 | #Or change it globally - this is what is done in production code 4 | $ErrorActionPreference = "Stop" 5 | Write-Error "Third failure" 6 | Write-Host "I'm here, yet again" 7 | 8 | -------------------------------------------------------------------------------- /PowerShell Error Handling/4-Error Handling with Try Catch.ps1: -------------------------------------------------------------------------------- 1 | #Let's revert to default 2 | $ErrorActionPreference = 'Continue' 3 | 4 | #Finally works always 5 | function Start-Work 6 | { 7 | param ( 8 | [switch]$Die 9 | ) 10 | 11 | Write-Host "Happily working" -ForegroundColor Green 12 | if ($Die.IsPresent) 13 | { 14 | Throw "Aaaargh meeting has started" 15 | } 16 | 17 | return "Job done" 18 | } 19 | 20 | #Without try catch there's not much we can do - script crashes 21 | #Start-Work -Die 22 | 23 | #Try/Catch 24 | try 25 | { 26 | Start-Work -Die 27 | } 28 | catch 29 | { 30 | Write-Host "Well that doesn't look good..." 31 | Write-Host $_ 32 | 33 | #Providing Throw without any comment rethrows the error 34 | #Throw 35 | } 36 | 37 | Write-Host "This is the end" 38 | -------------------------------------------------------------------------------- /PowerShell Error Handling/5-Try Finally.ps1: -------------------------------------------------------------------------------- 1 | #Let's revert to default 2 | $ErrorActionPreference = 'Continue' 3 | 4 | #Finally works always 5 | function Start-Work 6 | { 7 | param ( 8 | [switch]$Die 9 | ) 10 | 11 | Write-Host "Happily working" -ForegroundColor Green 12 | if ($Die.IsPresent) 13 | { 14 | Throw "Aaaargh meeting has started" 15 | } 16 | 17 | return "Job done" 18 | } 19 | 20 | #Try/Catch 21 | try 22 | { 23 | Start-Work -Die 24 | } 25 | catch 26 | { 27 | Write-Host "Well that doesn't look good..." 28 | Write-Host $_ 29 | Throw 30 | } 31 | finally 32 | { 33 | Write-Host "Locking up office" -ForegroundColor Blue 34 | } 35 | 36 | -------------------------------------------------------------------------------- /PowerShell Error Handling/6-Investigating errors.ps1: -------------------------------------------------------------------------------- 1 | #Investigating errors 2 | Invoke-RestMethod -Uri qazedc.fds 3 | 4 | #Only PowerShell v7 and newer 5 | Get-Error 6 | 7 | $Error[0].InvocationInfo 8 | $Error[0].Exception 9 | $Error[0].Exception.Message 10 | $Error[0].Exception.StackTrace 11 | 12 | #This line is useful for typed exceptions 13 | $Error[0].exception.GetType().FullName -------------------------------------------------------------------------------- /PowerShell Error Handling/7-typed exceptions.ps1: -------------------------------------------------------------------------------- 1 | #Catching typed exception 2 | # try 3 | # { 4 | # $null = Invoke-RestMethod -Uri google.com -Ea stop 5 | # $null = Get-Item -Path "123blah123" -ErrorAction stop 6 | # } 7 | # catch [System.Net.Http.HttpRequestException] 8 | # { 9 | # Write-Host "Http Request Execption" -ForegroundColor DarkGreen 10 | # } 11 | # catch 12 | # { 13 | # Write-Host "Generic error" -ForegroundColor DarkGreen 14 | # Throw 15 | # } 16 | 17 | # Throwing typed exception 18 | Write-Host "Happy working" 19 | Throw [System.AccessViolationException]::new("Not anymore") 20 | (Get-Error).exception.Type -------------------------------------------------------------------------------- /PowerShell Error Handling/8-application errors.ps1: -------------------------------------------------------------------------------- 1 | try 2 | { 3 | Get-Command -Name git -CommandType Application -ErrorAction Stop 4 | } 5 | catch 6 | { 7 | Throw "No git, everything fails" 8 | } 9 | 10 | #Not all native applications would return error 11 | try 12 | { 13 | git --thiscommanddoesntexist 14 | } 15 | catch 16 | { 17 | Throw "Git has failed" 18 | } 19 | # That's why we have last exit code 20 | $LASTEXITCODE 21 | 22 | git --version 23 | $LASTEXITCODE 24 | 25 | git --thiscommanddoesntexist 26 | if ($LASTEXITCODE -ne 0)  27 | { 28 | Throw "Git has failed" -------------------------------------------------------------------------------- /PowerShell Files/Downloads/PowerShell File Downloading.ps1: -------------------------------------------------------------------------------- 1 | $link = "https://download-installer.cdn.mozilla.net/pub/firefox/releases/107.0/win64/en-GB/Firefox%20Setup%20107.0.exe" 2 | 3 | $tempFolder = [System.IO.Path]::GetTempPath() 4 | $destination = "$tempFolder/firefox.exe" 5 | 6 | #Invoke Web Request 7 | #If the downloads runs slow (e.g. Windows PowerShell), change progress preference 8 | #$ProgressPreference = 'SilentlyContinue' 9 | Invoke-WebRequest -Uri $link -OutFile $destination 10 | 11 | #Using Invoke-RestMethod, essentialy it's the same 12 | Invoke-RestMethod -Uri $link -OutFile $destination 13 | 14 | #Using class 15 | $client = [System.Net.WebClient]::new() 16 | $client.DownloadFile($link, $destination) 17 | 18 | #as above, but one line 19 | ([System.Net.WebClient]::new()).DownloadFile($link, $destination) 20 | 21 | #Windows Only - Bits Transfer 22 | Start-BitsTransfer -Source $link -Destination $destination -------------------------------------------------------------------------------- /PowerShell Function/Convert script into function/1. Simple script.ps1: -------------------------------------------------------------------------------- 1 | # Sample script which asks user for basic information, then manipulates it and 2 | # display some information 3 | 4 | # There's no way (at least easy) to pass these parameters from prompt, nor validate 5 | $Name = Read-Host -Prompt "What's your name?" 6 | $Age = Read-Host -Prompt "What's your age?" 7 | 8 | Write-Host "==================" 9 | 10 | $email = '{0}@company.com' -f $Name.ToLower() 11 | 12 | Write-Host "Hi $($Name.ToUpper())" 13 | Write-Host "your email address is: $email" 14 | 15 | if ($Age -gt 17) { 16 | Write-Host "You will be able to access any website" 17 | } else { 18 | Write-Host "We will turn on content blocker approriate to your age" 19 | } -------------------------------------------------------------------------------- /PowerShell Function/Convert script into function/2. Script with parameters.ps1: -------------------------------------------------------------------------------- 1 | # In this step we formalised parameters, but user must explicitly provide them 2 | param ( 3 | $Name, 4 | 5 | $Age 6 | ) 7 | 8 | Write-Host "==================" 9 | 10 | $email = '{0}@company.com' -f $Name.ToLower() 11 | 12 | Write-Host "Hi $($Name.ToUpper())" 13 | Write-Host "your email address is: $email" 14 | 15 | if ($Age -gt 17) { 16 | Write-Host "You will be able to access any website" 17 | } else { 18 | Write-Host "We will turn on content blocker approriate to your age" 19 | } -------------------------------------------------------------------------------- /PowerShell Function/Convert script into function/3. Parameters and types.ps1: -------------------------------------------------------------------------------- 1 | # In this case user can either pass parameters, or will be prompted as they are mandatory 2 | # type is specified, therefore $Age only accepts integers 3 | param ( 4 | [Parameter(Mandatory)] 5 | [string]$Name, 6 | 7 | [Parameter(Mandatory)] 8 | [int]$Age 9 | ) 10 | 11 | Write-Host "==================" 12 | 13 | $email = '{0}@company.com' -f $Name.ToLower() 14 | 15 | Write-Host "Hi $($Name.ToUpper())" 16 | Write-Host "your email address is: $email" 17 | 18 | if ($Age -gt 17) { 19 | Write-Host "You will be able to access any website" 20 | } else { 21 | Write-Host "We will turn on content blocker approriate to your age" 22 | } -------------------------------------------------------------------------------- /PowerShell Function/Convert script into function/4. Convert script into function.ps1: -------------------------------------------------------------------------------- 1 | # Now we converted script into function, it must be first loaded to memory before it 2 | # can be executed. 3 | function Get-Person { 4 | param ( 5 | [Parameter(Mandatory)] 6 | [string]$Name, 7 | 8 | [Parameter(Mandatory)] 9 | [int]$Age 10 | ) 11 | 12 | Write-Host "==================" 13 | 14 | $email = '{0}@company.com' -f $Name.ToLower() 15 | 16 | Write-Host "Hi $($Name.ToUpper())" 17 | Write-Host "your email address is: $email" 18 | 19 | if ($Age -gt 17) { 20 | Write-Host "You will be able to access any website" 21 | } 22 | else { 23 | Write-Host "We will turn on content blocker approriate to your age" 24 | } 25 | } -------------------------------------------------------------------------------- /PowerShell Function/Parameters/1Mandatory.ps1: -------------------------------------------------------------------------------- 1 | function Get-Person { 2 | [cmdletbinding()] 3 | param ( 4 | #[Parameter(Mandatory)] 5 | [string]$Surname, 6 | 7 | [string]$Firstname, 8 | 9 | [Parameter(Mandatory)] 10 | [int]$Id, 11 | 12 | [switch]$All, 13 | 14 | [switch]$IncludeInactive, 15 | 16 | [string]$Region 17 | ) 18 | 19 | $items = [System.Collections.Generic.List[pscustomobject]]::new() 20 | $data = Import-PowerShellDataFile -Path "$PSScriptRoot\data.psd1" 21 | $users = $data.users 22 | 23 | if (!($IncludeInactive.IsPresent)) { 24 | $users = $users | Where-Object {$_.Active -eq $true} 25 | } 26 | 27 | 28 | if ($PSBoundParameters.ContainsKey('Region')) { 29 | $users = $users | Where-Object {$_.Region -eq $Region} 30 | } 31 | 32 | foreach ($u in $users) { 33 | $items.Add([pscustomobject]$u) 34 | } 35 | 36 | if ($PSBoundParameters.ContainsKey('All')) { 37 | return $items 38 | } 39 | 40 | if ($PSBoundParameters.ContainsKey('ID')) { 41 | return $items.Where({$_.ID -eq $Id}) 42 | } 43 | 44 | if ($PSBoundParameters.ContainsKey('Surname')) { 45 | 46 | if ($PSBoundParameters.ContainsKey("Firstname")) { 47 | return $items.Where( { $_.Surname -eq $Surname -and $_.FirstName -eq $Firstname }) 48 | } 49 | else { 50 | return $items.Where( { $_.Surname -eq $Surname }) 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /PowerShell Function/Parameters/2ParameterSetName.ps1: -------------------------------------------------------------------------------- 1 | function Get-Person { 2 | [cmdletbinding(DefaultParameterSetName = "All")] 3 | param ( 4 | [Parameter(Mandatory, ParameterSetName = "byName")] 5 | [string]$Surname, 6 | 7 | [Parameter(ParameterSetName = "byName")] 8 | [string]$Firstname, 9 | 10 | [Parameter(Mandatory, ParameterSetName = "byId")] 11 | [int]$Id, 12 | 13 | [Parameter(ParameterSetName = "All")] 14 | [switch]$All, 15 | 16 | [switch]$IncludeInactive, 17 | 18 | [string]$Region 19 | ) 20 | 21 | $items = [System.Collections.Generic.List[pscustomobject]]::new() 22 | $data = Import-PowerShellDataFile -Path "$PSScriptRoot\data.psd1" 23 | $users = $data.users 24 | 25 | if (!($IncludeInactive.IsPresent)) { 26 | $users = $users | Where-Object {$_.Active -eq $true} 27 | } 28 | 29 | if ($PSBoundParameters.ContainsKey('Region')) { 30 | $users = $users | Where-Object {$_.Region -eq $Region} 31 | } 32 | 33 | foreach ($u in $users) { 34 | $items.Add([pscustomobject]$u) 35 | } 36 | 37 | if ($PSCmdlet.ParameterSetName -eq "All") { 38 | return $items 39 | } 40 | 41 | if ($PSCmdlet.ParameterSetName -eq "byId") { 42 | return $items.Where({$_.ID -eq $Id}) 43 | } 44 | 45 | if ($PSCmdlet.ParameterSetName -eq "byName") { 46 | 47 | if ($PSBoundParameters.ContainsKey("Firstname")) { 48 | return $items.Where( { $_.Surname -eq $Surname -and $_.FirstName -eq $Firstname }) 49 | } 50 | else { 51 | return $items.Where( { $_.Surname -eq $Surname }) 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /PowerShell Function/Parameters/3Position.ps1: -------------------------------------------------------------------------------- 1 | function Get-Person { 2 | [cmdletbinding(DefaultParameterSetName = "All")] 3 | param ( 4 | [Parameter(Mandatory, ParameterSetName = "byName", Position = 1)] 5 | [string]$Surname, 6 | 7 | [Parameter(ParameterSetName = "byName", Position = 2)] 8 | [string]$Firstname, 9 | 10 | [Parameter(Mandatory, ParameterSetName = "byId", Position = 1)] 11 | [int]$Id, 12 | 13 | [Parameter(ParameterSetName = "All")] 14 | [switch]$All, 15 | 16 | [switch]$IncludeInactive, 17 | 18 | [string]$Region 19 | ) 20 | 21 | $items = [System.Collections.Generic.List[pscustomobject]]::new() 22 | $data = Import-PowerShellDataFile -Path "$PSScriptRoot\data.psd1" 23 | $users = $data.users 24 | 25 | if (!($IncludeInactive.IsPresent)) { 26 | $users = $users | Where-Object {$_.Active -eq $true} 27 | } 28 | 29 | if ($PSBoundParameters.ContainsKey('Region')) { 30 | $users = $users | Where-Object {$_.Region -eq $Region} 31 | } 32 | 33 | foreach ($u in $users) { 34 | $items.Add([pscustomobject]$u) 35 | } 36 | 37 | if ($PSCmdlet.ParameterSetName -eq "All") { 38 | return $items 39 | } 40 | 41 | if ($PSCmdlet.ParameterSetName -eq "byId") { 42 | return $items.Where({$_.ID -eq $Id}) 43 | } 44 | 45 | if ($PSCmdlet.ParameterSetName -eq "byName") { 46 | 47 | if ($PSBoundParameters.ContainsKey("Firstname")) { 48 | return $items.Where( { $_.Surname -eq $Surname -and $_.FirstName -eq $Firstname }) 49 | } 50 | else { 51 | return $items.Where( { $_.Surname -eq $Surname }) 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /PowerShell Function/Parameters/4ValueFromPipeline.ps1: -------------------------------------------------------------------------------- 1 | function Get-Person { 2 | [cmdletbinding(DefaultParameterSetName = "All")] 3 | param ( 4 | [Parameter(Mandatory, ParameterSetName = "byName", Position = 1, ValueFromPipeline)] 5 | [string]$Surname, 6 | 7 | [Parameter(ParameterSetName = "byName", Position = 2)] 8 | [string]$Firstname, 9 | 10 | [Parameter(Mandatory, ParameterSetName = "byId", Position = 1, ValueFromPipeline)] 11 | [int]$Id, 12 | 13 | [Parameter(ParameterSetName = "All")] 14 | [switch]$All, 15 | 16 | [switch]$IncludeInactive, 17 | 18 | [string]$Region 19 | ) 20 | 21 | $items = [System.Collections.Generic.List[pscustomobject]]::new() 22 | $data = Import-PowerShellDataFile -Path "$PSScriptRoot\data.psd1" 23 | $users = $data.users 24 | 25 | if (!($IncludeInactive.IsPresent)) { 26 | $users = $users | Where-Object {$_.Active -eq $true} 27 | } 28 | 29 | if ($PSBoundParameters.ContainsKey('Region')) { 30 | $users = $users | Where-Object {$_.Region -eq $Region} 31 | } 32 | 33 | foreach ($u in $users) { 34 | $items.Add([pscustomobject]$u) 35 | } 36 | 37 | if ($PSCmdlet.ParameterSetName -eq "All") { 38 | return $items 39 | } 40 | 41 | if ($PSCmdlet.ParameterSetName -eq "byId") { 42 | return $items.Where({$_.ID -eq $Id}) 43 | } 44 | 45 | if ($PSCmdlet.ParameterSetName -eq "byName") { 46 | 47 | if ($PSBoundParameters.ContainsKey("Firstname")) { 48 | return $items.Where( { $_.Surname -eq $Surname -and $_.FirstName -eq $Firstname }) 49 | } 50 | else { 51 | return $items.Where( { $_.Surname -eq $Surname }) 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /PowerShell Function/Parameters/5Validate.ps1: -------------------------------------------------------------------------------- 1 | function Get-Person { 2 | [cmdletbinding(DefaultParameterSetName = "All")] 3 | param ( 4 | [Parameter(Mandatory, ParameterSetName = "byName", Position = 1, ValueFromPipeline)] 5 | [string]$Surname, 6 | 7 | [Parameter(ParameterSetName = "byName", Position = 2)] 8 | [ValidateNotNullOrEmpty()] 9 | [string]$Firstname, 10 | 11 | [Parameter(Mandatory, ParameterSetName = "byId", Position = 1, ValueFromPipeline)] 12 | [ValidateRange(1,4)] 13 | [int]$Id, 14 | 15 | [Parameter(ParameterSetName = "All")] 16 | [switch]$All, 17 | 18 | [switch]$IncludeInactive, 19 | 20 | [ValidateSet("EU", "US", "NZ")] 21 | [string]$Region 22 | ) 23 | 24 | $items = [System.Collections.Generic.List[pscustomobject]]::new() 25 | $data = Import-PowerShellDataFile -Path "$PSScriptRoot\data.psd1" 26 | $users = $data.users 27 | 28 | if (!($IncludeInactive.IsPresent)) { 29 | $users = $users | Where-Object {$_.Active -eq $true} 30 | } 31 | 32 | if ($PSBoundParameters.ContainsKey('Region')) { 33 | $users = $users | Where-Object {$_.Region -eq $Region} 34 | } 35 | 36 | foreach ($u in $users) { 37 | $items.Add([pscustomobject]$u) 38 | } 39 | 40 | if ($PSCmdlet.ParameterSetName -eq "All") { 41 | return $items 42 | } 43 | 44 | if ($PSCmdlet.ParameterSetName -eq "byId") { 45 | return $items.Where({$_.ID -eq $Id}) 46 | } 47 | 48 | if ($PSCmdlet.ParameterSetName -eq "byName") { 49 | 50 | if ($PSBoundParameters.ContainsKey("Firstname")) { 51 | return $items.Where( { $_.Surname -eq $Surname -and $_.FirstName -eq $Firstname }) 52 | } 53 | else { 54 | return $items.Where( { $_.Surname -eq $Surname }) 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /PowerShell Function/Parameters/6Alias.ps1: -------------------------------------------------------------------------------- 1 | function Get-Person { 2 | [cmdletbinding(DefaultParameterSetName = "All")] 3 | param ( 4 | [Parameter(Mandatory, ParameterSetName = "byName", Position = 1, ValueFromPipeline)] 5 | [Alias("SecondName")] 6 | [string]$Surname, 7 | 8 | [Parameter(ParameterSetName = "byName", Position = 2)] 9 | [ValidateNotNullOrEmpty()] 10 | [Alias("GivenName")] 11 | [string]$Firstname, 12 | 13 | [Parameter(Mandatory, ParameterSetName = "byId", Position = 1, ValueFromPipeline)] 14 | [ValidateRange(1,4)] 15 | [int]$Id, 16 | 17 | [Parameter(ParameterSetName = "All")] 18 | [switch]$All, 19 | 20 | [switch]$IncludeInactive, 21 | 22 | [ValidateSet("EU", "US", "NZ")] 23 | [string]$Region 24 | ) 25 | 26 | $items = [System.Collections.Generic.List[pscustomobject]]::new() 27 | $data = Import-PowerShellDataFile -Path "$PSScriptRoot\data.psd1" 28 | $users = $data.users 29 | 30 | if (!($IncludeInactive.IsPresent)) { 31 | $users = $users | Where-Object {$_.Active -eq $true} 32 | } 33 | 34 | if ($PSBoundParameters.ContainsKey('Region')) { 35 | $users = $users | Where-Object {$_.Region -eq $Region} 36 | } 37 | 38 | foreach ($u in $users) { 39 | $items.Add([pscustomobject]$u) 40 | } 41 | 42 | if ($PSCmdlet.ParameterSetName -eq "All") { 43 | return $items 44 | } 45 | 46 | if ($PSCmdlet.ParameterSetName -eq "byId") { 47 | return $items.Where({$_.ID -eq $Id}) 48 | } 49 | 50 | if ($PSCmdlet.ParameterSetName -eq "byName") { 51 | 52 | if ($PSBoundParameters.ContainsKey("Firstname")) { 53 | return $items.Where( { $_.Surname -eq $Surname -and $_.FirstName -eq $Firstname }) 54 | } 55 | else { 56 | return $items.Where( { $_.Surname -eq $Surname }) 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /PowerShell Function/Parameters/data.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | users = @( 3 | @{ID = 1; FirstName = "John"; Surname = "Smith"; Active = $true; Region = "EU" } 4 | @{ID = 2; FirstName = "Elen"; Surname = "Smith"; Active = $true; Region = "NZ"} 5 | @{ID = 3; FirstName = "Andy"; Surname = "Oliver"; Active = $true; Region = "US" } 6 | @{ID = 4; FirstName = "Richard"; Surname = "Mann"; Active = $false; Region = "EU" } 7 | ) 8 | } -------------------------------------------------------------------------------- /PowerShell Hashtable/PowerShell Hashtable.ps1: -------------------------------------------------------------------------------- 1 | 2 | <#PSScriptInfo 3 | .VERSION 1.0.0 4 | .GUID 50fa84c4-080d-45cd-82a8-9e8dba10b187 5 | .AUTHOR Kamil Procyszyn 6 | .COPYRIGHT Kamil Procyszyn 7 | .PROJECTURI https://github.com/kprocyszyn/About-PowerShell 8 | .RELEASENOTES 2021 September 9 | .DESCRIPTION 10 | Link to the video: https://youtu.be/oti2l8EmAT8 11 | Documentation: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_hash_tables?view=powershell-7.1#:~:text=In%20PowerShell%2C%20each%20hash%20table%20is%20a%20Hashtable,to%20create%20an%20ordered%20dictionary%20%28System.Collections.Specialized.OrderedDictionary%29%20in%20PowerShell. 12 | #> 13 | 14 | <# 15 | About hashtable: 16 | 17 | A hash table, also known as a dictionary or associative array, 18 | is a compact data structure that stores one or more key/value pairs. 19 | For example, a hash table might contain a series of IP addresses and computer names, 20 | where the IP addresses are the keys and the computer names are the values, or vice versa. 21 | #> 22 | 23 | #Creating a hashtable 24 | $hash = @{} 25 | 26 | ############################# 27 | # Adding items to hashtable # 28 | ############################# 29 | 30 | $hash.Add("Person", "John") 31 | $hash.Add("Email", "John@john.com") 32 | $hash.Add("Pet", "Cat") 33 | $hash.Add("Surname", "Smith") 34 | $hash 35 | 36 | # Removing Key from hashtable 37 | $hash.Remove("Surname") 38 | $hash 39 | 40 | # Prepopulating hashtable 41 | $details = @{ 42 | Person = "Mike" 43 | Email = "Mike@Mike.com" 44 | Pet = "Dog" 45 | } 46 | $details 47 | 48 | # Adding key that already exists throws 49 | $details.Add("Pet", "Snake") 50 | 51 | ################### 52 | # Accessing items # 53 | ################### 54 | 55 | # Accessing with property name 56 | $details['Pet'] 57 | $details.Pet 58 | 59 | # We can use variable 60 | $property = "Email" 61 | $details[$property] 62 | 63 | # Accessing multiple properties 64 | $details["Email", "Person"] 65 | 66 | # Non existent value doesn't throw 67 | $details['Surname'] 68 | $details.Surname 69 | 70 | # Although we can check for true/false 71 | [bool]$details['Surname'] 72 | 73 | ################### 74 | # Updating values # 75 | ################### 76 | 77 | # We can update and add new values 78 | $details['Pet'] = "Snake" 79 | $details['Drink'] = "Flat white" 80 | $details 81 | 82 | $details.pet = "Dog" 83 | $details.Food = "Lamb Shish Kebab" 84 | $details 85 | 86 | ########### 87 | # Looping # 88 | ########### 89 | 90 | # using foreach 91 | foreach ($key in $details.Keys) { 92 | "{0} is {1}" -f $key, $details[$key] 93 | } 94 | 95 | # piping to foreach-object 96 | $details.Keys | ForEach-Object { 97 | "{0} is {1}" -f $_, $details[$_] 98 | } 99 | 100 | # GetEnumerator() allows us to work with properties 101 | $details.GetEnumerator() | ForEach-Object { 102 | "{0} is {1}" -f $_.Key, $_.Value 103 | } 104 | 105 | # Values can't be updated while enumarated! 106 | foreach ($key in $details.Keys) { 107 | $details[$key] = 'BLAH' 108 | } 109 | 110 | # Keys must be cloned before updating 111 | $details.Keys.Clone() | ForEach-Object { 112 | $details[$_] = "SANITISED" 113 | } 114 | $details 115 | 116 | ###### 117 | # IF # 118 | ###### 119 | 120 | # checking if hashtable exists 121 | if ($details) {"It's there"} 122 | 123 | $empty = @{} 124 | if ($empty) {"It's empty, but it's there!"} 125 | 126 | # Checking if key exists 127 | if ($details.Person) {"There's some info about a person"} 128 | 129 | # Deailing with false 130 | $details.Add("Empty", "") 131 | $details.Add("Null", $Null) 132 | $details.Add("False", $false) 133 | $details 134 | 135 | if ($details.Empty) {"It's there"} 136 | if ($details.Null) {"It's there"} 137 | if ($details.False) {"It's there"} 138 | 139 | if ($details.ContainsKey('Null')) {"It's null!"} 140 | 141 | ###################### 142 | # Custom expressions # 143 | ###################### 144 | 145 | $employee = @{ 146 | Name = "Beth" 147 | HourlyWage = 10 148 | HoursWorked = 7.5 149 | } 150 | $employee | Select-Object -Property *,@{N = "Wage"; E = {$_.HourlyWage * $_.HoursWorked } } 151 | 152 | ############# 153 | # Splatting # 154 | ############# 155 | 156 | Invoke-RestMethod -Uri catfact.ninja/facts -Method Get | Select-Object Data -ExpandProperty Data 157 | 158 | $params = @{ 159 | Uri = "catfact.ninja/facts" 160 | Method = "Get" 161 | } 162 | Invoke-RestMethod @params | Select-Object Data -ExpandProperty Data 163 | 164 | # Adding parameters 165 | 166 | $Verbose = $true 167 | if ($Verbose) { 168 | $params['Verbose'] = $true 169 | } 170 | Invoke-RestMethod @params 171 | 172 | ##################### 173 | # Nested hashtables # 174 | ##################### 175 | 176 | $Environments = @{ 177 | 178 | Development = @{ 179 | Server = "Server1" 180 | Admin = "Rachel Green" 181 | Credentials = @{ 182 | Username = "Serv1" 183 | Password = "Secret" 184 | } 185 | } 186 | 187 | Test = @{ 188 | Server = "Server2" 189 | Admin = "Joe Triviani" 190 | Credentials = @{ 191 | Username = "Serv2" 192 | Password = "Letmein" 193 | } 194 | } 195 | 196 | } 197 | 198 | # Accessing nested properties 199 | $Environments 200 | $Environments.Keys 201 | $Environments.Values 202 | 203 | $Environments.Test 204 | $Environments.Test.Credentials 205 | $Environments['Test']['Credentials'] 206 | 207 | # Updating nested properties 208 | $Environments.Test.Credentials.Username = "admin" 209 | $Environments.Test.Credentials 210 | 211 | # Quickly unwrapping all properties 212 | $Environments | ConvertTo-Json -Depth 99 213 | 214 | # Adding nested properties 215 | $Environments['Production'] = @{} 216 | $Environments.Production.Server = "Server3" 217 | $Environments.Production.Admin = "Ross Geller" 218 | $Environments.Production['Credentials'] = @{} 219 | $Environments.Production.Credentials.Username = "Serv3" 220 | $Environments.Production.Credentials.Password = "Nosuchplace" 221 | 222 | ##################### 223 | # Working with JSON # 224 | ##################### 225 | 226 | $Environments | ConvertTo-Json | Out-File C:\temp\envs.json 227 | Get-Content C:\Temp\envs.json | ConvertFrom-Json #This will create pscustomobject 228 | 229 | ################## 230 | # PSCustomObject # 231 | ################## 232 | 233 | # Creating a new object 234 | $EnvironmentsObject = [pscustomobject]@{ 235 | 236 | Development = @{ 237 | Server = "Server1" 238 | Admin = "Rachel Green" 239 | Credentials = @{ 240 | Username = "Serv1" 241 | Password = "Secret" 242 | } 243 | } 244 | 245 | Test = @{ 246 | Server = "Server2" 247 | Admin = "Joe Triviani" 248 | Credentials = @{ 249 | Username = "Serv2" 250 | Password = "Letmein" 251 | } 252 | } 253 | } 254 | 255 | # Casting hashtable to object 256 | [PSCustomObject]$Environments 257 | 258 | -------------------------------------------------------------------------------- /PowerShell Module/Building Module/KpInfo/.gitignore: -------------------------------------------------------------------------------- 1 | [Oo]utput/ -------------------------------------------------------------------------------- /PowerShell Module/Building Module/KpInfo/Install-Requirements.ps1: -------------------------------------------------------------------------------- 1 | $modules = @("ModuleBuilder") 2 | foreach ($m in $modules) { 3 | 4 | try { 5 | Get-InstalledModule -Name $m -ErrorAction stop 6 | } catch { 7 | Write-Host "Installing $m" 8 | Install-Module -Name $m -Force 9 | } 10 | } -------------------------------------------------------------------------------- /PowerShell Module/Building Module/KpInfo/README.md: -------------------------------------------------------------------------------- 1 | # The KpInfo PowerShell Module 2 | 3 | The module allows to quickly access the information I find important like info about cats. 4 | 5 | ## Folder structure 6 | 7 | - All building files must in Source folders: 8 | - In the root, place the module manifest 9 | - In Public, place functions accessible by users 10 | - In Private, place functions that inaccessible by users, e.g. helper functions 11 | - Place one function per file, and file name must match the name of the function 12 | - In the root of the repository we have: 13 | - Install-Requirements.ps1, this script installs all required modules for this module to be built 14 | - Start-ModuleBuild.ps1, builds the module with files from Source folder and puts thm into Output folder 15 | 16 | ## About ModuleBuilder 17 | 18 | You can find source of ModuleBuilder [here](https://github.com/PoshCode/ModuleBuilder) 19 | -------------------------------------------------------------------------------- /PowerShell Module/Building Module/KpInfo/Source/KpInfo.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | 3 | # Script module or binary module file associated with this manifest. 4 | RootModule = 'KpInfo.psm1' 5 | 6 | # Version number of this module. 7 | ModuleVersion = '0.0.1' 8 | 9 | # Supported PSEditions 10 | # CompatiblePSEditions = @() 11 | 12 | # ID used to uniquely identify this module 13 | GUID = '063eb93f-71ef-4d0c-bc51-25bebaa74a36' 14 | 15 | # Author of this module 16 | Author = 'Kamil Pro' 17 | 18 | # Company or vendor of this module 19 | CompanyName = 'Unknown' 20 | 21 | # Copyright statement for this module 22 | Copyright = '(c) Kamil Pro. All rights reserved.' 23 | 24 | # Description of the functionality provided by this module 25 | Description = 'PowerShell module that retrieves information from various sources.' 26 | 27 | # Minimum version of the PowerShell engine required by this module 28 | PowerShellVersion = '5.1' 29 | 30 | # Name of the PowerShell host required by this module 31 | # PowerShellHostName = '' 32 | 33 | # Minimum version of the PowerShell host required by this module 34 | # PowerShellHostVersion = '' 35 | 36 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 37 | # DotNetFrameworkVersion = '' 38 | 39 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 40 | # ClrVersion = '' 41 | 42 | # Processor architecture (None, X86, Amd64) required by this module 43 | # ProcessorArchitecture = '' 44 | 45 | # Modules that must be imported into the global environment prior to importing this module 46 | # RequiredModules = @() 47 | 48 | # Assemblies that must be loaded prior to importing this module 49 | # RequiredAssemblies = @() 50 | 51 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 52 | # ScriptsToProcess = @() 53 | 54 | # Type files (.ps1xml) to be loaded when importing this module 55 | # TypesToProcess = @() 56 | 57 | # Format files (.ps1xml) to be loaded when importing this module 58 | # FormatsToProcess = @() 59 | 60 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 61 | # NestedModules = @() 62 | 63 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. 64 | FunctionsToExport = @() 65 | 66 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. 67 | CmdletsToExport = @() 68 | 69 | # Variables to export from this module 70 | VariablesToExport = '*' 71 | 72 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. 73 | AliasesToExport = @() 74 | 75 | # DSC resources to export from this module 76 | # DscResourcesToExport = @() 77 | 78 | # List of all modules packaged with this module 79 | # ModuleList = @() 80 | 81 | # List of all files packaged with this module 82 | # FileList = @() 83 | 84 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 85 | PrivateData = @{ 86 | 87 | PSData = @{ 88 | 89 | # Tags applied to this module. These help with module discovery in online galleries. 90 | Tags = @("PSModule", "Information") 91 | 92 | # A URL to the license for this module. 93 | # LicenseUri = '' 94 | 95 | # A URL to the main website for this project. 96 | ProjectUri = 'https://github.com/kprocyszyn/About-PowerShell' 97 | 98 | # A URL to an icon representing this module. 99 | # IconUri = '' 100 | 101 | # ReleaseNotes of this module 102 | # ReleaseNotes = '' 103 | 104 | # Prerelease string of this module 105 | # Prerelease = '' 106 | 107 | # Flag to indicate whether the module requires explicit user acceptance for install/update/save 108 | # RequireLicenseAcceptance = $false 109 | 110 | # External dependent modules of this module 111 | # ExternalModuleDependencies = @() 112 | 113 | } # End of PSData hashtable 114 | 115 | } # End of PrivateData hashtable 116 | 117 | # HelpInfo URI of this module 118 | # HelpInfoURI = '' 119 | 120 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 121 | DefaultCommandPrefix = 'KpI' 122 | 123 | } 124 | 125 | -------------------------------------------------------------------------------- /PowerShell Module/Building Module/KpInfo/Source/Private/Invoke-Request.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-Request { 2 | [cmdletbinding()] 3 | param ( 4 | [Parameter(Mandatory, ValueFromPipeline, Position = 1)] 5 | [uri]$Uri, 6 | 7 | [switch]$ContentOnly 8 | ) 9 | 10 | $params = @{ 11 | UseBasicParsing = $true 12 | Uri = $Uri 13 | } 14 | 15 | $result = Invoke-WebRequest @params 16 | if ($ContentOnly.IsPresent) { 17 | return $result.Content 18 | } else { 19 | return $result 20 | } 21 | } -------------------------------------------------------------------------------- /PowerShell Module/Building Module/KpInfo/Source/Public/Get-CatFact.ps1: -------------------------------------------------------------------------------- 1 | function Get-CatFact { 2 | $result = Invoke-Request -Uri https://catfact.ninja/fact -ContentOnly | ConvertFrom-Json 3 | return $result.fact 4 | } -------------------------------------------------------------------------------- /PowerShell Module/Building Module/KpInfo/Source/Public/Get-Quote.ps1: -------------------------------------------------------------------------------- 1 | function Get-Quote { 2 | $quotes = Invoke-Request -Uri https://type.fit/api/quotes -ContentOnly | ConvertFrom-Json 3 | $random = Get-Random -Minimum 0 -Maximum $quotes.Count 4 | return $quotes[$random] 5 | } -------------------------------------------------------------------------------- /PowerShell Module/Building Module/KpInfo/Source/Public/Get-Weather.ps1: -------------------------------------------------------------------------------- 1 | function Get-Weather { 2 | Invoke-Request -Uri https://wttr.in/ -ContentOnly 3 | } -------------------------------------------------------------------------------- /PowerShell Module/Building Module/KpInfo/Start-ModuleBuild.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [version]$Version = "1.0.0" 3 | ) 4 | #Requires -Module ModuleBuilder 5 | 6 | $params = @{ 7 | SourcePath = "$PSScriptRoot\Source\KpInfo.psd1" 8 | CopyPaths = @("$PSScriptRoot\README.md") 9 | Version = $Version 10 | UnversionedOutputDirectory = $true 11 | } 12 | Build-Module @params -------------------------------------------------------------------------------- /PowerShell Module/Module Manifest/cat.ps1: -------------------------------------------------------------------------------- 1 | function Get-CatFact { 2 | Invoke-RestMethod https://catfact.ninja/fact 3 | } -------------------------------------------------------------------------------- /PowerShell Module/Module Manifest/mystuff.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'mystuff' 3 | # 4 | # Generated by: Kamil 5 | # 6 | # Generated on: 22/02/2022 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'mystuff.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '1.3.34' 16 | 17 | # Supported PSEditions 18 | # CompatiblePSEditions = @() 19 | 20 | # ID used to uniquely identify this module 21 | GUID = '583dda2e-b132-4929-8d89-a27f4d5cad7c' 22 | 23 | # Author of this module 24 | Author = 'KamilKrzysztof' 25 | 26 | # Company or vendor of this module 27 | CompanyName = 'Unknown' 28 | 29 | # Copyright statement for this module 30 | Copyright = '(c) KamilKrzysztof. All rights reserved.' 31 | 32 | # Description of the functionality provided by this module 33 | Description = 'This bundles together my important functions' 34 | 35 | # Minimum version of the PowerShell engine required by this module 36 | PowerShellVersion = '5.1' 37 | 38 | # Name of the PowerShell host required by this module 39 | # PowerShellHostName = '' 40 | 41 | # Minimum version of the PowerShell host required by this module 42 | # PowerShellHostVersion = '' 43 | 44 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 45 | # DotNetFrameworkVersion = '' 46 | 47 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 48 | # ClrVersion = '' 49 | 50 | # Processor architecture (None, X86, Amd64) required by this module 51 | # ProcessorArchitecture = '' 52 | 53 | # Modules that must be imported into the global environment prior to importing this module 54 | RequiredModules = @(@{ModuleName = "Az.Storage"; ModuleVersion = '1.0.0'} ) 55 | 56 | # Assemblies that must be loaded prior to importing this module 57 | # RequiredAssemblies = @() 58 | 59 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 60 | # ScriptsToProcess = @() 61 | 62 | # Type files (.ps1xml) to be loaded when importing this module 63 | # TypesToProcess = @() 64 | 65 | # Format files (.ps1xml) to be loaded when importing this module 66 | # FormatsToProcess = @() 67 | 68 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 69 | # NestedModules = @() 70 | 71 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. 72 | FunctionsToExport = @("Get-CatFact") 73 | 74 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. 75 | CmdletsToExport = @() 76 | 77 | # Variables to export from this module 78 | VariablesToExport = '*' 79 | 80 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. 81 | AliasesToExport = @() 82 | 83 | # DSC resources to export from this module 84 | # DscResourcesToExport = @() 85 | 86 | # List of all modules packaged with this module 87 | # ModuleList = @() 88 | 89 | # List of all files packaged with this module 90 | # FileList = @() 91 | 92 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 93 | PrivateData = @{ 94 | 95 | PSData = @{ 96 | 97 | # Tags applied to this module. These help with module discovery in online galleries. 98 | Tags = @("PSMODULE") 99 | 100 | # A URL to the license for this module. 101 | # LicenseUri = '' 102 | 103 | # A URL to the main website for this project. 104 | # ProjectUri = '' 105 | 106 | # A URL to an icon representing this module. 107 | # IconUri = '' 108 | 109 | # ReleaseNotes of this module 110 | # ReleaseNotes = '' 111 | 112 | # Prerelease string of this module 113 | # Prerelease = '' 114 | 115 | # Flag to indicate whether the module requires explicit user acceptance for install/update/save 116 | # RequireLicenseAcceptance = $false 117 | 118 | # External dependent modules of this module 119 | # ExternalModuleDependencies = @() 120 | 121 | } # End of PSData hashtable 122 | 123 | } # End of PrivateData hashtable 124 | 125 | # HelpInfo URI of this module 126 | # HelpInfoURI = '' 127 | 128 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 129 | DefaultCommandPrefix = 'KP' 130 | 131 | } 132 | 133 | -------------------------------------------------------------------------------- /PowerShell Module/Module Manifest/mystuff.psm1: -------------------------------------------------------------------------------- 1 | function Get-CatFact { 2 | Invoke-RestMethod https://catfact.ninja/fact 3 | Get-Quote 4 | } 5 | 6 | function Get-Quote { 7 | $quotes = Invoke-RestMethod https://type.fit/api/quotes 8 | $random = Get-Random -Minimum 0 -Maximum $quotes.Count 9 | return $quotes[$random] 10 | } 11 | 12 | function Get-Weather { 13 | 14 | Invoke-RestMethod https://wttr.in/ 15 | 16 | } -------------------------------------------------------------------------------- /PowerShell Module/Module Manifest/quote.ps1: -------------------------------------------------------------------------------- 1 | function Get-Quote { 2 | $quotes = Invoke-RestMethod https://type.fit/api/quotes 3 | $random = Get-Random -Minimum 0 -Maximum $quotes.Count 4 | return $quotes[$random] 5 | } -------------------------------------------------------------------------------- /PowerShell Module/Module Manifest/weather.ps1: -------------------------------------------------------------------------------- 1 | function Get-Weather { 2 | 3 | Invoke-RestMethod https://wttr.in/ 4 | 5 | } -------------------------------------------------------------------------------- /PowerShell Module/Module Manifest/wrapper.ps1: -------------------------------------------------------------------------------- 1 | . .\cat.ps1 2 | . .\quote.ps1 3 | . .\weather.ps1 -------------------------------------------------------------------------------- /PowerShell PsCustomObject/PowerShell PsCustomObject.ps1: -------------------------------------------------------------------------------- 1 | 2 | <#PSScriptInfo 3 | .VERSION 1.0.0 4 | .GUID f5228c81-d25c-4984-bb0c-e64576487b3e 5 | .AUTHOR Kamil Procyszyn 6 | .COPYRIGHT Kamil Procyszyn 7 | .PROJECTURI https://github.com/kprocyszyn/About-PowerShell 8 | .RELEASENOTES 2021 November 9 | .DESCRIPTION 10 | Link to the video: https://youtu.be/DAVGyCytsqM 11 | #> 12 | 13 | <# 14 | About PsCustomObject: 15 | https://forums.powershell.org/t/what-is-the-difference-between-pscustomobject-and-psobject/3887/4 16 | [PSCustomObject] is a type accelerator. It constructs a PSObject, but does so in a way that results in hash table keys 17 | becoming properties. 18 | PSCustomObject isn’t an object type per se - it’s a process shortcut. 19 | The docs are relatively clear about it (https://msdn.microsoft.com/en-us/library/system.management.automation.pscustomobject(v=vs.85).aspx) 20 | PSCustomObject is a placeholder that’s used when PSObject is called with no constructor parameters. 21 | #> 22 | 23 | # Creating custom object: 24 | $obj = [PSCustomObject]@{ 25 | Name = "Mr Fiber" 26 | Species = "Domestic cat" 27 | Type = "Tabby cat" 28 | } 29 | $obj 30 | $obj.Name 31 | 32 | # Saving to a file (JSON): 33 | # We could save CSV, however CSV doesn't support nested properties, thus why JSON is preferable 34 | $Path = "$env:TEMP\pstojson.json" 35 | $obj | ConvertTo-Json -Depth 99 | Set-Content -Path $path 36 | $imported = Get-Content -Path $Path 37 | $imported 38 | $imported | ConvertFrom-Json 39 | 40 | ############## 41 | # PROPERTIES # 42 | ############## 43 | 44 | # Accessing properties 45 | $obj.Species 46 | 47 | # Dynamically accessing properties 48 | $prop = 'Type' 49 | $obj.$prop 50 | 51 | # Adding property 52 | $obj | Add-Member -MemberType NoteProperty -Name 'Favourite Snack' -Value 'Dental treats' 53 | $obj.'Favourite Snack' 54 | 55 | # Removing properties 56 | $obj.psobject.Properties.Remove('Favourite Snack') 57 | $obj.'Favourite Snack' 58 | 59 | # Listing properteis 60 | $obj.psobject.properties.name 61 | $obj | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name 62 | 63 | ############# 64 | # Hashtable # 65 | ############# 66 | 67 | # Converting hashtable to psobject: 68 | $ht = @{ 69 | Name = "Mr Fiber" 70 | Species = "Domestic cat" 71 | Type = "Tabby cat" 72 | } 73 | $ht 74 | $htobj = [pscustomobject]$ht 75 | $htobj 76 | 77 | # Converting psobject to hashtable 78 | $newHt = @{} 79 | foreach ($property in $htobj.psobject.Properties.name) { 80 | $newHt[$property] = $htobj.$property 81 | } 82 | $newHt 83 | 84 | ########### 85 | # Methods # 86 | ########### 87 | 88 | # We can actually have some action! 89 | $method = { 90 | "Hi, my name is $($this.name) and I like to sleep." 91 | } 92 | 93 | $params = @{ 94 | MemberType = "ScriptMethod" 95 | Name = "SayHi" 96 | Value = $method 97 | } 98 | $obj | Add-Member @params 99 | $obj.SayHi() 100 | 101 | # How about, converting Object to Hashtable, as the actual method? 102 | $params = @{ 103 | MemberType = "ScriptMethod" 104 | Name = "OutHashtable" 105 | Value = { 106 | $hash = @{} 107 | $this.psobject.properties.name.foreach({ 108 | $hash[$_] = $this.$_ 109 | }) 110 | return $hash 111 | } 112 | } 113 | $obj | Add-Member @params 114 | $obj.OutHashtable() 115 | 116 | ######### 117 | # Types # 118 | ######### 119 | 120 | $obj | Get-Member # now it is PSCustomObject, duh 121 | 122 | $obj.psobject.TypeNames # this looks familiar 123 | $obj.psobject.TypeNames.Insert(0, "Kp.CatsAreAwesome") 124 | $obj | Get-Member 125 | 126 | function Invoke-CAA { 127 | param ( 128 | # We only accept parameter of type Kp.CatsAreAwesome 129 | [PSTypeName('Kp.CatsAreAwesome')] 130 | [Parameter(ValueFromPipeline)] 131 | $Cat 132 | ) 133 | 134 | # If $Cat has been passed, we call method SayHi(), otherwise we just say that cats are awesome (generally) 135 | if ($PSBoundParameters.ContainsKey('Cat')) { 136 | "Here's an awesome cat:" 137 | return $Cat.SayHi() 138 | } else { 139 | "Cats are awesome!" 140 | } 141 | } 142 | Invoke-CAA 143 | Invoke-Caa -Cat $obj 144 | Invoke-Caa -Cat "BLA" 145 | 146 | # We can also specify type name at creation 147 | $obj2 = [pscustomobject]@{ 148 | PSTypeName = 'Kp.CatsAreAwesome' 149 | Name = 'Whiskers' 150 | Species = "Domestic cat" 151 | Type = "Persian" 152 | } 153 | 154 | $method = { 155 | "Hi, my name is $($this.name) and I like to sleep." 156 | } 157 | 158 | $params = @{ 159 | MemberType = "ScriptMethod" 160 | Name = "SayHi" 161 | Value = $method 162 | } 163 | $obj2 | Add-Member @params 164 | $obj2 | Invoke-CAA 165 | 166 | # Specify default output 167 | Update-TypeData -TypeName kp.CatsAreAwesome -DefaultDisplayPropertySet Name,Type 168 | $obj # list is now limited to only Name and Type properties 169 | $obj2 170 | $obj | Format-List -Property * #displays all 171 | 172 | # Let's see arrays and pscustomobjects working together 173 | $list = [System.Collections.Generic.List[pscustomobject]]::new() 174 | $locations = @("London", "Sligo", "Barcelona", "Paphos", "Ubud", "Valdemosa") 175 | $baseUri = "wttr.in/" 176 | 177 | foreach ($location in $locations) { 178 | "Currently retrieving weather for: $location" 179 | $Uri = "{0}{1}?format=j1" -f $baseUri, $location 180 | $Uri 181 | $data = Invoke-RestMethod $Uri 182 | $result = [pscustomobject]@{ 183 | City = $Location 184 | Temperature = $data.current_condition.temp_C 185 | Pressure = $data.current_condition.pressure 186 | } 187 | $list.Add($result) 188 | } 189 | $list -------------------------------------------------------------------------------- /PowerShell Switch statement/Powershell Switch statement.ps1: -------------------------------------------------------------------------------- 1 | # Link to the video: https://youtu.be/EqJ0lBO1rM4 2 | 3 | # Documentation: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_switch?view=powershell-7.1 4 | 5 | # Basic version 6 | 7 | <# 8 | switch ( test-value ) { 9 | condition {do-stuff} 10 | another condition {do-stuff} 11 | } 12 | #> 13 | 14 | # This will print out Green 15 | switch (2) { 16 | 0 { "Blue" } 17 | 1 { "Yellow"} 18 | 2 { "Green"} 19 | 3 { "Red"} 20 | } 21 | 22 | # Work with variable 23 | $number = 1 24 | switch ($number) { 25 | 0 { "Blue" } 26 | 1 { "Yellow"} 27 | 2 { "Green"} 28 | 3 { "Red"} 29 | } 30 | 31 | # Assign variables within scriptblock 32 | $number = 3 33 | switch ($number) { 34 | 0 { $result = "Blue" } 35 | 1 { $result = "Yellow"} 36 | 2 { $result = "Green"} 37 | 3 { $result = "Red"} 38 | } 39 | Write-Host "The result is: $result" -ForegroundColor $result 40 | 41 | # We can also assign statement to variable 42 | $number = 0 43 | $result = switch ($number) { 44 | 0 { "Blue" } 45 | 1 { "Yellow"} 46 | 2 { "Green"} 47 | 3 { "Red"} 48 | } 49 | Write-Host "The result is: $result" -ForegroundColor $result 50 | 51 | # Use default in case there's no match 52 | $number = 8 53 | $result = switch ($number) { 54 | 0 { "Blue" } 55 | 1 { "Yellow"} 56 | 2 { "Green"} 57 | 3 { "Red"} 58 | default { 59 | Write-Warning "Unknown value, defaulting to White" 60 | "White" } 61 | } 62 | Write-Host "The result is: $result" -ForegroundColor $result 63 | 64 | # Strings can also be matched 65 | # This also shows working on expression 66 | switch ( (Get-Host).Name ) { 67 | "Visual Studio Code Host" { "You are using VS CODE" } 68 | "ConsoleHost" { "You are using Console!" } 69 | default {"Unknown host $_"} 70 | } 71 | 72 | # Arrays! 73 | $employees = @("Developer", "Project Manager", "DevOps Engineer", "Developer", "Sysadmin") 74 | switch ($employees) { 75 | "Developer" {"We need a Developer!"} 76 | "Project Manager" {"We need Project Manager"} 77 | "DevOps Engineer" {"We need DevOps Engineer"} 78 | "Sysadmin" {"We need Sysadmin"} 79 | } 80 | 81 | # Using script block, when comparing value 82 | $age = 25 83 | switch ($age) { 84 | {$_ -ge 18} { 85 | "It's an adult" 86 | } 87 | 88 | {$_ -lt 18} { 89 | "It's not an adult" 90 | } 91 | } 92 | 93 | # PowerShell will match multiple times 94 | switch ("something") { 95 | "something" {"This is lower case"} 96 | "SOMETHING" {"This is upper case"} 97 | "SomeTHinG" {"This is mixed"} 98 | } 99 | 100 | # Stop execution with break 101 | switch ("something") { 102 | "something" {"This is lower case"} 103 | "SOMETHING" {"This is upper case" 104 | break} 105 | "SomeTHinG" {"This is mixed"} 106 | } 107 | 108 | # Make test case sensitive 109 | switch -CaseSensitive ("something") { 110 | "something" {"This is lower case"} 111 | "SOMETHING" {"This is upper case"; break;} 112 | "SomeTHinG" {"This is mixed"} 113 | } 114 | 115 | # Enable wildcard 116 | switch -Wildcard ("Kamil") { 117 | "*Anna*" {"There's notification for Anna"} 118 | "*John*" {"There's notification for John"} 119 | "*Kamil*" {"There's notification for Kamil"} 120 | default {"Unknown"} 121 | } 122 | 123 | # Enable Regex 124 | switch -Regex ("Kamil") { 125 | "^Anna" {"There's notification for Anna"} 126 | "^John" {"There's notification for John"} 127 | "^Kamil" {"There's notification for Kamil"} 128 | default {"Unknown"} 129 | } -------------------------------------------------------------------------------- /PowerShell loops - For/PowerShell loops - For.ps1: -------------------------------------------------------------------------------- 1 | # Link to the video: https://youtu.be/YQnBVn-9SN0 2 | 3 | # Documentation: 4 | # https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_for?view=powershell-7.1 5 | 6 | # Basic syntax: 7 | 8 | # for (Initial Value/statement; Condition; Repeat) { Run my code } 9 | 10 | # Initial value: Set this is up before starting the loop 11 | # Condition: For loops ends, when condition evaluates to false; or it keep running as lon as condition is true 12 | # Repeat: Do this after every loop 13 | 14 | for ($MyVariable = 0; $MyVariable -lt 10; $MyVariable = $MyVariable + 1) { 15 | '$MyVariable is {0}' -f $MyVariable 16 | Start-Sleep -Seconds 2 17 | } 18 | 19 | for ($MyVariable = 0; $MyVariable -lt 99; $MyVariable++) { 20 | '$MyVariable is {0}' -f $MyVariable 21 | } 22 | 23 | # We can also decrease it 24 | for ($MyVariable = 10; $MyVariable -gt 5; $MyVariable = $MyVariable - 1) { 25 | '$MyVariable is {0}' -f $MyVariable 26 | } 27 | 28 | # or specify variable outside if 29 | $outside = 7 30 | for (; $outside -lt 15; $outside++) { 31 | '$Outside is {0}' -f $outside 32 | } 33 | 34 | #Looping through array 35 | $pets = @("Cat", "Dog", "Fish", "Turtle") 36 | $pets.Count 37 | 38 | $pets[2] 39 | 40 | "My pets in order:" 41 | for ($i = 0; $i -lt $pets.Count; $i++) { 42 | $pets[$i] 43 | } 44 | 45 | # How about I'd like to add numbers 46 | "" 47 | "My pets in order:" 48 | "" 49 | for ($i = 0; $i -lt $pets.Count; $i++) { 50 | $Number = $i + 1 51 | " {0}. {1}" -f $Number, $pets[$i] 52 | } 53 | 54 | # For also works with strings 55 | for ($text = ''; $text.Length -lt 10; $text += '@') { 56 | $text 57 | } 58 | 59 | # Nested for 60 | $row = 1..10 61 | $column = 1..10 62 | 63 | for ($i = 0; $i -lt $row.Count; $i++) { 64 | for ( $j = 0; $j -lt $column.Count; $j++) { 65 | 66 | $r = $row[$i] 67 | $c = $column[$j] 68 | $result = $r * $c 69 | 70 | $t = "{0} * {1} = {2}" -f $r, $c, $result 71 | Write-Host $t 72 | } 73 | } 74 | 75 | # It never ends... We need to break with CTRL - C 76 | for ( $i = 0 ; ; $i++ ) { 77 | "Loop number: $I" 78 | } 79 | 80 | # Or we can break when certain condition is met 81 | for ( $i = 0 ; ; $i++ ) { 82 | "Loop number: $I" 83 | if ($i -eq 1000) { 84 | "Breaking out" 85 | break 86 | } 87 | } 88 | 89 | # A real case scenario with Azure Application Insigts 90 | 91 | $Headers = @("First Name", "Email", "Phone Number") 92 | 93 | $Rows = @( 94 | @("Kamil", "kamil@kamil.mail", "111-111-111"), 95 | @("John", "john@john.mail", "222-222-222"), 96 | @("Abigail", "abigail@abigail.mail", "333-333-333") 97 | ) 98 | 99 | # List is like an array, however it allows to add new entries to it 100 | $result = New-Object System.Collections.Generic.List[System.Object] 101 | 102 | # We work with one record at the time 103 | foreach ($row in $Rows) { 104 | 105 | # We need a blank PowerShell object. Notice we don't specify any properties up front 106 | $record = [PSCustomObject]@{} 107 | 108 | # Now we are going to iterate through each property in the row 109 | for ($i = 0; $i -lt $Headers.Count; $i++) { 110 | 111 | # Since we are working with PowerShell object, we can add members 112 | # Notice we use index for both name and value 113 | $record | Add-Member -MemberType NoteProperty -Name $Headers[$i] -Value $row[$i] 114 | } 115 | # We add completed object object to the list 116 | $result.Add($record) 117 | } 118 | #Display list with all records 119 | $result -------------------------------------------------------------------------------- /PowerShell loops - For/for.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thekamilpro/About-PowerShell/a48ced4b18e07bd3b129debc8f09de6e6c55467d/PowerShell loops - For/for.drawio.png -------------------------------------------------------------------------------- /Powershell If statement - controlling the flow of your code/Powershell If statement.ps1: -------------------------------------------------------------------------------- 1 | # Link to the video: https://youtu.be/j8Ubwv8ApdU 2 | 3 | # Documentation: 4 | # Operators: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_operators?view=powershell-7.1 5 | # About If: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_if?view=powershell-7.1 6 | 7 | # Basic version 8 | # if something is true then do this 9 | 10 | if ($true) { "This is true" } 11 | 12 | if ($false) { "This is false" } 13 | 14 | # if something is true then do this, otherwise do that 15 | 16 | if ($true) { "This is true" } else { "This is false" } 17 | 18 | if ($false) { "This is true" } else { "This is false" } 19 | 20 | # let's do some actual example 21 | if ( 5 -gt 3 ) { "This is more!" } else { "This is less!" } 22 | 23 | # we can also compare against variables. 24 | $random = Get-Random -Minimum 1 -Maximum 11; $random 25 | if ($random -ge 5) { "$Random is more than 5!" } else { "$Random is less than 5!" } 26 | 27 | # running functions and assigning them directly in the statement 28 | if ( ($random = Get-Random -Minimum 1 -Maximum 11) -ge 5) { "$Random is more than 5!" } else { "$Random is less than 5!" } 29 | 30 | $number = 5 31 | if ( ($random = Get-Random -Minimum 1 -Maximum 11) -ge $number) { "$Random is more than 5!" } else { "$Random is less than 5!" } 32 | 33 | #Checking if variable exists 34 | if ($nonExisting -eq $true) { "That variable exists!" } else { "It doesn't exist" } 35 | 36 | if ($user) { "User exists" } else { "User doesn't exist" } 37 | 38 | $user = @{} 39 | $user['Name'] = 'Geralt' 40 | $user['Surname'] = 'of Rivia' 41 | $user 42 | if ($user) { "User exists" } else { "User doesn't exist" } 43 | 44 | #We can do more complex operations 45 | if ($user) { 46 | $email = '{0}.{1}@novigrad.com' -f $user.Name, $user.Surname -replace ' ', '' 47 | "Found user: $($user.Name) $($user.Surname)" 48 | "Email for user: {0}" -f $email.ToLower() 49 | } 50 | 51 | #Like operator 52 | if ($email -like "*Rivia*") { "Email has Rivia in it!" } 53 | 54 | #We can check if something is not true 55 | if ( -not $user1 ) { "This user doesn't exist" } 56 | if ( !$user1 ) { "This user doesn't exist" } 57 | 58 | # More complex logic 59 | if ( $user.Name -eq "Geralt" -AND $user.Surname -eq "of Rivia" ) { "User Exists" } 60 | if ( $user.Name -eq "Geralt" -AND $user.Surname -eq "of Rivia" -AND $user1 ) { "User Exists" } 61 | 62 | # Splitting statement accross different lines 63 | if ( $user.Name -eq "Geralt" -OR 64 | $user.Surname -eq "of Rivia" -OR 65 | $user1 ) { 66 | "User Exists" 67 | } 68 | 69 | # Testing if folder exists 70 | $Folder = "C:\Windows" 71 | if ( Test-Path -Path $Folder ) { "Folder: $Folder Exists!" } 72 | 73 | #Nested IF Statements 74 | if ($user.Name -eq "Geralt") { 75 | if ($user.Surname -eq "of Rivia") { 76 | if ( $email) { 77 | "User created successfully" 78 | } 79 | else { 80 | "User's email is not created" 81 | } 82 | } 83 | else { 84 | "Users surname is not created" 85 | } 86 | } 87 | else { 88 | "User's name is not set" 89 | } 90 | 91 | #Multiple if else statements 92 | $Today = (Get-Date).DayOfWeek 93 | 94 | if ($today -eq "Monday" -or $today -eq "Tuesday" -or $today -eq "Wednesday" -or $today -eq "Thursday" -or $today -eq "Friday") { 95 | "Today is Working day" 96 | } 97 | elseif ($today -eq "Saturday") { 98 | "Today is first day of the weekend" 99 | } 100 | elseif ($today -eq "Sunday") { 101 | "Today is the last of week. Tomorrow we begin a new week." 102 | } 103 | else { 104 | "Unknown day: $today" 105 | } 106 | 107 | #Switch 108 | switch ($today) { 109 | { $_ -in ( "Monday", "Tuesday", "Wednesday", "Thursday", "Friday") } { "Today is working day" } 110 | "Saturday" { "Today is first day of the weekend" } 111 | "Sunday" { "Today is the last day of the week." } 112 | default { "Unknown day: $today" } 113 | } 114 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # About-PowerShell 2 | 3 | About PowerShell is educational series of videos that teach you about different aspects of PowerShell usage. 4 | 5 | In this repository, you can find all code I've been using with "About PowerShell" series on YouTube, alongside to the link to the video so that you can jump straight in! 6 | 7 | [YouTube channel](https://www.youtube.com/c/KamilPro) 8 | [About PowerShell playlist](https://www.youtube.com/playlist?list=PL-esmhgrps8Zv9bAHesStPRQ1AiUL1wY3) 9 | 10 | ## Videos in the series 11 | 12 | [Conference Speach - PSDayUk 2023 - Developing a Web Application with PowerShell](https://www.youtube.com/watch?v=3m1RKykoWtU) 13 | 14 | [PowerShell Error Handling - One error at the time please](https://youtu.be/-rQTBuaIVS8) 15 | 16 | [Developing a Web Application with PowerShell - Pode, the PowerFul Module](https://youtu.be/N-yjDGzEYak) 17 | 18 | [Building PowerShell module on Azure DevOps pipeline - step by step guide](https://youtu.be/RZzmdF1iI7E) 19 | 20 | [Building PowerShell Module - how to organise your source files and build with ease](https://youtu.be/lKO_LPMfV1Y) 21 | 22 | [PowerShell Module and Manifest- create and configure your tools](https://youtu.be/xPQq0ui8j78) 23 | 24 | [PowerShell Parameter Attributes - validate, group, require params and add pipeline to your function](https://youtu.be/hJIAK3qjlZQ) 25 | 26 | [PowerShell function - converting script into function with parameters](https://youtu.be/VGzEbEUfZCU) 27 | 28 | [PowerShell PSCustomObject - Custom Object, the way it was meant to be](https://youtu.be/DAVGyCytsqM) 29 | 30 | [PowerShell Hash Table - Storing key value pairs](https://youtu.be/oti2l8EmAT8) 31 | 32 | [PowerShell Switch Statement - Different take on branching](https://youtu.be/EqJ0lBO1rM4) 33 | 34 | [PowerShell For loop](https://youtu.be/YQnBVn-9SN0) 35 | 36 | [PowerShell If statement - controlling the flow of your code](https://youtu.be/j8Ubwv8ApdU) 37 | -------------------------------------------------------------------------------- /Shorts/Array/1.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | $array = @() 3 | $array.Count 4 | 5 | Clear-Host 6 | $array2 = @("Jules", "Walker", "Solo") 7 | $array2.Count 8 | $array2 9 | 10 | Clear-Host 11 | $array3 = 1..50 12 | $array3 -------------------------------------------------------------------------------- /Shorts/Array/2.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | $array = @("Jules", "Walker", "Solo") 3 | $array[0] 4 | 5 | Clear-Host 6 | $array = @("Jules", "Walker", "Solo") 7 | $array[-1] 8 | -------------------------------------------------------------------------------- /Shorts/Array/3.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | $array = @("Blue", "Green") 3 | $array 4 | 5 | Write-Host "======" 6 | $array += "Yellow" 7 | $array -------------------------------------------------------------------------------- /Shorts/Array/4.ps1: -------------------------------------------------------------------------------- 1 | $data = 1,2,3,4,5 2 | $data 3 | 4 | Write-Host "===" 5 | 6 | $data[0] = "A" 7 | $data[2] = "C" 8 | $data[4] = "E" 9 | $data -------------------------------------------------------------------------------- /Shorts/For/1.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | #Basic loop construct 3 | for ($i = 0; $i -lt 10; $i++) 4 | { 5 | Write-Host $i 6 | } -------------------------------------------------------------------------------- /Shorts/For/2.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | #Now oposite 3 | for ($i = 10; $i -ne 0; $i--) 4 | { 5 | Write-Host $i 6 | } -------------------------------------------------------------------------------- /Shorts/For/3.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | #Iterating over some data 3 | $data = @("Holden", "Burton", "Nagata") 4 | 5 | # $data[1] is Burton 6 | 7 | for ($i = 0; $i -lt $data.Length; $i++) 8 | { 9 | Write-Host "Character: $($data[$i])" 10 | } -------------------------------------------------------------------------------- /Shorts/ForEach/1.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | #Basic foreach use 3 | $users = @("Geralt", "Triss", "Yenefer") 4 | 5 | foreach ($user in $users) 6 | { 7 | Write-Host $user 8 | } -------------------------------------------------------------------------------- /Shorts/ForEach/2.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | #BREAK out of the loop 3 | $users = @("Geralt", "Triss", "Yenefer") 4 | 5 | foreach ($user in $users) 6 | { 7 | if ($user -eq "Triss") 8 | { 9 | break 10 | } 11 | Write-Host $user 12 | } -------------------------------------------------------------------------------- /Shorts/ForEach/3.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | #SKIP item from the loop 3 | $users = @("Geralt", "Triss", "Yenefer") 4 | 5 | foreach ($user in $users) 6 | { 7 | if ($user -eq "Triss") 8 | { 9 | continue 10 | } 11 | Write-Host $user 12 | } -------------------------------------------------------------------------------- /Shorts/ForEach/4.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | #Create iteration 3 | $users = @("Geralt", "Triss", "Yenefer") 4 | 5 | $i = 1 6 | foreach ($user in $users) 7 | { 8 | Write-host "Doing: $i" 9 | Write-Host $user 10 | $i++ 11 | } -------------------------------------------------------------------------------- /Shorts/Generic-List/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "powershell.codeFormatting.openBraceOnSameLine": false 3 | } -------------------------------------------------------------------------------- /Shorts/Generic-List/1.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | Write-Host "Create a list of type Integer" 3 | $list = [System.Collections.Generic.List[int]]::new() 4 | $list.Count -------------------------------------------------------------------------------- /Shorts/Generic-List/2.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | Write-Host "Add items to list" 3 | $list = [System.Collections.Generic.List[int]]::new() 4 | $list.Add(5) 5 | $list.Add(9) 6 | Write-Host "Count: $($list.Count) First: $($list[0])" 7 | 8 | Write-Host "This will fail" 9 | $list.Add("Hi!") -------------------------------------------------------------------------------- /Shorts/Generic-List/3.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | Write-Host "Update items in the list" 3 | $list = [System.Collections.Generic.List[int]]::new() 4 | $list.Add(5) 5 | $list.Add(9) 6 | Write-Host "Item: $($list[1])" 7 | $list[1] = 128 8 | Write-Host "Item: $($list[1])" -------------------------------------------------------------------------------- /Shorts/Generic-List/4.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | Write-Host "Array vs List when adding" 3 | $array = @() 4 | $list = [System.Collections.Generic.List[string]]::new() 5 | 6 | $listTime = Measure-Command { 7 | foreach ($i in 1..100000) 8 | { 9 | $list.Add("Hi $i") 10 | } 11 | } 12 | 13 | Write-Host "List seconds: $($listTime.TotalSeconds)" 14 | 15 | $arrayTime = Measure-Command { 16 | foreach ($i in 1..100000) 17 | { 18 | $array += ("Hi $i") 19 | } 20 | } 21 | 22 | Write-Host "Array seconds: $($arrayTime.TotalSeconds)" -------------------------------------------------------------------------------- /Shorts/Help/1.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | function Get-CatFact 3 | { 4 | [CmdletBinding(DefaultParameterSetName = "byRandom")] 5 | param( 6 | [Parameter(ParameterSetName = "byRandom")] 7 | [switch]$Random, 8 | 9 | [Parameter(Mandatory, ParameterSetName = "byId")] 10 | [string]$ID 11 | ) 12 | 13 | $url = if ($PSCmdlet.ParameterSetName -eq "byRandom") 14 | { 15 | "https://cat-fact.herokuapp.com/facts/random" 16 | } 17 | else 18 | { 19 | "https://cat-fact.herokuapp.com/facts/$id" 20 | } 21 | $response = Invoke-RestMethod -Uri $url 22 | return $response 23 | } 24 | help Get-CatFact -Full -------------------------------------------------------------------------------- /Shorts/Help/2.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | function Get-CatFact 3 | { 4 | <# 5 | .Synopsis 6 | Gets a random cat fact from the cat fact API. 7 | .Description 8 | Function allows to retrieve a random fact about cats of specific one based on ID. 9 | .PARAMETER Random 10 | Gets a random cat fact from the cat fact API. 11 | .PARAMETER ID 12 | Retrieve specific cat fact 13 | .Example 14 | Get-CatFact 15 | Retrieves a random fact (same as with -Random switch) 16 | .EXAMPLE 17 | Get-CatFact -ID 5c72dbd851021f001415f010 18 | Retrieves a specific fact 19 | .LINK 20 | Documentation: https://alexwohlbruck.github.io/cat-facts/docs/ 21 | .NOTES 22 | Free PowerShell course and ebook - kamilpro.com 23 | #> 24 | [CmdletBinding(DefaultParameterSetName = "byRandom")] 25 | param( 26 | [Parameter(ParameterSetName = "byRandom")] 27 | [switch]$Random, 28 | 29 | [Parameter(Mandatory, ParameterSetName = "byId")] 30 | [string]$ID 31 | ) 32 | $url = if ($PSCmdlet.ParameterSetName -eq "byRandom") 33 | { 34 | "https://cat-fact.herokuapp.com/facts/random" 35 | } 36 | else 37 | { 38 | "https://cat-fact.herokuapp.com/facts/$id" 39 | } 40 | $response = Invoke-RestMethod -Uri $url 41 | return $response 42 | } 43 | help Get-CatFact -Full -------------------------------------------------------------------------------- /Shorts/If/1.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | $witcherIsTheBestBookSeriesEverWritten = $true 3 | 4 | #-eq $True is implicit 5 | if ($witcherIsTheBestBookSeriesEverWritten) 6 | { 7 | Write-Host "I win" 8 | } 9 | 10 | if ($witcherIsTheBestBookSeriesEverWritten -eq $false) 11 | { 12 | Write-Host "You loose" 13 | } -------------------------------------------------------------------------------- /Shorts/If/2.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | 3 | $number = Get-Random -Maximum 15 4 | 5 | if ($number -le 9) 6 | { 7 | Write-Host "Number [$Number] is less than 10" 8 | } 9 | else 10 | { 11 | Write-Host "Number [$Number] is 10 or more" 12 | } -------------------------------------------------------------------------------- /Shorts/If/3.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | function Get-RandomDay 3 | { 4 | $random = [System.Random]::new() 5 | $date = [datetime]::new(2024, 1, 1) 6 | $range = ([datetime]::Today - $date).Days 7 | $output = $date.AddDays($random.Next($range)) 8 | return $output.DayOfWeek 9 | } 10 | 11 | $day = Get-RandomDay 12 | Write-Host "Random day: $day" 13 | if ($day -in @('Monday', 'Tuesday','Wednesday', 'Thursday')) 14 | { 15 | Write-Host "Work Work" 16 | } 17 | elseif ($day -eq 'Friday') 18 | { 19 | Write-Host "It's practically a weekend" 20 | } 21 | else 22 | { 23 | Write-Host "Weekend!" 24 | } -------------------------------------------------------------------------------- /Shorts/Param/1.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | 3 | $value = Read-Host -Prompt "Provide some number" 4 | return $value + 1 -------------------------------------------------------------------------------- /Shorts/Param/2.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | $Value 3 | ) 4 | 5 | return $value + 1 -------------------------------------------------------------------------------- /Shorts/Param/3.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [int]$Value 3 | ) 4 | 5 | return $value + 1 -------------------------------------------------------------------------------- /Shorts/Param/4.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [Parameter(Mandatory)] 3 | [int]$Value 4 | ) 5 | 6 | return $value + 1 -------------------------------------------------------------------------------- /Shorts/Pipeline-User/1.ps1: -------------------------------------------------------------------------------- 1 | $app = Get-Command -Name pwsh 2 | $app.Path 3 | $app.Path | Get-Item 4 | 5 | Get-Process -Name pwsh 6 | 7 | #This doesn't work - why? 8 | "pwsh" | Get-Process 9 | 10 | #This works 11 | [pscustomobject]@{Name = "pwsh"} | Get-Process 12 | 13 | -------------------------------------------------------------------------------- /Shorts/Pipeline-User/2.ps1: -------------------------------------------------------------------------------- 1 | #We need to read the help 2 | help Get-Item -Parameter Path | Out-Host 3 | 4 | #Path accepts String by Value, how to check type? 5 | "ABC" | Get-Member 6 | 7 | "/usr/local/microsoft/powershell/7/pwsh" | Get-Item 8 | 9 | -------------------------------------------------------------------------------- /Shorts/Pipeline-User/3.ps1: -------------------------------------------------------------------------------- 1 | help Get-Process -Parameter Name | Out-Host 2 | 3 | [pscustomobject]@{Name = "pwsh"} | Get-Process 4 | 5 | [pscustomobject]@{Name = "pwsh"; Rubbish = $True} | Get-Process 6 | 7 | help Stop-Process -Parameter InputObject | Out-Host 8 | 9 | Get-Process -Id $pid 10 | Get-Process -Id $pid | Get-Member 11 | 12 | #Stop process expectes System.Diadnostic.Process, which is what Get-Process outputs. So it should work 13 | Get-Process -Id $pid | Stop-Process -------------------------------------------------------------------------------- /Shorts/Switch/1.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | 3 | $person = "Holden" 4 | 5 | $role = switch ($person) 6 | { 7 | "Burton" { "Mechanic" } 8 | "Nagata" { "Engineer" } 9 | "Holden" { "Captain" } 10 | "Kamal" { "Pilot" } 11 | } 12 | 13 | Write-Host "Person: [$person] is [$role]" 14 | 15 | #we could as well use a hashtable for this example -------------------------------------------------------------------------------- /Shorts/Switch/2.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | 3 | $person = "Nagata" 4 | 5 | $role = switch ($person) 6 | { 7 | {$_ -like "B*"} { "Mechanic" } 8 | {$_ -like "N*"} { "Engineer" } 9 | {$_ -like "H*"} { "Captain" } 10 | {$_ -like "K*"} { "Pilot" } 11 | } 12 | 13 | Write-Host "Person: [$person] is [$role]" -------------------------------------------------------------------------------- /Shorts/Switch/3.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | 3 | switch (7) 4 | { 5 | 1 {"It is one."} 6 | 2 {"It is two."} 7 | 3 {"It is three."} 8 | 4 {"It is four."} 9 | 3 {"Three again."} 10 | default {"Unknown number: $_"} 11 | } --------------------------------------------------------------------------------