PowerShell - ilya-khadykin/notes-outdated GitHub Wiki
TO DO:
- review and add new information from http://ss64.com/ps/syntax-arrays.html
- review and add new information from http://ss64.com/ps/syntax-functions.html
- review and add new information from http://ss64.com/ps/syntax-args.html
- review and add new information from http://stackoverflow.com/documentation/powershell/topics
- https://social.technet.microsoft.com/wiki/contents/articles/7703.powershell-running-executables.aspx
Sometimes in order to be able to run certain commandlets you have to change execution policy using the following command:
Set-ExecutionPolicy RemoteSigned
Commandlets (1)
Commandlets or Cmdlt are basically commands you can use in your PowerShell scripts. All of them are orgasmed in a certain standardized fashion <verb>-<noun>
and have detailed help files you can read using this cmdlt get-help <commandlet-name>
, for example:
get-help * # shows help about specified topic or cmdlt
update-help # updates local help files from the Internet
test-connection 192.168.1.1 # test connection to specified computer using ICMP echo request packets
More formal definition:
A cmdlet is a lightweight command that is used in the Windows PowerShell environment. The Windows PowerShell runtime invokes these cmdlets within the context of automation scripts that are provided at the command line. The Windows PowerShell runtime also invokes them programmatically through Windows PowerShell APIs.
Cmdlets perform an action and typically return a Microsoft .NET Framework
object to the next command in the pipeline.
Everything is an Object (3)
PowerShell uses Objects as its output rather than text like bash
in Linux or legacy command prompt. This is a big deal because you are no longer have to parse the output of the command and use regular expressions.
Every object has properties and methods. You can see an object's properties and methods by passing it to the Get-Member
cmdlet.
The objects that a PowerShell cmdlet outputs are largely underlying types from the .Net framework, but you can create your own objects if you need to use a language like C# or use the PSObject type.
There are plenty of Linux shells with a pipeline, allowing you to send the text that one command outputs as input to the next command in the pipeline. PowerShell takes this to the next level by allowing you to take the objects that one cmdlet outputs and pass them as input to the next cmdlet in the pipeline.
The trick is knowing what type of object a cmdlet returns, which is really easy when using the Get-Member
cmdlet.
Get-Service | Get-Member
Get-Member
cmdlet also returns another important piece of information, the underlying object type, for example: System.ServiceProcess.ServiceController
Since PowerShell deals with objects and not text, not all cmdlets can be linked together using the pipeline. That means we need to find a cmdlet that’s looking to accept a System.ServiceProcess.ServiceController
object from the pipeline with the following command:
Get-Command -ParameterType System.ServiceProcess.ServiceController
Use Get-Help -Name <Cdlt-name> –Full
to get more information about the cmdlt and how you can use it.
Formatting, Filtering and Comparing objects (4)
PowerSheel may not show every property of an object by default because it may be overwhelming to see all the details. Instead, it uses the following file C:\Windows\System32\WindowsPowerShell\v1.0\DotNetTypes.format.ps1xml
as formatting information.
But what if the object type you are dealing with doesn't have an entry in that file, or any other format file for that matter? Well then, it's quite simple actually. If the object coming out of the pipeline has 5 or more properties, PowerShell displays all of the object's properties in a list; if it has less than 5 properties, it displays them in a table.
If you are not happy with the default formatting of an object or type, you can roll your own formatting. There are three cmdlets you need to know to do this:
-
Format-List
Get-Process | Format-List –Property *
- shows properties of an object as a list - **Format-Table **
Get-Process | Format-Table name,id –AutoSize
- takes data and turns it into a table -
Format-Wide
Get-Service | Format-Wide -Property DisplayName -Column 1
- simply takes a collection of objects and displays a single property of each object
One of the best things about using an object-based pipeline is that you can filter objects out of the pipeline at any stage using the Where-Object cmdlet.
Get-Service | Where-Object {$_.Status -eq “Running”}
Using where object is actually very simple. $_
represents the current pipeline object, from which you can choose a property that you want to filter on. Here, were are only keeping objects where the Status property equals Running. -eq
is a comparison operator in PowerShell
Variables (5)
Here is how to create a variable called “FirstName” and give it the value “John”.
$FirstName = "John"
Variables in PowerShell are weakly typed by default meaning they can contain any kind of data
In PowerShell, you can see all the variables you have created in the variable PSDrive.
gci variable:
Which means you can delete a variable from the shell at anytime too:
Remove-Item Variable:\FirstName
Variables don’t have to contain a single object either; you can just as easily store multiple objects in a variable. For example, if you wanted to store a list of running processes in a variable, you can just assign it the output of Get-Process
:
$Proc = Get-Process
The trick to understanding this is to remember that the right hand side of the equals sign is always evaluated first. This means that you can have an entire pipeline on the right hand side if you want to.
$CPUHogs = Get-Process | Sort CPU -Descending | select -First 3
The CPUHogs variable will now contain the three running processes using the most CPU.
When you do have a variable holding a collection of objects, there are some things to be aware of. For example, calling a method on the variable will cause it to be called on each object in the collection.
$CPUHogs.Kill()
Which would kill all three process in the collection. If you want to access a single object in the variable, you need to treat it like an array.
$CPUHogs[0]
There are a few comparison operators you can use in the filtering script block:
-
eq
(Equal To) -
neq
(Not Equal To) -
gt
(Greater Than) -
ge
(Greater Than or Equal To) -
lt
(Less Than) -
le
(Less Than or Equal To) -
like
(Wildcard String Match)
A full list and more information can be viewed in the about_comparison conceptual help file:
get-help about_Comparison_Operators -showWindow
You can prompt users for information using it is really simple:
$FirstName = Read-Host –Prompt ‘Enter your first name’
Writing output is just as easy with the Write-Output cmdlet.
Write-Output “How-To Geek Rocks!”
Writing Scripts (2)
The most of your work in Windows PowerShell will be done by writing and running scripts rather than using interactive console entering one commandlet at a time. I recommend using PowerShell Integrated Scripting Environment (ISE) which is shipped with PowerSheel, it makes the process of writing and testing scripts much easier.
Windows PowerShell scripts have .ps1
extension
You’ll often write a script or function that needs to accept some kind of input.
Param(
[string]$computerName,
[string]$filePath
)
Keep in mind that each parameter is its own entity, and it’s separated from the next parameter by a comma. You don’t have to use the [Parameter()]
decorator on every parameter (Only use it on the ones where you need to declare something, such as the parameter being mandatory, accepting pipeline input, being in a certain position and so on).
Run help Get-Help about_Functions_Advanced_Parameters
in Windows PowerShell for more information on other attributes you can declare that way.
Writing functions and scripts that accept input only via parameters is a best practice. It makes them more self-contained, easier to document and more consistent with the way the rest of the shell works.
If I put this into a script named Get-Something.ps1, I’d use the parameters like this:
./Get-Something –computerName SERVER1 –filePath C:\Whatever
I could also truncate the parameter names. This lets me type fewer characters and they still work:
./Get-Something –comp SERVER1 –file C:\Whatever
I could even omit the names entirely. Windows PowerShell will automatically and positionally accept values. Here I need to be careful to provide values in the same order in which the parameters are listed in my file:
./Get-Something SERVER1 C:\Whatever
Of course, by using parameter names, the command becomes a bit easier for a person to figure out. I then get the luxury of putting the parameters in any order I want:
./Get-Something –filePath C:\Whatever –computerName SERVER1
Windows PowerShell also provides a more complex way of declaring parameters. This more full-fledged syntax lets you define parameters as mandatory, specify a position (if you don’t do so, then the parameter can only be used by name) and more. This expanded syntax is also legal in both scripts and functions:
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True,Position=1)]
[string]$computerName,
[Parameter(Mandatory=$True)]
[string]$filePath
)
Again, you can run all that together on a single line, but breaking it down makes it a bit easier to read. I’ve given both of my parameters a [Parameter()] decorator, and defined them both as mandatory.
There are some other advantages to using the [CmdletBinding()]
directive. For one, it ensures my script or function will have all the Windows PowerShell common parameters, including –Verbose and –Debug. Now, I can use Write-Verbose and Write-Debug within my script or function, and their output will be suppressed automatically.
Run the script or function with –Verbose
or –Debug
, and Write-Verbose
or Write-Debug
(respectively) are magically activated. That’s a great way to produce step-by-step progress information (Write-Verbose
) or add debugging breakpoints (Write-Debug
) in your scripts.
Declaring parameter as [string[]]
would let you accept an entire collection of values. You’d then enumerate this using a Foreach
loop, so you could work with one value at a time.
Another neat parameter type is [switch]
:
Param([switch]$DoSomething)
Now, I can run my script or function with NO –DoSomething
parameter and internally the $DoSomething
variable will be $False
. If I run the script with the –DoSomething
parameter, $DoSomething
gets set to $True
. There’s no need to pass a value to the parameter. Windows PowerShell sets it to $True
if you simply include it. This is how switch parameters operate, such as the –recurse
parameter of Get-ChildItem
.
It's always a good idea to put help information in your scripts. It can be accessed by get-help YourScript.ps1
. Here is how you can add it
<#
.SYNOPSIS
Measures an average response time to a remote hosts and forms the resulting table
.DESCRIPTION
The script uses Test-Connection Cmdlt which sends Internet Control Message Protocol (ICMP) echo request packets ("pings"), calculates the average response time in turn and forms the resulting table showing the host with the lowest value at the top.
.PARAMETER hosts
The list of hosts you want to test
.PARAMETER count
The number of pings send to a remote host, 100 by default
.EXAMPLE
Get-AvgPingResponseTime -hosts 8.8.8.8, 8.8.4.4 -count 10
.LINK
https://github.com/m-a-ge/utilities
#>
param(
[string]$count = 100,
[Parameter(Mandatory=$true)][string]$hosts
)
If ($this -eq $that) {
# commands
} elseif ($those -ne $them) {
# commands
} elseif ($we -gt $they) {
# commands
} else {
# commands
}
Do {
# commands
} While ($this -eq $that)
While (Test-Path $path) {
# commands
}
$services = Get-Service
ForEach ($service in $services) {
$service.Stop()
}
Reading .csv file and looping through its contents:
$path = "d:\scratch\export.csv"
$csv = Import-Csv -path $path
foreach($line in $csv)
{
$properties = $line | Get-Member -MemberType Properties
for($i=0; $i -lt $properties.Count;$i++)
{
$column = $properties[$i]
$columnvalue = $line | Select -ExpandProperty $column.Name
# doSomething $column.Name $columnvalue
# doSomething $i $columnvalue
}
}
function Mine {
Get-Service
Get-Process
}
Mine
function Get-LetterCount {
Param ([string]$string)
Write-Host -ForegroundColor Cyan “string length is” $string.Length
$string | clip.exe
} # End Function Get-LetterCount
1..10 | ForEach-Object -process {
# code here will repeat 10 times
# use $_ to access the current iteration
# number
}
Due to security risks Windows PowerShell may not run scripts by default.
If the execution policy in all scopes is Undefined, the effective execution policy is Restricted, which is the default execution policy.
For more details read the help file:
get-help about_Execution_Policies -showWindow
You can change the settings using the following cmdlts:
# get the current execution policy
Get-ExecutionPolicy
# setting a new execution policy which allows you to run scripts only from a trusted publisher
Set-ExecutionPolicy -ExecutionPolicy AllSigned
$env:Path -split ";" | ft