Repository: techthoughts2/Learn-PowerShell-Code-Examples Branch: master Commit: 332cc9dfe274 Files: 21 Total size: 78.3 KB Directory structure: gitextract_gc06ac9l/ ├── .github/ │ └── CODE_OF_CONDUCT.md ├── .vscode/ │ ├── extensions.json │ ├── settings.json │ └── tasks.json ├── LICENSE ├── LearnPowerShell/ │ ├── EP1 - PowerShell Basics.ps1 │ ├── EP10 - PowerShell Script.ps1 │ ├── EP11 - PowerShell Functions.ps1 │ ├── EP12 - Manage Cloud with PowerShell.ps1 │ ├── EP13 - PowerShell Modules/ │ │ ├── EP13 - PowerShell Modules.ps1 │ │ └── LearnPowerShell/ │ │ ├── LearnPowerShell.psd1 │ │ └── LearnPowerShell.psm1 │ ├── EP2 - PowerShell Pipeline.ps1 │ ├── EP3 - State of the Shell.ps1 │ ├── EP4 - PowerhShell Development.ps1 │ ├── EP5 - PowerShell Variables.ps1 │ ├── EP6 - PowerShell Logic.ps1 │ ├── EP7 - PowerShell Input Output.ps1 │ ├── EP8 - PowerShell Error Handling.ps1 │ └── EP9 - PowerShell Remoting.ps1 └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at tech@techthoughts.info. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [https://www.contributor-covenant.org/version/1/4/code-of-conduct.html](https://www.contributor-covenant.org/version/1/4/code-of-conduct.html) [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see [https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq) ================================================ FILE: .vscode/extensions.json ================================================ { // See http://go.microsoft.com/fwlink/?LinkId=827846 // for the documentation about the extensions.json format "recommendations": [ "ms-vscode.PowerShell", "streetsidesoftware.code-spell-checker" ] } ================================================ FILE: .vscode/settings.json ================================================ { "powershell.codeFormatting.preset": "Stroustrup", "cSpell.words": [ "COMPUTERNAME", "creds", "imgur", "ipify", "jakemorrison", "learnpowershell", "newcsv", "notcontains", "pkgs", "Pubkey", "quickconfig", "RAXDC", "Remoting", "sshs", "Stroustrup", "techthoughts", "techthoughtscontainer", "techthoughtsstorage", "USCS", "westus" ] } ================================================ FILE: .vscode/tasks.json ================================================ // Available variables which can be used inside of strings. // ${workspaceRoot}: the root folder of the team // ${file}: the current opened file // ${relativeFile}: the current opened file relative to workspaceRoot // ${fileBasename}: the current opened file's basename // ${fileDirname}: the current opened file's dirname // ${fileExtname}: the current opened file's extension // ${cwd}: the current working directory of the spawned process { // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format "version": "2.0.0", // Start PowerShell "windows": { "options": { "shell": { //"executable": "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", // "executable": "C:\\Program Files\\PowerShell\\6\\pwsh.exe", "executable": "${env:ProgramFiles}/PowerShell/7/pwsh.exe", "args": [ "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command" ] } } }, "linux": { "options": { "shell": { "executable": "/usr/bin/pwsh", "args": [ "-NoProfile", "-Command" ] } } }, "osx": { "options": { "shell": { "executable": "/usr/local/bin/pwsh", "args": [ "-NoProfile", "-Command" ] } } } } ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2022 Jake Morrison Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: LearnPowerShell/EP1 - PowerShell Basics.ps1 ================================================ #____________________________________________________________ # https://www.techthoughts.info/learn-and-use-powershell-with-just-three-commands/ #____________________________________________________________ # your first cmdlet - getting timezone information Get-TimeZone #____________________________________________________________ # Get-Command Get-Command * # An asterisk (*) in many languages acts as a wildcard. This syntax is saying: get me ALL of the commands Get-Command *process* # the wild cards around process will find ANY command that contains the word process # Get-Command can't always find everything, you may have to Google Get-Command *file* #____________________________________________________________ # Get-Help # Windows Users: Get-Help Stop-Process #Linux/MacOs Users Get-Help Stop-Process -Online Get-Help Stop-Process -Examples #____________________________________________________________ # Get-Member Get-Date | Get-Member Get-Random | Get-Member #____________________________________________________________ # Expand the available viewable properties of a cmdlet with Format-List Get-Date | Format-List #____________________________________________________________ # Find-Module Find-Module -Tag Telegram #____________________________________________________________ ================================================ FILE: LearnPowerShell/EP10 - PowerShell Script.ps1 ================================================ #____________________________________________________________ # https://www.techthoughts.info/powershell-scripts/ #____________________________________________________________ #region links #About Execution Policies #https://docs.microsoft.com/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-6 #About Scripts #https://docs.microsoft.com/powershell/module/microsoft.powershell.core/about/about_scripts?view=powershell-6 #endregion #region running scripts #get the execution policy of all scopes in the order of precedence Get-ExecutionPolicy -List #change execution policy Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser #unblock a script downloaded from the internet after you have read and understood the code Unblock-File -Path .\drive_warn.ps1 #run a local script .\drive_warn.ps1 #run a local script in the current scope . .\drive_warn.ps1 #endregion #region script example param ( [Parameter(Mandatory = $true)] [string] $Drive ) if ($PSVersionTable.Platform -eq 'Unix') { $logPath = '/tmp' } else { $logPath = 'C:\Logs' #log path location } #need linux path $logFile = "$logPath\driveCheck.log" #log file #verify if log directory path is present. if not, create it. try { if (-not (Test-Path -Path $logPath -ErrorAction Stop )) { # Output directory not found. Creating... New-Item -ItemType Directory -Path $logPath -ErrorAction Stop | Out-Null New-Item -ItemType File -Path $logFile -ErrorAction Stop | Out-Null } } catch { throw } Add-Content -Path $logFile -Value "[INFO] Running $PSCommandPath" #verify that the required Telegram module is installed. if (-not (Get-Module -ListAvailable -Name PoshGram)) { Add-Content -Path $logFile -Value '[INFO] PoshGram not installed.' throw } else { Add-Content -Path $logFile -Value '[INFO] PoshGram module verified.' } #get hard drive volume information and free space try { if ($PSVersionTable.Platform -eq 'Unix') { $volume = Get-PSDrive -Name $Drive -ErrorAction Stop #verify volume actually exists if ($volume) { $total = $volume.Free + $volume.Used $percentFree = [int](($volume.Free / $total) * 100) Add-Content -Path $logFile -Value "[INFO] Percent Free: $percentFree%" } else { Add-Content -Path $logFile -Value "[ERROR] $Drive was not found." throw } } else { $volume = Get-Volume -ErrorAction Stop | Where-Object { $_.DriveLetter -eq $Drive } #verify volume actually exists if ($volume) { $total = $volume.Size $percentFree = [int](($volume.SizeRemaining / $total) * 100) Add-Content -Path $logFile -Value "[INFO] Percent Free: $percentFree%" } else { Add-Content -Path $logFile -Value "[ERROR] $Drive was not found." throw } } } catch { Add-Content -Path $logFile -Value '[ERROR] Unable to retrieve volume information:' Add-Content -Path $logFile -Value $_ throw } #evaluate if a message needs to be sent if the drive is below 20GB free space if ($percentFree -le 20) { try { Import-Module PoshGram -ErrorAction Stop Add-Content -Path $logFile -Value '[INFO] PoshGram imported successfully.' } catch { Add-Content -Path $logFile -Value '[ERROR] PoshGram could not be imported:' Add-Content -Path $logFile -Value $_ throw } Add-Content -Path $logFile -Value '[INFO] Sending Telegram notification' $messageSplat = @{ BotToken = "#########:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ChatID = "-#########" Message = "[LOW SPACE] Drive at: $percentFree%" ErrorAction = 'Stop' } try { Send-TelegramTextMessage @messageSplat Add-Content -Path $logFile -Value '[INFO] Message sent successfully' } catch { Add-Content -Path $logFile -Value '[ERROR] Error encountered sending message:' Add-Content -Path $logFile -Value $_ throw } } #endregion ================================================ FILE: LearnPowerShell/EP11 - PowerShell Functions.ps1 ================================================ #____________________________________________________________ # https://www.techthoughts.info/powershell-functions/ #____________________________________________________________ #region links #Functions #https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_functions?view=powershell-7 #Parameters #https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_parameters?view=powershell-7 #Functions Advanced #https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_functions_advanced?view=powershell-7 #Functions Advanced Parameters #https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_functions_advanced_parameters?view=powershell-7 #PowerShell Approved Verbs #https://docs.microsoft.com/en-us/powershell/scripting/developer/cmdlet/approved-verbs-for-windows-powershell-commands?view=powershell-7 #CmdletBindingAttribute #https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_functions_cmdletbindingattribute?view=powershell-7 #endregion # ---------------------------------------------- # Anatomy of a PowerShell Function # ---------------------------------------------- # function help - (optional but strongly encouraged) # function name # CmdletBinding - (optional) # parameters - (optional) # function logic (optional Begin / Process / End) # return - (optional) function Verb-Noun { [CmdletBinding()] param ( ) begin { } process { } end { } } # ---------------------------------------------- # function Help # ---------------------------------------------- <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE C:\PS> Example of how to use this cmdlet .EXAMPLE C:\PS> Another example of how to use this cmdlet .PARAMETER InputObject Specifies the object to be processed. You can also pipe the objects to this command. .OUTPUTS Output from this cmdlet (if any) .NOTES General notes .COMPONENT The component this cmdlet belongs to #> # ---------------------------------------------- # function CmdletBinding # ---------------------------------------------- [CmdletBinding()] # ---------------------------------------------- # function parameters # ---------------------------------------------- <# .SYNOPSIS Returns weather report information. .DESCRIPTION Console-oriented weather forecast that returns weather information for specified parameters. .EXAMPLE Get-Weather Returns full weather information based on the location of your IP with all defaults. .EXAMPLE Get-Weather -Short Returns basic weather information based on the location of your IP. .EXAMPLE Get-Weather -City 'London' -Units Metric -Language 'en' Returns full weather information for the city of London in Metric units with UK language. .EXAMPLE Get-Weather -City 'San Antonio' -Units USCS -Short Returns basic weather information for the city of San Antonio in United State customary units. .PARAMETER City The city you would like to get the weather from. If not specified the city of your IP is used. .PARAMETER Units Units to display Metric vs United States customary units .PARAMETER Language Language to display results in .PARAMETER Short Will return only basic weather information .NOTES https://github.com/chubin/wttr.in https://wttr.in/:help #> function Get-Weather { [CmdletBinding()] param ( [Parameter( Position = 0, Mandatory = $false )] [string] $City, [Parameter(Position = 1)] [ValidateSet('Metric', 'USCS')] [string] $Units = 'USCS', [Parameter(Position = 2)] [ValidateSet('ar', 'af', 'be', 'ca', 'da', 'de', 'el', 'en', 'et', 'fr', 'fa', 'hu', 'ia', 'id', 'it', 'nb', 'nl', 'pl', 'pt-br', 'ro', 'ru', 'tr', 'th', 'uk', 'vi', 'zh-cn', 'zh-tw')] [string] $Language = 'en', [Parameter(Position = 3)] [switch] $Short ) $uriString = 'https://wttr.in/' if ($City) { $uriString += "$City" } switch ($Units) { 'Metric' { $uriString += "?m" } 'USCS' { $uriString += "?u" } } if ($Short) { $uriString += "&format=4" } $uriString += "&lang=$Language" Write-Verbose "URI: $uriString" $invokeSplat = @{ Uri = $uriString ErrorAction = 'Stop' } try { Invoke-RestMethod @invokeSplat } catch { Write-Error $_ } }#Get-Weather # ---------------------------------------------- # Begin Process End # ---------------------------------------------- function Get-PipelineBeginEnd { param ( [string]$SomeInput ) begin { "Begin: The input is $SomeInput" } process { "The value is: $_" } end { "End: The input is $SomeInput" } }#Get-PipelineBeginEnd 1, 2, 3 | Get-PipelineBeginEnd -SomeInput 'Test' # ---------------------------------------------- # Function Return # ---------------------------------------------- function Get-Total { param ( [int]$Number1, [int]$Number2 ) $total = $Number1 + $Number2 return $total } Get-Total -Number1 2 -Number2 2 # ---------------------------------------------- # First Function # ---------------------------------------------- <# .SYNOPSIS Returns your public IP address. .DESCRIPTION Queries the ipify Public IP Address API and returns your public IP. .EXAMPLE Get-PublicIP Returns the public IP. .OUTPUTS System.String .NOTES https://github.com/rdegges/ipify-api #> function Get-PublicIP { $uri = 'https://api.ipify.org' try { $invokeRestMethodSplat = @{ Uri = $uri ErrorAction = 'Stop' } $publicIP = Invoke-RestMethod @invokeRestMethodSplat } catch { Write-Error $_ } return $publicIP }#Get-PublicIP # ---------------------------------------------- # Function Scope # ---------------------------------------------- function Get-NumberTimesTwo { [CmdletBinding()] param ( [int]$Number ) $total = $Number * 2 Write-Debug $total return $total }#Get-NumberTimesTwo Get-NumberTimesTwo -Number 2 -Debug <# .SYNOPSIS Launches the default browser to display reddit pictures. .DESCRIPTION Long description .EXAMPLE Show-Pics -URL https://i.imgur.com/fcuRqwl.jpg Launches default browser to provided link. .EXAMPLE $severalURLs | Show-Pics Launches default browser tab for each provided link. .PARAMETER URL i.redd.it or v.redd.it or imgur URL .NOTES Jake Morrison - @jakemorrison - https://www.techthoughts.info #> function Show-Pics { [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, HelpMessage = 'i.redd.it or v.redd.it or imgur URL')] [ValidatePattern('i.redd.it|v.redd.it|imgur')] [string]$URL ) begin { Write-Verbose "Starting Show-Pics function." } process { try { Start-Process $URL -ErrorAction Stop Write-Verbose "Browser launch successful." } catch { Write-Error $_ } } end { Write-Verbose "All done." } }#Show-Pics <# .SYNOPSIS PowerShell based interactive reddit browser .DESCRIPTION Uses PowerShell to establish a connection to reddit and pulls down a JSON payload for the specified subreddit. The number of threads (default 3) specified by the user is then evaluated and output to the console window. If the thread is picture-based the user has the option to display those images in their native browser. .PARAMETER Subreddit The name of the desired subreddit - Ex PowerShell or aww .PARAMETER Threads The number of threads that will be pulled down - the default is 3 .PARAMETER ShowPics Determines if pics will be shown (if available) .EXAMPLE Get-Reddit -Subreddit PowerShell Retrieves the top 3 threads of the PowerShell subreddit .EXAMPLE Get-Reddit -Subreddit aww -Threads 4 -ShowPics Retrieves the top 4 threads of the aww subreddit and if pictures are available, displays them in the native browser .NOTES Jake Morrison - @jakemorrison - https://www.techthoughts.info #> function Get-Reddit { [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $false, Position = 1, HelpMessage = 'The name of the desired subreddit')] [string]$Subreddit, [Parameter(Mandatory = $false, ValueFromPipeline = $false, Position = 2, HelpMessage = 'The number of threads that will be pulled down')] [ValidateRange(1, 25)] [int]$Threads = 3, [Parameter(Mandatory = $false, ValueFromPipeline = $false, Position = 3, HelpMessage = 'Determines if pics will be shown (if available)')] [switch]$ShowPics ) Write-Verbose "Specified subreddit: $Subreddit" Write-Verbose "Specified # of threads: $Threads" $results = [System.Collections.ArrayList]@() Write-Verbose "Initiating Download" $uri = "http://www.reddit.com/r/$Subreddit/.json" Write-Verbose "URI: $uri" try { $invokeWebRequestSplat = @{ Uri = $uri ErrorAction = 'Stop' } $rawReddit = Invoke-WebRequest @invokeWebRequestSplat Write-Verbose "Download successful." } catch { Write-Error $_ return $results } if ($rawReddit) { Write-Verbose "Converting JSON..." $redditInfo = $rawReddit | ConvertFrom-Json Write-Verbose "Generating output..." for ($i = 0; $i -lt $Threads; $i++) { $childObject = $null #reset $childObject = $redditInfo.data.children.data[$i] $obj = [PSCustomObject]@{ Title = $childObject.title URL = $childObject.url # PermaLink = $childObject.permalink Score = $childObject.score # Ups = $childObject.ups # Downs = $childObject.downs Author = $childObject.author Comments = $childObject.num_comments } $results.Add($obj) | Out-Null if ($obj.URL -like "*i.redd.it*" -or $obj.URL -like "*imgur*" -or $obj.URL -like "*v.redd.it*" -and $ShowPics) { Show-Pics -url $obj.URL } } }#if_rawReddit else { Write-Warning -Message 'No information was returned from reddit.' }#else_rawReddit return $results }#Get-Reddit ================================================ FILE: LearnPowerShell/EP12 - Manage Cloud with PowerShell.ps1 ================================================ #____________________________________________________________ # https://www.techthoughts.info/manage-cloud-with-powershell/ #____________________________________________________________ #region AWS # ---------------------------------------------- # AWS # ---------------------------------------------- # Install AWS.Tools - A Modularized Version of AWS Tools for PowerShell Install-Module -Name AWS.Tools.Installer # Get a list of AWS services supported by the Tools for PowerShell Import-Module AWS.Tools.Common Get-AWSService | Select-Object Service, ServiceName, ModuleName | Format-Table -AutoSize # Discover available AWS regions Get-AWSRegion # Keep AWS.Tools versions in sync Update-AWSToolsModule #___________________________________ # Set AWS authentication and region # Import the AWS Tools Common module Import-Module AWS.Tools.Common # set the credential for the session Set-AWSCredential -AccessKey $aKey -SecretKey $sKey # set the default region for the session Set-DefaultAWSRegion -Region us-west-2 #___________________________________ # AWS FINAL EXAMPLE # 1 - Create an S3 bucket # 2 - Make the S3 bucket secure - NO PUBLIC ACCESS # 3 - Upload a file to the new S3 bucket # 4 - Create a pre-signed URL to enable people to securely download the file worldwide # Install the AWS.Tools S3 module to work with Amazon Simple Storage Service (S3) Install-Module AWS.Tools.S3 Import-Module AWS.Tools.S3 # 1 - This command creates a new private bucket named "techthoughts". # https://docs.aws.amazon.com/powershell/latest/reference/items/New-S3Bucket.html New-S3Bucket -BucketName 'techthoughts' Get-S3PublicAccessBlock -BucketName 'techthoughts' # by default the bucket will not have public access blocked # 2 - Adjust public access to the bucket to BLOCKED # https://docs.aws.amazon.com/powershell/latest/reference/items/Add-S3PublicAccessBlock.html $publicAccessBlockSplat = @{ PublicAccessBlockConfiguration_BlockPublicAcl = $true PublicAccessBlockConfiguration_IgnorePublicAcl = $true PublicAccessBlockConfiguration_BlockPublicPolicy = $true PublicAccessBlockConfiguration_RestrictPublicBucket = $true BucketName = 'techthoughts' } Add-S3PublicAccessBlock @publicAccessBlockSplat Get-S3PublicAccessBlock -BucketName 'techthoughts' # verify the new BLOCKED policy is in place # 3 - Upload a local file on your drive to the new S3 bucket $filePath = 'C:\rs-pkgs\techthoughts_text_file.txt' $key = 'techthoughts_text_file.txt' $bucketName = 'techthoughts' # https://docs.aws.amazon.com/powershell/latest/reference/index.html?page=Write-S3Object.html&tocid=Write-S3Object # http://iwantmyreal.name/s3-download-only-presigned-upload $writeS3Splat = @{ BucketName = $bucketName File = $filePath Key = $key HeaderCollection = @{ 'Content-Disposition' = "attachment; filename=""$key""" } } Write-S3Object @writeS3Splat # 4 - Create a pre-signed URL to securely allow others to download the file for a set period of time # https://docs.aws.amazon.com/powershell/latest/reference/items/Get-S3PreSignedURL.html # This URL will be good for 1 day - 24 hours! $url = Get-S3PreSignedURL -BucketName $bucketName -Key $key -Expire (Get-Date).AddDays(1) #endregion #region Azure # ---------------------------------------------- # Azure # ---------------------------------------------- # Install the Az module Install-Module -Name Az # Get a list of Azure services supported by the Az modules Get-Command -Noun Az* | Sort-Object Source # List all (read only) Get cmdlets that contain VM in the Az.Compute module Get-Command -Verb Get -Noun AzVM* -Module Az.Compute # Get a list of available Azure locations to deploy resources to Get-AzLocation | Select-Object DisplayName, Location Import-Module Az.Accounts # Connect to Azure with a browser sign in token Connect-AzAccount # If you have more than one subscription associated with your mail account, you can choose the default subscription. Get-AzSubscription Select-AzSubscription -Subscription "My Subscription" Get-AzResourceGroup | Select-Object ResourceGroupName, Location Set-AzDefault -ResourceGroupName myResourceGroup # AZURE FINAL EXAMPLE # 1 - Create a resource group to hold storage account # 2 - Create a storage account # 3 - Create a storage container # 4 - Upload a file to the new storage container # 5 - Create a pre-signed URL to enable people to securely download the file worldwide #Resource Group $resourceGroupName = "techthoughts" $location = "westus" # 1 - Create a resource group to hold storage account # https://docs.microsoft.com/powershell/module/az.resources/new-azresourcegroup?view=azps-4.4.0 $newResourceGroupSplat = @{ Name = $resourceGroupName Location = $location } New-AzResourceGroup @newResourceGroupSplat # 2 - Create a storage account # https://docs.microsoft.com/powershell/module/az.storage/new-azstorageaccount?view=azps-4.4.0 $storageAccountName = 'techthoughtsstorage' $newStorageAccountSplat = @{ ResourceGroupName = $resourceGroupName AccountName = $storageAccountName Location = $location SkuName = 'Standard_LRS' Kind = 'StorageV2' } New-AzStorageAccount @newStorageAccountSplat # 3 - Create a storage container # https://docs.microsoft.com/powershell/module/az.storage/get-azstorageaccount?view=azps-4.4.0 $getStorageAccountSplat = @{ ResourceGroupName = $resourceGroupName Name = $storageAccountName } $storageContext = Get-AzStorageAccount @getStorageAccountSplat # https://docs.microsoft.com/powershell/module/az.storage/new-azstoragecontainer?view=azps-4.4.0 $containerName = 'techthoughtscontainer' $newStorageContainerSplat = @{ Context = $storageContext.Context Name = $containerName Permission = 'Off' } New-AzStorageContainer @newStorageContainerSplat # 4 - Upload a file to the new storage container # https://docs.microsoft.com/powershell/module/az.storage/set-azstorageblobcontent?view=azps-4.4.0 $setAzStorageBlobSplat = @{ Context = $storageContext.Context Container = $containerName File = 'C:\rs-pkgs\techthoughts_text_file.txt' Blob = 'techthoughts_text_file.txt' } Set-AzStorageBlobContent @setAzStorageBlobSplat # 5 - Create a pre-signed URL to enable people to securely download the file worldwide # https://docs.microsoft.com/powershell/module/az.storage/new-azstorageblobsastoken?view=azps-4.4.0 $newStorageSASSplat = @{ Context = $storageContext.Context Container = $containerName Blob = 'techthoughts_text_file.txt' ExpiryTime = (Get-Date).AddDays(1) Permission = 'r' FullUri = $true } $url = New-AzStorageBlobSASToken @newStorageSASSplat #endregion ================================================ FILE: LearnPowerShell/EP13 - PowerShell Modules/EP13 - PowerShell Modules.ps1 ================================================ #____________________________________________________________ # https://www.techthoughts.info/powershell-modules/ #____________________________________________________________ # importing a psm1 # a psm1 module can now be imported Import-Module .\learnpowershell.psm1 # we can confirm that the module is loaded Get-Module learnpowershell # now that the module is imported we can see what commands are available Get-Command -Module learnpowershell #____________________________________________________________ # importing a psd1 # create a basic module manifest New-ModuleManifest -Path C:\learnpowershell\learnpowershell.psd1 # test a module manifest Test-ModuleManifest .\learnpowershell.psd1 # import a module by specifying the manifest Import-Module .\learnpowershell.psd1 # we can confirm that the module is loaded Get-Module learnpowershell #____________________________________________________________ # using a repository to find and install modules # the PowerShell Gallery is registered by default Get-PSRepository # search for modules that are tagged with the Telegram key word Find-Module -Tag Telegram | Format-List # install a module from the PowerShell Gallery Install-Module -Name PoshGram -Scope CurrentUser # determine where a module was installed on the system Get-Module -Name PoshGram -ListAvailable | Select-Object Path # update installed module Update-Module -Name PoshGram # list all modules available on the system Get-Module -ListAvailable #____________________________________________________________ # manually installing a module # PowerShell sources modules from paths specified in the PSModulePath environment variable $env:PSModulePath # change dir to the modules install folder Set-Location $env:USERPROFILE\Documents\PowerShell\Modules # create a new folder that is the same name as your module New-Item -Name learnpowershell -ItemType Directory # copy the psd1 and psm1 files to this new directory # verify that PowerShell can now source that module Get-Module learnpowershell -ListAvailable #____________________________________________________________ # saving a module for testing / evaluation # save a module to a directory of your choice Save-Module PoshGram -Path C:\eval -Repository PSGallery # change directory to the downloaded module Set-Location 'C:\eval\PoshGram\2.2.2' # import the module directly for testing and evaluation Import-Module .\PoshGram.psd1 #____________________________________________________________ # publish your module to the PowerShell Gallery Publish-Module -Name "learnpowershell" -NuGetApiKey "your-api-key-goes-here" -Repository PSGallery ================================================ FILE: LearnPowerShell/EP13 - PowerShell Modules/LearnPowerShell/LearnPowerShell.psd1 ================================================ # # Module manifest for module 'LearnPowerShell' # # Generated by: Jake Morrison # # Generated on: 06/13/22 # @{ # Script module or binary module file associated with this manifest. RootModule = 'LearnPowerShell.psm1' # Version number of this module. ModuleVersion = '0.7.0' # Supported PSEditions # CompatiblePSEditions = @() # ID used to uniquely identify this module GUID = '1240e1b2-fa3a-4617-98cc-25adec29389a' # Author of this module Author = 'Jake Morrison' # Company or vendor of this module CompanyName = 'TechThoughts' # Copyright statement for this module Copyright = '(c) Jake Morrison. All rights reserved.' # Description of the functionality provided by this module Description = 'Returns episode information from the Learn PowerShell series. Learn PowerShell in an operationally focused blog and video series. This module contains information about each episode.' # Minimum version of the PowerShell engine required by this module # PowerShellVersion = '' # Name of the PowerShell host required by this module # PowerShellHostName = '' # Minimum version of the PowerShell host required by this module # PowerShellHostVersion = '' # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. # DotNetFrameworkVersion = '' # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. # ClrVersion = '' # Processor architecture (None, X86, Amd64) required by this module # ProcessorArchitecture = '' # Modules that must be imported into the global environment prior to importing this module # RequiredModules = @() # Assemblies that must be loaded prior to importing this module # RequiredAssemblies = @() # Script files (.ps1) that are run in the caller's environment prior to importing this module. # ScriptsToProcess = @() # Type files (.ps1xml) to be loaded when importing this module # TypesToProcess = @() # Format files (.ps1xml) to be loaded when importing this module # FormatsToProcess = @() # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess # NestedModules = @() # 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. FunctionsToExport = @( 'Get-LearnPowerShellInfo' ) # 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. # CmdletsToExport = @() # Variables to export from this module # VariablesToExport = '*' # 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. # AliasesToExport = @() # DSC resources to export from this module # DscResourcesToExport = @() # List of all modules packaged with this module # ModuleList = @() # List of all files packaged with this module # FileList = @() # 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. PrivateData = @{ PSData = @{ # Tags applied to this module. These help with module discovery in online galleries. Tags = @( 'examples', 'howto', 'learn', 'learn-powershell', 'learn-powershell-series', 'learning-powershell', 'learningpowershell', 'learnpowershell', 'powershell', 'powershellcourse', 'powershell-course', 'powershellexamples' 'powershell-examples' 'powershell-training', 'powershelltraining', 'training', 'training-course' ) # A URL to the license for this module. # LicenseUri = '' # A URL to the main website for this project. ProjectUri = 'https://github.com/techthoughts2/Learn-PowerShell-Code-Examples' # A URL to an icon representing this module. # IconUri = '' # ReleaseNotes of this module # ReleaseNotes = '' # Prerelease string of this module # Prerelease = '' # Flag to indicate whether the module requires explicit user acceptance for install/update/save # RequireLicenseAcceptance = $false # External dependent modules of this module # ExternalModuleDependencies = @() } # End of PSData hashtable } # End of PrivateData hashtable # HelpInfo URI of this module # HelpInfoURI = '' # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. # DefaultCommandPrefix = '' } ================================================ FILE: LearnPowerShell/EP13 - PowerShell Modules/LearnPowerShell/LearnPowerShell.psm1 ================================================ #region Learn PowerShell Information [System.Collections.ArrayList]$script:learnPowerShellInfo = @() $script:learnPowerShellInfo.Add([PSCustomObject]@{ Episode = '0' Title = 'Should you learn PowerShell?' Blog = 'https://www.techthoughts.info/ps1-should-you-learn-powershell/' YouTube = 'https://youtu.be/csuz7qSJv_Q' GitHub = '' Tags = @( 'PowerShell' 'Learn' 'Time' ) }) | Out-Null $script:learnPowerShellInfo.Add([PSCustomObject]@{ Episode = 1 Title = 'PowerShell Basics' Blog = 'https://www.techthoughts.info/learn-and-use-powershell-with-just-three-commands/' YouTube = 'https://youtu.be/cDcS6iL1G4I' GitHub = 'https://github.com/techthoughts2/Learn-PowerShell-Code-Examples/blob/master/LearnPowerShell/EP1%20-%20PowerShell%20Basics.ps1' Tags = @( 'PowerShell' 'Learn' 'Cmdlets' 'Verb' 'Noun', 'Command' 'Help' 'Get-Help' 'Get-Command' 'Get-Member' ) }) | Out-Null $script:learnPowerShellInfo.Add([PSCustomObject]@{ Episode = 2 Title = 'PowerShell Pipeline' Blog = 'https://www.techthoughts.info/working-with-the-powershell-pipeline/' YouTube = 'https://youtu.be/QKmyf6c83Rs' GitHub = 'https://github.com/techthoughts2/Learn-PowerShell-Code-Examples/blob/master/LearnPowerShell/EP2%20-%20PowerShell%20Pipeline.ps1' Tags = @( 'PowerShell' 'Learn' 'Pipeline' 'PSItem' 'Format' 'Select' 'Object' 'Sort' 'Parameters' ) }) | Out-Null $script:learnPowerShellInfo.Add([PSCustomObject]@{ Episode = 3 Title = 'State of the Shell' Blog = 'https://www.techthoughts.info/powershell-history-and-current-state/' YouTube = 'https://youtu.be/nQTZRJjcuE4' GitHub = 'https://github.com/techthoughts2/Learn-PowerShell-Code-Examples/blob/master/LearnPowerShell/EP3%20-%20State%20of%20the%20Shell.ps1' Tags = @( 'PowerShell' 'Learn' 'History' 'pwsh' ) }) | Out-Null $script:learnPowerShellInfo.Add([PSCustomObject]@{ Episode = 4 Title = 'PowerShell Development Setup' Blog = 'https://www.techthoughts.info/getting-setup-powershell-development/' YouTube = 'https://youtu.be/J6mQIISjXFA' GitHub = 'https://github.com/techthoughts2/Learn-PowerShell-Code-Examples/blob/master/LearnPowerShell/EP4%20-%20PowerhShell%20Development.ps1' Tags = @( 'PowerShell' 'Learn' 'Development' 'VSCode' 'Terminal' 'PSScriptAnalyzer' ) }) | Out-Null $script:learnPowerShellInfo.Add([PSCustomObject]@{ Episode = 5 Title = 'Working With PowerShell Variables' Blog = 'https://www.techthoughts.info/working-with-powershell-variables/' YouTube = 'https://youtu.be/4Rc0aEMXiWw' GitHub = 'https://github.com/techthoughts2/Learn-PowerShell-Code-Examples/blob/master/LearnPowerShell/EP5%20-%20PowerShell%20Variables.ps1' Tags = @( 'PowerShell' 'Learn' 'Variables' 'Variable' ) }) | Out-Null $script:learnPowerShellInfo.Add([PSCustomObject]@{ Episode = 6 Title = 'Taking Control with PowerShell Logic' Blog = 'https://www.techthoughts.info/taking-control-with-powershell-logic/' YouTube = 'https://youtu.be/nesN4Iznbco' GitHub = 'https://github.com/techthoughts2/Learn-PowerShell-Code-Examples/blob/master/LearnPowerShell/EP6%20-%20PowerShell%20Logic.ps1' Tags = @( 'PowerShell' 'Learn' 'Conditional' 'Switch' 'Loops' 'For' 'Foreach' 'While' ) }) | Out-Null $script:learnPowerShellInfo.Add([PSCustomObject]@{ Episode = 7 Title = 'PowerShell Input & Output' Blog = 'https://www.techthoughts.info/powershell-input-output/' YouTube = 'https://youtu.be/nnTlsNA3hPk' GitHub = 'https://github.com/techthoughts2/Learn-PowerShell-Code-Examples/blob/master/LearnPowerShell/EP7%20-%20PowerShell%20Input%20Output.ps1' Tags = @( 'PowerShell' 'Learn' 'Input' 'Output' ) }) | Out-Null $script:learnPowerShellInfo.Add([PSCustomObject]@{ Episode = 8 Title = 'PowerShell Errors and Exceptions Handling' Blog = 'https://www.techthoughts.info/powershell-errors-and-exceptions-handling/' YouTube = 'https://youtu.be/A6afjA5Q9eM' GitHub = 'https://github.com/techthoughts2/Learn-PowerShell-Code-Examples/blob/master/LearnPowerShell/EP8%20-%20PowerShell%20Error%20Handling.ps1' Tags = @( 'PowerShell' 'Learn' 'Errors' 'Exceptions' 'Terminating' 'ErrorAction' 'Try' 'Catch' ) }) | Out-Null $script:learnPowerShellInfo.Add([PSCustomObject]@{ Episode = 9 Title = 'PowerShell Remoting' Blog = 'https://www.techthoughts.info/powershell-remoting/' YouTube = 'https://youtu.be/qvJRaYlxI1w' GitHub = 'https://github.com/techthoughts2/Learn-PowerShell-Code-Examples/blob/master/LearnPowerShell/EP9%20-%20PowerShell%20Remoting.ps1' Tags = @( 'PowerShell' 'Learn' 'Remoting' 'WinRm' 'SSH' ) }) | Out-Null $script:learnPowerShellInfo.Add([PSCustomObject]@{ Episode = 10 Title = 'PowerShell Scripts' Blog = 'https://www.techthoughts.info/powershell-scripts/' YouTube = 'https://youtu.be/IABNJEl2ZWk' GitHub = 'https://github.com/techthoughts2/Learn-PowerShell-Code-Examples/blob/master/LearnPowerShell/EP10%20-%20PowerShell%20Script.ps1' Tags = @( 'PowerShell' 'Learn' 'Scripts' 'Script' ) }) | Out-Null $script:learnPowerShellInfo.Add([PSCustomObject]@{ Episode = 11 Title = 'PowerShell Functions' Blog = 'https://www.techthoughts.info/powershell-functions/' YouTube = 'https://youtu.be/qrwPvbCWRtI' GitHub = 'https://github.com/techthoughts2/Learn-PowerShell-Code-Examples/blob/master/LearnPowerShell/EP11%20-%20PowerShell%20Functions.ps1' Tags = @( 'PowerShell' 'Learn' 'Functions' 'Function' ) }) | Out-Null $script:learnPowerShellInfo.Add([PSCustomObject]@{ Episode = 12 Title = 'Manage Cloud with PowerShell' Blog = 'https://www.techthoughts.info/manage-cloud-with-powershell/' YouTube = 'https://youtu.be/x-bAD3RX_P0' GitHub = 'https://github.com/techthoughts2/Learn-PowerShell-Code-Examples/blob/master/LearnPowerShell/EP12%20-%20Manage%20Cloud%20with%20PowerShell.ps1' Tags = @( 'PowerShell' 'Learn' 'Cloud' 'Azure' 'AWS' ) }) | Out-Null $script:learnPowerShellInfo.Add([PSCustomObject]@{ Episode = 13 Title = 'PowerShell Modules' Blog = '' YouTube = '' GitHub = '' Tags = @( 'PowerShell' 'Learn' 'Module' 'Modules' 'psm1' 'psd1' ) }) | Out-Null # $script:learnPowerShellInfo.Add([PSCustomObject]@{ # Episode = 14 # Title = '' # Blog = '' # YouTube = '' # GitHub = '' # Tags = @( # 'PowerShell' # 'Learn' # ) # }) | Out-Null # $script:learnPowerShellInfo.Add([PSCustomObject]@{ # Episode = 15 # Title = '' # Blog = '' # YouTube = '' # GitHub = '' # Tags = @( # 'PowerShell' # 'Learn' # ) # }) | Out-Null # $script:learnPowerShellInfo.Add([PSCustomObject]@{ # Episode = 16 # Title = '' # Blog = '' # YouTube = '' # GitHub = '' # Tags = @( # 'PowerShell' # 'Learn' # ) # }) | Out-Null # $script:learnPowerShellInfo.Add([PSCustomObject]@{ # Episode = 17 # Title = '' # Blog = '' # YouTube = '' # GitHub = '' # Tags = @( # 'PowerShell' # 'Learn' # ) # }) | Out-Null # $script:learnPowerShellInfo.Add([PSCustomObject]@{ # Episode = 18 # Title = '' # Blog = '' # YouTube = '' # GitHub = '' # Tags = @( # 'PowerShell' # 'Learn' # ) # }) | Out-Null #endregion #region main <# .SYNOPSIS Returns episode information about the Learn PowerShell series .DESCRIPTION Returns episode information about the Learn PowerShell series .EXAMPLE Get-LearnPowerShellInfo Returns all episode information from the Learn PowerShell series .EXAMPLE Get-LearnPowerShellInfo -Tag 'vscode' Returns all episode(s) information that are tagged with vscode in the Learn PowerShell series .EXAMPLE Get-LearnPowerShellInfo -EpisodeNumber 5 Returns information for Episode 5 from the Learn PowerShell series .PARAMETER Tag Topic Tag .PARAMETER EpisodeNumber Episode Number .OUTPUTS System.Management.Automation.PSCustomObject .NOTES Have fun learning PowerShell! .COMPONENT LearnPowerShell .LINK https://www.techthoughts.info/learn-powershell-series/ .LINK https://github.com/techthoughts2/Learn-PowerShell-Code-Examples #> function Get-LearnPowerShellInfo { [CmdletBinding( DefaultParameterSetName = 'x' )] param ( [Parameter(ParameterSetName = 'Tag', Mandatory = $true, HelpMessage = 'Topic tag')] [string] $Tag, [Parameter(ParameterSetName = 'Episode', Mandatory = $true, HelpMessage = 'Episode Number')] [ValidateRange(1, 15)] [int] $EpisodeNumber ) Write-Verbose -Message ('ParameterSetName: {0}' -f $($PSCmdlet.ParameterSetName)) if ($Tag) { Write-Verbose -Message 'Finding episode(s) by tag' $result = $script:learnPowerShellInfo | Where-Object { $_.Tags -like "*$Tag*" } } elseif ($EpisodeNumber) { Write-Verbose -Message 'Finding episode by episode number' $result = $script:learnPowerShellInfo | Where-Object { $_.Episode -eq $EpisodeNumber } } else { Write-Verbose -Message 'Returning all episode information' $result = $script:learnPowerShellInfo } return $result } #endregion ================================================ FILE: LearnPowerShell/EP2 - PowerShell Pipeline.ps1 ================================================ #____________________________________________________________ # https://www.techthoughts.info/working-with-the-powershell-pipeline/ #____________________________________________________________ # the pipeline operator Get-Process | Sort-Object Id #____________________________________________________________ # In this example, every command found will be "piped" to Get-Help # This will run Get-Help against EVERY command found Get-Command | Get-Help #____________________________________________________________ # This example would restart the BITS service! Get-Service -Name BITS | Restart-Service #____________________________________________________________ # try running this command on your machine to see the results. # the WhatIf parameter will make Stop-Process take no actual action Get-Process | Stop-Process -WhatIf #____________________________________________________________ # PSItem # Get all processes. For each process (object) found, # display that object Get-Process | ForEach-Object {$PSItem} # In this simple example, we will display the current object # to the console 1,2,3 | ForEach-Object {$PSItem} # Spelling out $PSItem (not common) 1,2,3 | ForEach-Object {$PSItem} # using $PSItem shorthand (common) 1,2,3 | ForEach-Object {$_} #____________________________________________________________ # Format-List & Format-Table # Note the way things look using Format-Table Get-Process | Format-Table # Now see how that differs if you pipe instead to Format-List Get-Process | Format-List # Note the return from just Get-Date Get-Date # Now see how the whole object is returned if you pipe to Format-List Get-Date | Format-List # basic information about the notepad process Get-Process notepad # more information about the notepad process Get-Process notepad | Format-List # all available information about the notepad process Get-Process notepad | Format-List #____________________________________________________________ # Select-Object # Using Select-Object you can retrieve only the properties you are after Get-Process | Select-Object Name,Id,CPU,Responding #____________________________________________________________ # Sort-Object # This example pipes all processes to Sort-Object which sorts by CPU use # Use to quickly identify your busiest processes. Very handy! Get-Process | Sort-Object CPU # You can combine multiple pipelines together as well Get-Process | Select-Object Name,Id,CPU,Responding | Sort-Object CPU #____________________________________________________________ # Where-Object # Get Processes, return only those where current object $_ is greater than 15 Get-Process | Where-Object {$_.CPU -gt 15} # Get file information for all files found in the $HOME directory # Return information for only files that are greater than 5MB in size Get-ChildItem $HOME -Recurse | Where-Object {$_.Length -gt 5MB} # Count the number of large file in your $HOME directory Get-ChildItem $HOME -Recurse | Where-Object {$_.Length -gt 50MB} | Measure-Object #____________________________________________________________ ================================================ FILE: LearnPowerShell/EP3 - State of the Shell.ps1 ================================================ #____________________________________________________________ # https://www.techthoughts.info/powershell-history-and-current-state/ #____________________________________________________________ # determine what version of PowerShell you are running with the following: $PSVersionTable # The PSVersion number is the version. you can get it specifically like this: $PSVersionTable.PSVersion #____________________________________________________________ # in a 5.1 window count the number of cmdlets: Get-Command | Measure-Object # now try the same thing in a 6+ console window Get-Command | Measure-Object #____________________________________________________________ # in a 6+ console window run the following: Install-Module WindowsCompatibility -Scope CurrentUser #____________________________________________________________ ================================================ FILE: LearnPowerShell/EP4 - PowerhShell Development.ps1 ================================================ #____________________________________________________________ # https://www.techthoughts.info/getting-setup-powershell-development/ #____________________________________________________________ code --list-extensions code --install-extension ms-vscode.PowerShell # PowerShell base VSCode settings: <# { // editor "editor.quickSuggestionsDelay": 1, "editor.tabCompletion": "on", "files.defaultLanguage": "powershell", // powershell settings changes // you can specify a custom location for the powershell.exe/pwsh.exe file // not required if you just want to use the default locations "powershell.powerShellAdditionalExePaths": { "PS7": "C:\\Program Files\\PowerShell\\7\\pwsh.exe", "PS5.1": "C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\powershell.exe" }, "powershell.powerShellDefaultVersion": "PS7", "powershell.codeFormatting.preset":"Stroustrup", "powershell.startAutomatically": true, "powershell.scriptAnalysis.enable": true, "powershell.integratedConsole.showOnStartup": false, "powershell.integratedConsole.focusConsoleOnExecute": true } #> ================================================ FILE: LearnPowerShell/EP5 - PowerShell Variables.ps1 ================================================ #____________________________________________________________ # https://www.techthoughts.info/working-with-powershell-variables/ #____________________________________________________________ #https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_variables?view=powershell-6 #https://docs.microsoft.com/en-us/powershell/scripting/learn/using-variables-to-store-objects?view=powershell-6 #____________________________________________________________ Get-Process $processes = Get-Process $processes #---------------------------------------- # not using variable Get-Process | Where-Object { $_.CPU -gt 5000 } #find processes keeping the CPU busy Get-Process | Sort-Object WorkingSet64 -Descending #sort processes by memory usage #---------------------------------------- # using variable $processes = Get-Process $processes | Where-Object { $_.CPU -gt 5000 } #find processes keeping the CPU busy $processes | Sort-Object WorkingSet64 -Descending #sort processes by memory usage #---------------------------------------- # not strong typed $myNewVariable # data types #---------------------------------------- $total = 2 + 2 $total $total | Get-Member #---------------------------------------- $total = '2 + 2' $total $total | Get-Member #____________________________________________________________ # understanding data types $num1 = 2 $num2 = 2 $total = $num1 + $num2 $total #---------------------------------------- $num1 = '2' $num2 = '2' $total = $num1 + $num2 $total #---------------------------------------- #strong type #---------------------------------------- [int]$num1 = '2' [int]$num2 = '2' $total = $num1 + $num2 #---------------------------------------- #convert #---------------------------------------- $stringReturn = $total.ToString() $total | Get-Member #---------------------------------------- #quotes $literal = 'Two plus one equals: $(1 + 2)' $literal $escaped = "Two plus one equals: $(1 + 2)" $escaped Write-Host '$escaped' Write-Host "$escaped" #constant variables are reserved Get-Variable # you can't use these $HOME = 'c:\test' #environment variables Get-ChildItem env: $env:COMPUTERNAME $env:USERNAME #putting it all together with an example $path = Read-Host -Prompt 'Please enter the file path you wish to scan for large files...' $rawFileData = Get-ChildItem -Path $path -Recurse $largeFiles = $rawFileData | Where-Object { $_.Length -gt 100MB } $largeFilesCount = $largeFiles | Measure-Object | Select-Object -ExpandProperty Count Write-Host "You have $largeFilesCount large file(s) in $path" #____________________________________________________________ ================================================ FILE: LearnPowerShell/EP6 - PowerShell Logic.ps1 ================================================ #____________________________________________________________ # https://www.techthoughts.info/taking-control-with-powershell-logic/ #____________________________________________________________ ################################################## #CONDITIONAL # do something based on a condition if ('a condition is met') { # do something / take an action } elseif ('a different condition is met') { # do something different } else { # do something else } #------------------------------------------------- $path = 'C:\Test' #windows # $path = /home #linux $evalPath = Test-Path $path if ($evalPath -eq $true) { Write-Host "$path VERIFIED" } elseif ($evalPath -eq $false) { Write-Host "$path NOT VERIFIED" } #COMPARISON OPERATORS ################################################## #SWITCH [int]$aValue = Read-Host 'Enter a number' switch ($aValue) { 1 { Write-Host 'You entered the number ONE' } 2 { Write-Host 'You entered the number TWO' } 3 { Write-Host 'You entered the number THREE' } 4 { Write-Host 'You entered the number FOUR' } 5 { Write-Host 'You entered the number FIVE' } Default { Write-Host "Sorry, I don't know what to do with $aValue" } } ################################################## # LOOPS for ($i = 0; $i -le 15; $i++) { Write-Host $i -ForegroundColor $i } #------------------------------------------------- $aString = 'Jean-Luc Picard' $reverseString = '' for ($i = $aString.Length; $i -ge 0; $i--) { $reverseString += $aString[$i] } $reverseString ################################################## $path = 'C:\Test' [int]$totalSize = 0 $fileInfo = Get-ChildItem $path -Recurse foreach ($file in $fileInfo) { $totalSize += $file.Length } Write-Host "The total size of file in $path is $($totalSize /1MB) MB." ################################################## #------------------------------------------------- # do while loop $pathVerified = $false do { # in a do while, the user will always be prompted at least once $path = Read-Host 'Please enter a file path to evaluate' if (Test-Path $path) { $pathVerified = $true } } while ($pathVerified -eq $false) #------------------------------------------------- # while loop $pathVerified = $true while ($pathVerified -eq $false) { # in a while loop, you might never enter the loop $path = Read-Host 'Please enter a file path to evaluate' if (Test-Path $path) { $pathVerified = $true } } #------------------------------------------------- $largeProcesses = Get-Process | Where-Object { $_.WorkingSet64 -gt 50MB } $largeProcesses = @() $processes = Get-Process foreach ($process in $processes) { if ($process.WorkingSet64 -gt 50MB) { $largeProcesses += $process } } #------------------------------------------------- $path = 'C:\Test' $folderCount = 0 Get-ChildItem $path | ForEach-Object -Process { if ($_.PSIsContainer) { $folderCount++ } } $folderCount #------------------------------------------------- # declare a few variables for counting [int]$fileCount = 0 [int]$folderCount = 0 [int]$totalSize = 0 # declare our path we want to evaluate $path = 'C:\Test' # get the file information $rawFileInfo = Get-ChildItem $path -Recurse # loop through that file information foreach ($item in $rawFileInfo) { if ($item.PSIsContainer) { # this is a folder/directory $folderCount++ } else { # this is a file, because it is not a PSIsContainer $fileCount++ $totalSize += $item.Length } } # generate output Write-Host "Breakdown of $path" Write-Host "Total Directories: $folderCount" Write-Host "Total Files: $fileCount" Write-Host "Total Size of files: $($totalSize / 1MB) MB" #------------------------------------------------- ================================================ FILE: LearnPowerShell/EP7 - PowerShell Input Output.ps1 ================================================ #____________________________________________________________ # https://www.techthoughts.info/powershell-input-output/ #____________________________________________________________ #INPUT #------------------------------------------------- #cmdlets - obviously #retrieve dynamic content from a website $webResults = Invoke-WebRequest -Uri 'https://reddit.com/r/powershell.json' $rawJSON = $webResults.Content $objData = $rawJSON | ConvertFrom-Json $posts = $objData.data.children.data $posts | Select-Object Title,Score | Sort-Object Score -Descending #------------------------------------------------- #Read Host #https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/read-host?view=powershell-6 [int]$numPosts = Read-Host -Prompt "Enter the number of posts to read" $posts | Select-Object Title,url | Sort-Object Score -Descending | Select-Object -First $numPosts [int]$numFacts = Read-Host -Prompt "Enter the number of cat facts you would like" $webResults = Invoke-RestMethod -Uri "https://catfact.ninja/facts?limit=$numFacts&max_length=140" $webResults.data #------------------------------------------------- #Get Content #https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-content?view=powershell-6 $logContent = Get-Content C:\Test\SampleLog.log $logContent = Get-Content C:\Test\SampleLog.log -Tail 5 $b = Get-Content C:\Test\SampleLog.log -Raw $logContent | Select-String -Pattern "INFO" $regex = "\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b" $logContent | Select-String -Pattern $regex -AllMatches $logContent | Where-Object {$_ -like "*.*.*.*"} $b | Select-String -Pattern $regex $b | Where-Object {$_ -like "*.*.*.*"} #__________________ $rawCSVInput = Get-Content C:\Test\tt.csv $objData = $rawCSVInput | ConvertFrom-Csv ############################################################################### ############################################################################### #OUTPUT #https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/write-host?view=powershell-6 #https://www.jsnover.com/blog/2013/12/07/write-host-considered-harmful/ Write-Host 'Text output to console' $hostInfo = Get-Host Write-Host $hostInfo Write-Host $hostInfo.Version Write-Host "Warning" -ForegroundColor Yellow Write-Host "ERROR" -ForegroundColor Red Write-Host "Works Great" -ForegroundColor Green Write-Host "CRITICAL ERROR" -BackgroundColor Red -ForegroundColor White Write-Host "The display name is: $($bits.DisplayName)" #------------------------------------------------- Write-Output #https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/write-output?view=powershell-6 <# The Write-Output cmdlet sends the specified object down the pipeline to the next command. If the command is the last command in the pipeline, the object is displayed in the console. Write-Output sends objects down the primary pipeline, also known as the "output stream" or the "success pipeline." To send error objects down the error pipeline, use Write-Error. This cmdlet is typically used in scripts to display strings and other objects on the console. However, because the default behavior is to display the objects at the end of a pipeline, it is generally not necessary to use the cmdlet. For instance, Get-Process | Write-Output is equivalent to Get-Process. #> $processes = Get-Process Write-Output $processes $P #------------------------------------------------- #Out-File #https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/out-file?view=powershell-6 $processes = Get-Process $processes | Out-File C:\Test\processInfo.txt $processes | ConvertTo-Csv -NoTypeInformation | Out-File c:\test\processes.csv $processes | Export-Csv -Path c:\test\processes2.csv $processes = Get-Process $xml = ConvertTo-Xml -As "Document" -Depth 3 -InputObject $processes #------------------------------------------------- ================================================ FILE: LearnPowerShell/EP8 - PowerShell Error Handling.ps1 ================================================ #____________________________________________________________ # https://www.techthoughts.info/powershell-errors-and-exceptions-handling/ #____________________________________________________________ #Github PowerShell error documentation: #https://github.com/MicrosoftDocs/PowerShell-Docs/issues/1583 # Primary Pipeline aka output stream aka success pipeline # error pipeline #------------------------------------------------- #non-terminating error 1 / 0; Write-Host 'Hello, will I run after an error?' #non-terminating errors don't stop loops $collection = @( 'C:\Test\newcsv.csv', 'c:\nope\nope.txt' 'C:\Test\newcsv2.csv' ) foreach ($item in $collection) { Get-Item $item } #------------------------------------------------- #terminating errors # Without ErrorAction Get-Item -Path c:\nope\nope.txt; Write-Host 'Hello, will I run after an error?' # With ErrorAction Get-Item -Path c:\nope\nope.txt -ErrorAction Stop; Write-Host 'Hello, will I run after an error?' #try/catch/finally #https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_try_catch_finally?view=powershell-6 # throw causes PowerShell to terminate try { 1 / 0; Write-Host 'Hello, will I run after an error?' } catch { throw } # this example will not go the catch and will run the Write-Host try { Get-Item -Path c:\nope\nope.txt; Write-Host 'Hello, will I run after an error?' } catch { Write-Host 'You are now in the catch' } # this example will error and go directly to the catch try { Get-Item -Path c:\nope\nope.txt -ErrorAction Stop; Write-Host 'Hello, will I run after an error?' } catch { Write-Host 'You are now in the catch' } $processNames = @( 'NotAProcess', 'Notepad' ) foreach ($item in $processNames) { try { Get-Process -Nam $item } catch { Write-Host $item throw } } #Write-Error simply prints the error for the user try { 1 / 0; Write-Host 'Hello, will I run after an error?' } catch { # Maybe Log Something Right here Write-Error $_ } # Finally will log results regardless of what happens try { Get-Content -Path c:\nope\nope.txt -ErrorAction Stop } catch { Write-Error $_ } finally { # log results to a logging file } #------------------------------------------------- #The website exists, but the page does not try { $webResults = Invoke-WebRequest -Uri 'https://www.techthoughts.info/nope.htm' } catch { Write-Error $_ } #The website exists, but the page does not try { $webResults = Invoke-WebRequest -Uri 'https://www.techthoughts.info/nope.htm' } catch { $theError = $_ if ($theError.Exception -like "*404*") { Write-Warning 'Web page not found. Check the address and try again.' #Retry code } else { throw } } #The website does not exist try { $webResults = Invoke-WebRequest -Uri 'https://techthoughtssssssss.info/' } catch { $theError = $_ $theError.Exception } #The website exists, but the page does not try { $webResults = Invoke-WebRequest -Uri 'https://www.techthoughts.info/nope.htm' } catch { $theError = $_ # see all the sub-properties $theError | Format-List * -Force } #------------------------------------------------- # $Error $Error 1 / 0; $Error Get-Process -Name 'NotAProcess' $Error $Error.Clear() $Error[5] | Format-List * -Force #------------------------------------------------- #this example will help display some helpful message to the user #this example will only work in PowerShell 6.1+ $uri = Read-Host 'Enter the URL' try { $webResults = Invoke-WebRequest -Uri $uri -ErrorAction Stop } catch { $statusCodeValue = $_.Exception.Response.StatusCode.value__ switch ($statusCodeValue) { 400 { Write-Warning -Message "HTTP Status Code 400 Bad Request. Check the URL and try again." } 401 { Write-Warning -Message "HTTP Status Code 401 Unauthorized." } 403 { Write-Warning -Message "HTTP Status Code 403 Forbidden. Server may be having issues. Check the URL and try again." } 404 { Write-Warning -Message "HTTP Status Code 404 Not found. Check the URL and try again." } 500 { Write-Warning -Message "HTTP Status Code 500 Internal Server Error." } Default { throw } } } ================================================ FILE: LearnPowerShell/EP9 - PowerShell Remoting.ps1 ================================================ #____________________________________________________________ # https://www.techthoughts.info/powershell-remoting/ #____________________________________________________________ #region WinRM Links #Running Remote Commands #https://docs.microsoft.com/en-us/powershell/scripting/learn/remoting/running-remote-commands?view=powershell-6 #Windows Remote Management #https://docs.microsoft.com/en-us/windows/win32/winrm/portal #Installation and Configuration for Windows Remote Management #https://docs.microsoft.com/en-us/windows/win32/winrm/installation-and-configuration-for-windows-remote-management #Making the second hop in PowerShell Remoting #https://docs.microsoft.com/en-us/powershell/scripting/learn/remoting/ps-remoting-second-hop?view=powershell-6 #PowerShell remoting over SSH #https://docs.microsoft.com/en-us/powershell/scripting/learn/remoting/ssh-remoting-in-powershell-core?view=powershell-6 #How to configure WinRM for HTTPS manually #https://www.visualstudiogeeks.com/devops/how-to-configure-winrm-for-https-manually #endregion #region ComputerName # Per PowerShell documentation you can find a list of cmdlets that support ComputerName with the following: Get-Command | Where-Object { $_.parameters.keys -contains "ComputerName" -and $_.parameters.keys -notcontains "Session" } # this will prompt you to enter your access credentials. the creds will be securely stored in the variable $creds = Get-Credential # restart a single computer Restart-Computer -ComputerName RemoteDevice -Credential $creds # restart several computers Restart-Computer -ComputerName RemoteDevice1, RemoteDevice2, RemoteDevice3 -Credential $creds # restart an entire list of computers $devices = Get-Content -Path C:\listOfServers.txt Restart-Computer -ComputerName $devices -Credential $Creds -Force #endregion #region WinRM #verify that WinRM is setup and configured locally Test-WSMan # basic WinRM configuration with default settings winrm quickconfig # example of WinRM configuration with more specific settings winrm quickconfig -transport:https # check winrm settings winrm get winrm/config/client winrm get winrm/config/service Get-Process C:\> winrm enumerate winrm/config/listener Listener Address = * Transport = HTTP Port = 5985 Hostname Enabled = true URLPrefix = wsman CertificateThumbprint ListeningOn = 10.0.3.253, 127.0.0.1, 192.168.1.253, ::1, #verify that WinRM is setup and responding on a remote device #you must specify the authentication type when testing a remote device. #if you are unsure about the authentication, set it to Negotiate $credential = Get-Credential Test-WSMan RemoteDeviceName -Authentication Negotiate -Credential $credential #verify local device is listening on WinRM port Get-NetTCPConnection -LocalPort 5985 #verify a remote device is listening on WinRM port Test-NetConnection -Computername 192.168.34.13 -Port 5985 #establish an interactive remote session $credential = Get-Credential Enter-PSSession -ComputerName RemoteDeviceName -Credential $credential #basic session opened to remote device $session = New-PSSession -ComputerName RemoteDeviceName -Credential domain\user #session opened to device over SSL $credential = Get-Credential $sessionHTTPS = New-PSSession -ComputerName RemoteDeviceName -Credential $credential -UseSSL #establish sessions to multiple devices $credential = Get-Credential $multiSession = New-PSSession -ComputerName RemoteDeviceName1, RemoteDeviceName2, RemoteDeviceName3 -Credential $credential #establish session to an entire list of devices $devices = Get-Content -Path C:\listOfServers.txt $credential = Get-Credential $multiSession = New-PSSession -ComputerName $devices -Credential $credential #session opened with advanced session options configured $sessionOptions = New-PSSessionOption -SkipCNCheck -SkipCACheck -SkipRevocationCheck $advancedSession = New-PSSession -ComputerName 10.0.3.27 -Credential user -UseSSL -SessionOption $so #endRegion #region Invoke-Command examples #get the number of CPUs for each remote device Invoke-Command -Session $sessions -ScriptBlock { (Get-CimInstance Win32_ComputerSystem).NumberOfLogicalProcessors } #get the amount of RAM for each remote device Invoke-Command -Session $sessions -ScriptBlock { Get-CimInstance Win32_OperatingSystem | Measure-Object -Property TotalVisibleMemorySize -Sum | ForEach-Object { [Math]::Round($_.sum / 1024 / 1024) } } #get the amount of free space on the C: drive for each remote device Invoke-Command -Session $sessions -ScriptBlock { $driveData = Get-PSDrive C | Select-Object Used, Free $total = $driveData.Used + $driveData.Free $calc = [Math]::Round($driveData.Free / $total, 2) $perFree = $calc * 100 return $perFree } #get the number of CPUs for each remote device Invoke-Command -Session $sessions -ScriptBlock { (Get-CimInstance Win32_ComputerSystem).NumberOfLogicalProcessors } #get the amount of RAM for each remote device Invoke-Command -Session $sessions -ScriptBlock { Get-CimInstance Win32_OperatingSystem | Measure-Object -Property TotalVisibleMemorySize -Sum | ForEach-Object { [Math]::Round($_.sum / 1024 / 1024) } } #get the amount of free space on the C: drive for each remote device Invoke-Command -Session $sessions -ScriptBlock { $driveData = Get-PSDrive C | Select-Object Used, Free $total = $driveData.Used + $driveData.Free $calc = [Math]::Round($driveData.Free / $total, 2) $perFree = $calc * 100 return $perFree } #stop the BITS service on all remote devices Invoke-Command -Session $sessions -ScriptBlock { Stop-Service BITS -Force } #endregion #region PowerShell-Linux-Remote-Access #install openssh sudo apt install openssh-client sudo apt install openssh-server #Edit the sshd_config file at location /etc/ssh #Make sure password authentication is enabled: PasswordAuthentication yes #Add a PowerShell subsystem entry: Subsystem powershell /usr/bin/pwsh -sshs -NoLogo -NoProfile #Optionally, enable key authentication: PubkeyAuthentication yes #Restart the sshd service. sudo service sshd restart #establish an interactive session to a remote Linux device $session = New-PSSession -HostName RemoteDevice -UserName user -SSHTransport Enter-PSSession $session #execute commands on a remote Linux device $session = New-PSSession -HostName RemoteDevice -UserName user -SSHTransport Invoke-Command -Session $session -ScriptBlock { Get-Process } #alternative to running Invoke-Command in parallel #foreach forces sequential connection and return for each server in the list #establish session to an entire list of devices $devices = Get-Content -Path C:\listOfServers.txt $credential = Get-Credential foreach ($server in $devices) { Invoke-Command -ComputerName $server -ScriptBlock { $env:COMPUTERNAME } -Credential $credential } #endregion #region advanced WinRM #add server to trusted hosts Get-ChildItem WSMan:\localhost\Client\TrustedHosts winrm s winrm/config/client '@{TrustedHosts="673448-RAXDC01"}' winrm s winrm/config/client '@{TrustedHosts="579188-HYP1"}' #domain to domain (http) New-PSSession -ComputerName Test-Join -Credential domain\user $domainToDomainHTTP = New-PSSession -ComputerName RemoteDeviceName -Credential domain\account #domain to domain (requires https listener and certificates pre-configured) New-PSSession -ComputerName Test-Join -Credential domain\user -UseSSL $domainToDomainHTTPS = New-PSSession -ComputerName PDC2 -Credential domain\account -UseSSL #by IP self-signed cert $so = New-PSSessionOption -SkipCNCheck -SkipCACheck -SkipRevocationCheck $test = New-PSSession -ComputerName 10.0.3.27 -Credential domain/account -UseSSL -SessionOption $so #change port WinRM listens on winrm/config/Listener?Address=*+Transport=HTTP '@{Port="8888"}' #check WinRM settings Get-WSManInstance -ResourceURI winrm/config/service/Auth Get-WSManInstance -ResourceURI winrm/config/client/Auth Get-WSManInstance -ResourceURI winrm/config/client #endregion #region final Example #declare servers we will connect to remotely $servers = 'Server1', 'Server2', 'Server3', 'Server4' #capture credentials used for remote access $creds = Get-Credential #declare array to hold remote command results $remoteResults = @() #declare a splat for our Invoke-Command parameters $invokeSplat = @{ ComputerName = $servers Credential = $creds ErrorVariable = 'connectErrors' ErrorAction = 'SilentlyContinue' } #execute remote command with splatted parameters. #store results in variable #errors will be stored in connectErrors $remoteResults = Invoke-Command @invokeSplat -ScriptBlock { #declare a custom object to store result in and return $obj = [PSCustomObject]@{ Name = $env:COMPUTERNAME CPUs = "-------" Memory = "-------" FreeSpace = "-------" } #retrieve the CPU / Memory / Hard Drive information $obj.CPUs = (Get-CimInstance Win32_ComputerSystem).NumberOfLogicalProcessors $obj.Memory = Get-CimInstance Win32_OperatingSystem ` | Measure-Object -Property TotalVisibleMemorySize -Sum ` | ForEach-Object { [Math]::Round($_.sum / 1024 / 1024) } $driveData = Get-PSDrive C | Select-Object Used, Free $total = $driveData.Used + $driveData.Free $calc = [Math]::Round($driveData.Free / $total, 2) $obj.FreeSpace = $calc * 100 return $obj } #capture any connection errors $remoteFailures = $connectErrors.CategoryInfo ` | Where-Object { $_.Reason -eq 'PSRemotingTransportException' } ` | Select-Object TargetName, @{n = 'ErrorInfo'; E = { $_.Reason } } #endregion ================================================ FILE: README.md ================================================ # Learn PowerShell ![PowerShell 5.1](https://img.shields.io/badge/PowerShell-5.1-blue.svg) ![PowerShell Core](https://img.shields.io/badge/PowerShell-6+-black.svg) ![PowerShell 7](https://img.shields.io/badge/PowerShell-7+-purple.svg) ![Cross Platform](https://img.shields.io/badge/platform-windows%20%7C%20macos%20%7C%20linux-lightgrey) ## Synopsis Contains code examples used in the [Learn PowerShell Video & Blog series](https://www.techthoughts.info/learn-powershell-series/) for easy reference. ## Description [Learn PowerShell Video & Blog series](https://www.techthoughts.info/learn-powershell-series/) is an operationally focused blog and video series designed to get you ramped up and using PowerShell quickly. The course provides numerous PowerShell examples which can be referenced in the *LearnPowerShell* directory. Examples are broken down by episode. ## Why To easily reference code examples provided in each episode. ## Accessing the PowerShell course ### Prerequisites * Access the [Learn PowerShell Video & Blog series](https://www.techthoughts.info/learn-powershell-series/) * [PowerShell 5.1/6.1+/7+ installed](https://github.com/PowerShell/PowerShell/releases) ## Author [Jake Morrison](https://twitter.com/JakeMorrison) - [https://www.techthoughts.info/](https://www.techthoughts.info/) ## Contributors [Kenneth Carnes](https://twitter.com/kennethcarnes1) ## License This project is [licensed under the MIT License](LICENSE).