class: center, middle # Basics of Windows PowerShell The Console is your friend --- ## Familiarising the Console and the ISE - The console - Windows PowerShell - Windows PowerShell (x86) - The [administrator] window for both - The Integrated Scripting Environment (.small-caps[ISE]) - Windows PowerShell .small-caps[ISE] - Windows PowerShell .small-caps[ISE] (x86) - The [administrator] window for both [Read more](//ramiyer.io/familiarising-the-powershell-windows). --- ## Remember less, use more logic - Verb-Noun format - Approved verbs that tell you what exactly is being done - Getting commands based on the nouns and the verbs easy - Output in columns make more sense - Ability to give custom names to columns - No juvenile talk in help - `-Syntax` - `-Examples` --- ## Find commands easily - Use `Get-Command` to find commands easily - Use the `-Verb` and `-Noun` parameters as quick filters - Wildcards work for command search ```powershell Get-Command -Noun 'Date' Get-Command -Verb 'Set' Get-Command -Name Get-Date ``` [Read more](//ramiyer.io/a-brief-history-of-windows/). --- ## Readily available help ```powershell Get-Command -Verb 'Get' -Noun '*service*' # You would then try to find some help for that specific command: Get-Help Get-Service # Not very helpful? Need complete help documentation? No problem: Get-Help Get-Service -Full # Still not helpful? Would you like to see an example or two? Here: Get-Help Get-Service -Examples ``` [Read more](//ramiyer.io/a-brief-history-of-windows/#easier-help). --- ## Aliases Helpful when: - Switching from the .small-caps[CMD] world - You want to reduce keystrokes - You are feeling lazy --- ## Caveats of aliases - They’re not readable - They’re not particularly understandable - They’re not portable: Custom aliases require configuration to work everywhere ```powershell # Readability gsv bits | spsv -wh # Understandability ls | ? {$_.psiscontainer} | % {"{0}`t{1}" -f $_.name,$_.lastaccesstime} ``` --- ## Aliases: The Don’ts - Do not use aliases if you’re starting straight off with PowerShell - Do not use aliases in scripts - Do not use off entire .small-caps[CMD] commands as aliases For instance, `dir /?` would translate to `Get-ChildItem /?` in PowerShell, which is syntactically wrong. [Read more](//ramiyer.io/aliases-execution-policies-and-other-friendly-features/#aliases-in-powershell). --- ## Execution Policy Security feature added to protect from execution of unknown code ```powershell AwesomeScript.ps1 cannot be loaded because the execution of scripts is disabled on this system. ``` --- ## Execution policy The different policies: - Restricted (default) - AllSigned - RemoteSigned - Unrestricted - Bypass - Undefined --- ## Execution Policy Scope: The Hierarchy - Process - CurrentUser - LocalMachine [Read more](//ramiyer.io/aliases-execution-policies-and-other-friendly-features/#execution-policies-in-powershell). --- ## PowerShell looks out for you - Execution Policy - `-WhatIf` - `-Confirm` -- ```powershell File E:\My works\My PowerShell Scripts\MembershipModifier\PowerShell\Scripts\LoadDialog.ps1 cannot be loaded because running scripts is disabled on this system. ``` --- ## PowerShell looks out for you ```powershell Set-ExecutionPolicy : Access to the registry key 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell' is denied. To change the execution policy for the default (LocalMachine) scope, start Windows PowerShell with the "Run as administrator" option. ``` -- ```powershell C:\Users\Ram> Get-AppxPackage | Where-Object {$_.Name -like '*twitter*'} | Remove-AppxPackage -WhatIf What if: Performing the operation "Remove package" on target "9E2F88E3.Twitter_5.0.3.0_x86__wgeqdkkx372wm". ``` --- ## PowerShell looks out for you ```powershell C:\Users\Ram> Get-AppxPackage | Where-Object {$_.Name -like '*twitter*'} | Remove-AppxPackage Confirm Are you sure you want to perform this action? Performing the operation "Remove package" on target "9E2F88E3.Twitter_5.0.3.0_x86__wgeqdkkx372wm". [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): ``` [Read more](//ramiyer.io/aliases-execution-policies-and-other-friendly-features/#shouldprocess-and-shouldcontinue). --- ## Formatting always in the end - Formatting options - `Format-Table` - `Format-List` - `Format-Wide` - `Format-Custom` --- ## Formatting always in the end - Formatting converts object to text - Kills the power of PowerShell - Difficult to pipe over formatted output - `-Format` and `-UFormat` are different from the Format cmdlets [Read more](//ramiyer.io/piping-commands-in-powershell/#formatting-the-output). --- ## The other “Drives” PowerShell treats Registry, File System, Aliases, etc. as drives. --- ## The other “Drives” ```powershell PS C:\Users\Ram> Get-PSDrive | select name, provider Name Provider ---- -------- Alias Microsoft.PowerShell.Core\Alias C Microsoft.PowerShell.Core\FileSystem ... HKLM Microsoft.PowerShell.Core\Registry Variable Microsoft.PowerShell.Core\Variable WSMan Microsoft.WSMan.Management\WSMan ``` --- ## The other “Drives” ```powershell PS C:\Users\Ram> Set-Location HKLM:\SOFTWARE PS HKLM:\SOFTWARE> ``` --- ## The dirtier your hands, the better you get - PowerShell to get simple information - Experimentation with cmdlets - One-liners for bulk tasks - Who knows, PowerShell might, someday, make coffee for you! --- class: middle # Getting Started with Cmdlets --- ## What are they? Most cmdlets are .small-caps[.NET] functions syntactically simplified for the benefit of administrators by means of encapsulation. --- ## Parts of a cmdlet ```powershell Get-Help Get-ChildItem ``` - The cmdlet itself, as Verb-Noun - Parameters - Switches - Parameter Sets In PowerShell, parameters and switches are all, technically, parameters. --- ## Named parameters - Explicitly specify what is being passed - Sometimes optional - Best practice to always use them ```powershell # List out contents of a folder Get-ChildItem -Path 'C:\Temp' ``` --- ## Positional Parameters - Adheres to the “more logic; less remembering” philosophy - Minimises keystrokes - Predefined contextual input mechanism ```powershell # To restart a computer Restart-Computer WORKSTATION01 # This is in fact: Restart-Computer -ComputerName 'WORKSTATION01' ``` --- ## Positional Parameters PowerShell _understands_ that you’re giving it the `ComputerName` [Read more](//ramiyer.io/basics-of-cmdlets/#positional-parameters). --- ## Multi-valued parameters - When you want a certain task done on multiple computers - Name the parameter (as a best practice) and separate the values with commas - Check the cmdlet help to see if it accepts multi-valued input ```powershell Restart-Computer -ComputerName 'WORKSTATION01', 'WORKSTATION02', 'WORKSTATION03' ``` --- ## Switch parameters - Tell PowerShell whether something has to be done or not - Binary in nature; `$true` and `$false` are the possible values - By default, _in most cases_, not specifying the switch stands for `$false` and just calling the parameter stands for `$true` ```powershell # At the movies Get-Popcorn -LowSalt # If specifying TRUE or FALSE Get-Popcorn -LowSalt:$true ``` --- ## Switch Parameters In some cases, like when PowerShell is looking out for you: ```powershell Get-Popcorn -Flavour Caramel | Burn-Popcorn Confirm Are you sure you want to perform this action? Performing the operation "Burn popcorn" on target "Caramel Popcorn". [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): ``` --- ## Switch Parameters The switch `-Confirm` is set to true by the maker of the cmdlet. If you know what you’re doing, and don’t want a confirmation prompt: ```powershell Get-Popcorn -Flavour Caramel | Burn-Popcorn -Confirm:$false ``` --- ## Parameter sets - Parameters are logically pre-grouped based on the actions they perform - Avoid mutually exclusive events and other such conflicts - Get-Help lists out these parameter sets in the `SYNTAX` section --- ## Parameter sets For example, the following won’t make sense ```powershell New-Burger 'AwesomeQuinoa' Set-Burger -Burger 'AwesomeQuinoa' ` -Sauce Barbecue ` -Add -Remove ``` [Read more](//ramiyer.io/basics-of-cmdlets/#parameter-sets). --- ## Basics of Piping - Pipes pass output from one cmdlet to another - Objects (not text) are transferred through the pipes ```powershell Get-ChildItem -Path 'C:\Temp' | Export-Csv -Path 'C:\Users\MyName\Documents\FolderExport.csv' ``` ```powershell Get-ChildItem -Path 'C:\Temp' | Measure-Object ``` Since the output is objects, they could be easily counted. --- class: middle ## Practical use of piping --- ### Column selection and sorting - Manipulate output to show us only what we need - Sort the content based on when the files were created - And do a lot more ```powershell Get-ChildItem -Path 'D:\Employee Details' | Select-Object Name, LastWriteTime ``` --- ### Column selection and sorting Let’s now export this to a .small-caps[CSV] file: ```powershell Get-ChildItem -Path 'D:\Employee Details' | Select-Object Name, LastWriteTime | Export-Csv -Path 'D:\Export\EmployeeDetails.csv' ``` Read more about [piping commands](//ramiyer.io/piping-commands-in-powershell/) and the [`select` statement](//ramiyer.io/piping-commands-in-powershell/#using-the-pipeline-to-select-properties). --- ### Pipe to filters The concept of pronouns (current subject): > Ryan stood in the queue at the counter. _He_ checked _his_ wallet to ensure _he_ had enough money for a balcony ticket. --- ### Pipe to filters PowerShell handles this using an automatic variable, `$PsItem` (or `$_`). ```powershell Get-ChildItem -Path 'D:\Employee Details' ` | Select-Object Name, LastWriteTime ` | Where-Object {$PsItem.LastWriteTime.Year -ge 2015} ``` [Read more about filters in PowerShell](//ramiyer.io/piping-commands-in-powershell/#filtering-the-output-based-on-a-parameter). .footnote[.red[*] Notice the use of `$PsItem.LastWriteTime.Year`], something like `(TheCurrentObject).LastWriteTime.Year`] --- ## Variables - Make programming possible and bring out the best in PowerShell - No pre-definition required in most cases, but is recommended - Data type definition is not required in most cases, but is recommended --- ## Variable conventions - All variables start with a `$` - They can be alpha-numeric - Just the variable name, no datatype such as `strName` - Use PascalCase (the first letter of all words should be capital) --- ## Variable best practices - Complete and meaningful (`$LastName` instead of `$LN`) - Concise like `$FavouriteBlueShirt` and not `$TheBlueShirtMyFriendsCallAwesome` - No underscores - Place variables with predefined values at the beginning to aid other scripters --- ## Inclusion in the output - Variables whose _value_ should be taken as a string should be enclosed in double quotes (**Expanding Strings**) - Variables that you want to appear as such, should be in single quotes (**Literal Strings**) --- ## Examples ```powershell # If value has to appear in the output $ComputerName = 'CaptainKirk' Write-Host "$ComputerName has taken down the Enterprise" > CaptainKirk has taken down the Enterprise ``` -- ```powershell # If the variable name has to appear in the output $ComputerName = 'CaptainKirk' Write-Host '$ComputerName has taken down the Enterprise' > $ComputerName has taken down the Enterprise ``` --- ## Things to note Variable carrying the output of a cmdlet contains the same objects that are part of the cmdlet output ```powershell # Cmdlet output (Get-ChildItem).Name # When using a variable $Files = Get-ChildItem $Files.Name # Gives the same output as before ``` --- ## Things to note Variables can be reused without reinitialising them—the datatype automatically switches .red[*] Careful when overloading variables; they can become a mess if not handled right --- ## Exercises Find the Print Spooler service and stop it. Start it a few moments later. -- ```powershell Get-Service | Where-Object Name -eq 'Spooler' | Stop-Service -Force ``` -- Alternatively, ```powershell Stop-Service -Name Spooler ``` Or if you’re feeling playful, even, ```powershell Set-Service -Name 'Spooler' -Status 'Stopped' ``` --- ## Exercises Generate a list of all .small-caps[PDF] files in a certain folder. -- See how to find the file type ```powershell # List only files, omit directories Get-ChildItem -File # Select only one file and list all its properties Get-ChildItem -File | Select-Object -Property * -First 1 ``` --- ## Exercises You’ll see there’s a field called `Extension`. Filter the output using the property. -- ```powershell Get-ChildItem | Where-Object Extension -eq '.pdf' ``` --- ## Exercises List the first ten processes running in the system at the moment. -- ```powershell Get-Process | Select-Object -First 10 ``` -- Display a list of aliases. -- ```powershell Get-Alias ``` -- Create a new alias, `proc` to list all running processes. -- ```powershell New-Alias -Name 'proc' -Value 'Get-Process' ``` --- ## Exercises List out all services whose names start with ‘P’. -- ```powershell Get-Service | Where-Object Name -like 'P*' ``` And if you’d rather avoid keystrokes, ```powershell Get-Service 'P*' ``` Or if you're hopelessly lazy, ```powershell gsv 'P*' ``` --- ## Some Gotchas Now that we’re comfortable with PowerShell, let’s look at some gotchas. --- ## Some Gotchas - You can select columns within cmdlets like `Format-Table`. -- - You can run a certain PowerShell cmdlet from a cmd window without actually launching PowerShell. -- - `Out-GridView` shows the output in a nice sortable, filterable table. -- - Dotted notations can be used to quickly fetch members of the objects the cmdlets return. -- - Array outputs' count can be directly accessed without `Measure-Object`. --- ## Gotchas in action ```powershell # Selecting columns in Format-Table Get-ChildItem -Path . | Format-Table Name, LastWriteTime -Autosize ``` -- ```dos C:\> powershell -command "& {Get-Process | Export-Csv ProcessList.csv -NoTypeInformation}" ``` -- ```powershell # Output the table as a nice grid Get-Service | Out-GridView ``` --- ## Gotchas in action ```powershell # Quickly select just the column data using dotted notation (Get-Service).DisplayName ``` -- ```powershell # Count returned objects in an array (Get-Verb).Count ``` --- ## Grouping objects - Objects can be grouped based on properties. - Example: You can group all the services in the system based on whether they’re running or not. - Output shows the count in each group as well. ```powershell # Group services based on their status Get-Service | Group-Object -Property Status ``` --- ## PowerShell Profile - Automation of user-specific configuration. - Runs every time PowerShell is loaded. - Different profiles for different PowerShell environments. - Location stored in a built-in variable. ```powershell $PROFILE C:\Users\Ram\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 ``` .footnote[.red[*]] The profiles will load provided the execution policy allows them to. --- ## Playing with PowerShell providers - Use `Get-PsProvider` to list out the available providers. - Providers can be connected to using Set-Location. - Ensure to add `:` at the end of the provider’s name when setting location. - Cmdlets like `Get-ChildItem` would work on most of these providers. --- ## Playing with PowerShell providers ```powershell # List out all providers Get-PsProvider # Connect to the Alias: provider Set-Location Alias: # List out all the aliases within Get-ChildItem ``` --- ## Environment variables - Windows shell usually understands them as %VARIABLE%. - PowerShell stores these variables within a PsDrive, called `env:`. - Notation is simplified, like `$env:USERNAME`. - Retrieve the list of these using `Get-ChildItem`. - Get details on each of these using `Get-Item`. - In general, these work because everything within PowerShell is treated as an object. --- class: middle # Remoting using PowerShell --- ## Why remoting? -- - Why not remoting?! -- - Brings out the Power in PowerShell -- - Needs PowerShell remoting enabled at the destination ```powershell Enable-PsRemoting ``` --- ## How to remote - The `ComputerName` parameter. -- - Remoting using Invoke-Command. -- - Using single-instance `Enter-PsSession`. -- - Pass credentials with `Enter-PsSession` if you don’t want the session to impersonate the logged-on user. -- - Using saved sessions and `Enter-PsSession`. -- .red[*] Remote sessions created using `Enter-PsSession` are real sessions running on remote computers. Changing directory and other operations happen on the remote computer you’ve connected to. --- ## Remoting cmdlets ```powershell # Running a single command on a remote computer Invoke-Command -ComputerName MyRemoteComputer -ScriptBlock {Get-Process | Select-Object -First 10} ``` ```powershell # Enter a simple session with impersonation Enter-PsSession -ComputerName 'MyRemoteComputer' # Exit the remote interactive PowerShell session exit ``` --- ## Remoting cmdlets ```powershell # Create a PowerShell session for use later $MySession = New-PsSession -ComputerName 'MyRemoteComputer' -Credential MyDomain\MyUsername # Enter the session with just the name Enter-PsSession $MySession ``` ```powershell # Single remote command using a session variable Invoke-Command -Session $MySession -ScriptBlock {Get-Process | Select-Object -First 10} ``` --- ## Points to keep in mind - Always remove sessions that are no more going to be used, using `Remove-PsSession $MySession`. - `Invoke-Command` can be run against multiple computers since `-ComputerName` accepts an array as input. - Returns the `PsComputerName` as well, which helps identify which computer returned what information. [Read more](//ramiyer.io/remoting-in-powershell).