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