PowerShell is a script language, compared to Bash on Linux, which used to run on the Microsoft Windows platform. But now, it has evolved to PowerShell Core
which isn't scoped to Windows only.
PowerShell tightly integrates with .NET but embodies a lot of script language features. I have observed a lot of guys are using PowerShell
with OOP style. This blog will explore some ways for PowerShell advanced usage.
1. Array Parameter
Suppose a function has a parameter, accepting array type.
Get-Process -Name <string[]>
At first glance, we need to prepare a array before invoking this function.
Get-Process -Name @("powershell", "explorer")
But, PowerShell can convert the comma separated string to array implicitly.
Get-Process -Name powershell, explorer
2. Array
If a function return more than one variables, the result would be array.
function Get-Something {
return 'Hello', 'World'
}
(Get-Something).GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
Like Python
, we can also select the part of elements from an array.
$range = 1, 2, 3, 4, 5
$range[2..4]
3
4
5
Some string method can be applied against the the string array. In this way, each element of this array will call the method respectively.
("azz", "abz", "zzz").trim("z")
a
ab
3. Splatting
If a function have a couple of parameters that cannot display in single line. you have two options:
- Wrap the editor
- Use line breaker
PowerShell has a functionality called Splatting
that can group the parameters
function Get-Process {
param (
[string[]]Name,
[int[]]Id
)
}$process = @{
Name = 'explorer'
}
Get-Process @process
We choose hashtable
to group all the argument and then pass it to the function.
@ instead of $
4. Property
For a custom object, it can add custom property dynamically. How retrieve the property value if don’t know the property name exactly. PowerShell’s .
operation can do that in the runtime.
$object = [pscutomobject]@{"some name" = "value"}
$object."some name" # value
$object.{some name} # value
$prop = "some name"
$object.$prop # value
5. Select-Object
Select-Object
is widely used command in PowerShell daily work. It can achieve couples of goals via parameter combination.
- Select properties:
Get-Process | Select-Object -Property Name, Id
- Select properties with wildcards:
Get-Process | Select-Object -Property Name, *Memory
- Select properties but exclude ones:
Get-Process | Select-Object -Property * -Exclude Memory
- Get first objects:
Get-Process | Select-Object -First 2
- Get last objects:
Get-Process | select-Object -Last 2
- Get object but skip ones:
Get-Process | Select-Object -Skip 4 -First 1
- Select property but expand them:
Get-Process | Select-Object -ExpandProperty Name
6. Array comparison operator
In general, the comparison operators
are used with scalar values. The result should be true
or false
. When an array applies to the comparison operator
, the result consists of elements that match the criteria.
1, $null -ne $null # 1
1,2,3,4 -ge 3 #3, 4
'One', 'Two', 'Three' -like '*e*' # 'one', 'three'
What if it is used in test whether any element match criteria.
$array = 1, 2, 3
if ($array -gt 3) {
Write-Host "Greater than 3"
}
# greater than 3
7. Redirection
In Bash, it has three major stream. stdout, stderr and stdin . It also has those concepts in the PowerShell as well.
It means you can direct the output for a specific stream.
function Test-Redirect {
'This is standard out'
Write-Error 'This is an error'
Write-Warning 'This is a warning'
}
$stdOut = Test-Redirect 3 > "warning.txt" 2> 'error.txt'
Get-Content 'Warning.txt'
# This is a warning
Get-Content 'error.txt'
# This is an error
It also supports to discard the output, like ls > /dev/null
used in bash
.
Get-Process > $null
# or
Get-Process | out-null
8. Confirm/WhatIf/Force
Confirm
, Force
and Whatif
are used to cooperate with other commands which are going to make change.
Confirm
parameter will introduce a prompt before actually complete a job.
> cd $env:TEMP
> New-Item data.txt
> Remove-Item data.txt -Confirm
Confirm
Are you sure you want to perform this action?
Performing the operation "Remove File" on target "C:\\Users\\fenga\\AppData\\Local\\Temp\\data.txt".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"):
Sometimes, the prompt shows up by default. Setting Confirm:$false
can bypass the prompt.
Clear-RecycleBin -Confirm:$false
A question to raise is that how to determine the prompt shows up? In PowerShell
session, it has ConfirmPreference
variable.
> $ConfirmPreference
High
Each command has the CmdletBindling
attribute with ConfirmImpact
property, e.g.
[CmdletBinding(ConfirmImpact='High')]
When executing each command, it will compare the $ConfirmPreference
and ConfirmImpact
.
> $ConfirmPreference="Low"
> New-Item data.txt
Confirm
Are you sure you want to perform this action?
Performing the operation "Create File" on target "Destination: C:\\Users\\fenga\\AppData\\Local\\Temp\\data.txt".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"):
WhatIf
presents with a simple statement that should state what would have been done.
> New-Item data.txt -Force
> Remove-Item data.txt -WhatIf
What if: Performing the operation "Remove File" on target "C:\\Users\\fenga\\AppData\\Local\\Temp\\data.txt".
By adding WhatIf
parameter, it didn't delete data.txt
actually. Same with Confirm
parameter, the WhatIfPreference
variables holds on a Boolean value.
$WhatIfPreference=$true
New-Item newfile.txt
What if: Performing the operation "Create File" on target "Destination: C:\\Users\\fenga\\AppData\\Local\\Temp\\newfile.txt".
How to define customized WhatIf
? It can be achieved by $pscmdlet.ShouldProcess
which wrap the code to execute.
function Test-ShouldProcess {
[CmdletBinding(SupportsShouldProcess)]
param()
if($pscmdlet.ShouldProcess("SomeObject", "delete")) {
Write-Host "Deleting SomeObject" -Foreground Cyan
}
}Test-ShouldProcess
What if: Performing the operation "delete" on target "SomeObject".
Force
parameter is widely used in command that avoid the prompt.
New-Item a.txt
Remove-Item a.txt -Force
9. Variable Scopes
PowerShell can limit the access to variables, aliases, functions by scope. It supports the following scopes:
- Global: The scope takes effect when PowerShell starts or when you create a new session or runspace.
- Local: The current scope. it can be the global scope or any other scope.
- Script: It is created while a script file runs.
Note: Private
is not a scope. It is an option to change the visibility of variable.
It has three basic rules of scope
- Scope may nest. An outer scope is referred to as the parents scope
- A variable in the scope is visible in which it was created and in any child scopes. Unless you explicitly make it private.
- A variable can be only changed in the scope in which it was created.
Sample 1
$local:thisValue = "Some Value"
"From Local: $local:thisValue" # From Local: Some Value
"From Global: $global:thisValue" # From Global: Some Valuefunction Test-ThisScope {
"From Local: $local:thisValue"
"From Global: $global:thisValue"
}
Test-ThisScope
# From Local:
# From Global: Some Value
$local:thisValue
is defined in local scope but it's also means global scope. So, it is accessible in line 2 and line 3. In Test-ThisScope
which is the child scope of global scope, it isn't accessible with local
scope any more but works in global
scope.
Sample 2
$thisValue = "Some Value"function Test-ThisScope {
"From Local: $local:thisValue"
"From Global: $global:thisValue"
"Without scope: $thisValue"
}
Test-ThisScope
# From Local:
# From Global: Some Value
# Without scope: Some Value
$thisValue
doesn't place scope prefix and it means local
scope. Test-ThisScope
is child scope. If doesn't specify the scope, it will resolve by looking up the parent.
Sample 3
$private:thisValue="Some Value"
"From global: $global:thisValue" #From global: Some Value
function Test-ThisScope {
"Without scope: $thisValue"
"From Private: $private:thisValue"
"From global: $global:thisValue"
}
Test-ThisScope
# Without scope:
# From Private:
# From global:
None of value is accessible in the Test-ThisScope
function since it thisVAlue
is defined as global scope but with private
prefix.
10. Dot Source
Script and functions follows all the rules of rule. But, you can add a script or function to the current scope by using dot source. By doing so, any function, variables that the script creates are available in the current scope.
Here we define a Sample.ps1
PowerShell file.
# Sample.ps1
$ThisValue = "Hello World"function Test-Hello {
Write-Host "This is from sample"
}
We can import ThisValue
and Test-
to the current scope.
. ./Sample.ps1
$ThisValue # Hello World
Test-Hello # This is from sample
11. PSProvider / PSDriver
In PowerShell, the data has multiple source. They can be filesystem, registry, certificate, and so on.
PS> Get-PSProvider
Name Capabilities Drives
---- ------------ ------
Registry ShouldProcess {HKLM, HKCU}
Alias ShouldProcess {Alias}
Environment ShouldProcess {Env}
FileSystem Filter, ShouldProcess, Credentials {C,D, Temp}
Function ShouldProcess {Function}
Variable ShouldProcess {Variable}
Each provider
has their own Drives
. The driver is the place where store the data.
> Get-PSDrive
Name Used (GB) Free (GB) Provider Root
---- --------- --------- -------- ----
Alias Alias
C 135.84 340.23 FileSystem C:\\
Cert Certificate \\
D 0.66 236.72 FileSystem D:\\
Env Environment
Function Function
HKCU Registry HKEY_CURRENT_USER
HKLM Registry HKEY_LOCAL_MACHINE
Temp 135.84 340.23 FileSystem C:\\Users\\gaufung\\AppData\\Local\\Tem…
Variable Variable
WSMan WSMan
In other words, we could walk through the different drives via Set-Location
command.
Set-Location Cert:\\
Get-ChildItem
# Location : CurrentUser
# StoreNames : {AuthRoot, My, CA, Root…}# Location : LocalMachine
# StoreNames : {Disallowed, SmartCardRoot, Trust, TestSignRoot…}
12. Comment-Based Help
As we all know, Get-Help
command can help us display more details about a command. How can I leverage it when exporting our method to us? Yes, the answer is the MAML
. It has several concepts:
- .SYNOPSIS (Mandatory: Brief introduction for the function)
- .DESCRPTION (Mandatory: Detailed introduction for the function)
- .PARAMETER <Name>(Optional: parameter name explaination)
- .EXAMPLE (Optional: example of this function usage)
- .INPUTS (Optional)
- .OUTPUTS (Optional)
- .NOTES (Optional)
- .LINK (Optional)
function Get-Something {
<#
.SYNOPSIS
Brifly describe the main action performed by Get-Something
.DESCRIPTION
A detailed descrption of the activities of Get-Something
#>
}PS > get-help get-somethingNAME
Get-SomethingSYNOPSIS
Brifly describe the main action performed by Get-SomethingSYNTAX
Get-Something [<CommonParameters>]DESCRIPTION
A detailed descrption of the activities of Get-SomethingRELATED LINKSREMARKS
To see the examples, type: "Get-Help Get-Something -Examples"
For more information, type: "Get-Help Get-Something -Detailed"
For technical information, type: "Get-Help Get-Something -Full"