PowerShell can be started in a number of ways:

It should be noted that PowerShell is invariably used to carry out administrative tasks, and as such, will often need to be launched using the Run as administrator option (this enables the "administrative" token, as controlled by Windows' User Account Control protection).

You can quickly determine the version of PowerShell installed on the local machine by viewing the values in the built-in $PSVersionTable variable (this variable is a , or "associative array" - more on these later).

PS C:\Users\JohnDoe> $PSVersionTable; Name Value ---- ----- PSVersion 4.0 WSManStackVersion 3.0 SerializationVersion CLRVersion 4.0.30319.18444 BuildVersion 6.3.9600.16406 PSCompatibleVersions {1.0, 2.0, 3.0, 4.0} PSRemotingProtocolVersion 2.2 PS C:\Users\JohnDoe>

PowerShell introduces the concept of execution policies.  An execution policy determines under what conditions a PowerShell script will be allowed to run, thus providing a mechanism for securing computers against PowerShell-based malicious software (malware).   The default execution policy settings vary between the versions of Microsoft Windows.  However, the available policy values remain the same for all installations; they are:

Policy Value Effect
Restricted Scripts cannot execute.
AllSigned All scripts, whether on the local machine, or on a network resource, must be by a trusted publisher.
RemoteSigned Script on the local machine can execute, but remote scripts must be .
Unrestricted Unsigned scripts can be executed, but a warning will be displayed when executing scripts sourced from the Internet (see for further information).
Bypass Nothing is blocked and no warnings are displayed.  This setting should clearly not be used.

The current Execution Policy settings can be viewed using the Get-ExecutionPolicy cmdlet:

PS C:\Users\JohnDoe> Get-ExecutionPolicy -List; Scope ExecutionPolicy ----- --------------- MachinePolicy Undefined (Defined in Group Policy. Affects all users of the computer.) UserPolicy Undefined (Defined in Group Policy. Affects the current user only.) Process Undefined (Locally defined. Affects just this instance of POWERSHELL.EXE.) CurrentUser Undefined (Locally defined. Affects the current user only.) LocalMachine Restricted (Locally defined. Affects all users of the computer.) PS C:\Users\JohnDoe>

Execution Policy settings can be controlled via Group Policy or by using the Set-ExecutionPolicy cmdlet.  For example, to change the Execution Policy for the current user to RemoteSigned, type:

PS C:\Users\JohnDoe> Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force; PS C:\Users\JohnDoe>

All current versions of Microsoft Windows are members of the "Windows NT" family, which dates back to 1993, when Windows NT 3.1 was released.  The internals of Windows NT and its derivatives are object-based, with virtually all operating system primitives (processes, threads, mutexes, semaphores, Etc.) and higher-level abstractions (file handles, COM objects, messages, services, Etc.) being represented as class objects with their own methods, properties and access control lists (ACLs).

So why mention this?  Well, PowerShell has been designed to interact with this object-based model natively.  That is, the default behaviour of PowerShell is to work with objects.  This makes PowerShell incredibly versatile in terms of what can be achieved from an interactive shell or script.

Up until now, the Windows Shell has behaved like MS-DOS, which, like most other shells, provides only textual interaction with the operating system.  For example, if you wish to list the contents of the current directory in the legacy Windows shell, you would type dir.  On a UNIX based operating system, you would type ls.  Both of these commands would return a textual list of files, directories and symbolic links, the formatting of which being dependent on the version of the operating system, the system locale, and certain user preferences.  If you were writing a script to carry out a task based on the contents of the current directory, you would have to use various commands, such as for, forfiles, findstr, grep, awk, Etc., to interpret the textual output, before carrying out your task.

PowerShell, on the other hand, works differently.  For example, when you use the Get-ChildItem cmdlet (or use one of its , such as gci, dir or ls) to list the contents of the current directory , it returns an of file system objects.  If you don't instruct PowerShell to do anything with the returned objects, it will "burst" them and render the results to the console as a textual representation.   This is demonstrated below.

PS C:\Users\JohnDoe> ls *.txt Directory: C:\Users\JohnDoe Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 24/10/2015 20:31 1794 file1.txt -a--- 24/10/2015 20:31 1236 file2.txt -a--- 24/10/2015 20:31 1922 file3.txt -a--- 24/10/2015 20:31 1076 file4.txt PS C:\Users\JohnDoe>
So, rather than just allow the objects to "burst", let's interact with the first element of the returned array (remember it's an instance of a file system object) and retrieve its last accessed date and time:
PS C:\Users\JohnDoe> (ls *.txt)[0].LastAccessTime; 24 October 2015 20:31:15 PS C:\Users\JohnDoe>
So that's a property retrieved.  We can also invoke one of the object's mehods:
PS C:\Users\JohnDoe> (ls *.txt)[0].Delete(); PS C:\Users\JohnDoe>

This is obviously a very simple, and somewhat contrived, example, but this concept carries through to all aspects of the Windows operating system, and any other technologies exposed to PowerShell (such as Microsoft Exchange Server and VMware vSphere).

PowerShell is made up of numerous cmdlets (lightweight commands).  The base installation of PowerShell V5.0 includes over 500 cmdlets and these can be extended upon by importing or adding snap-ins.

All cmdlets names follow the format verb-noun, where verb is the action you wish to perform, and noun is the object or item you wish to interact with.   The list of approved verbs is documented in Microsoft's TechNet library, with examples including: Add, Clear, Close, Copy, Find, Get, Move, Select, Test, Unlock and Watch (this list is not exhaustive).

The list of available nouns depends on which modules are loaded and which snap-ins have been added.  A subset of the default nouns includes Acl, Alias, ChildItem, Command, Computer, Content, Date, Event, File, Help, Html, Item, Json, List, Member, Module, Object, Output, Path, Process, RestMethod, Service, TimeSpan, Type and Xml.

The Get-Command cmdlet can be used to list the currently available cmdlets.

PS C:\Users\JohnDoe> Get-Command -CommandType cmdlet; CommandType Name ModuleName ----------- ---- ---------- Cmdlet Add-BitsFile BitsTransfer Cmdlet Add-Computer Microsoft.PowerShell.Management Cmdlet Add-Content Microsoft.PowerShell.Management Cmdlet Add-History Microsoft.PowerShell.Core Cmdlet Add-JobTrigger PSScheduledJob ... ... ... Cmdlet Write-Host Microsoft.PowerShell.Utility Cmdlet Write-Output Microsoft.PowerShell.Utility Cmdlet Write-Progress Microsoft.PowerShell.Utility Cmdlet Write-Verbose Microsoft.PowerShell.Utility Cmdlet Write-Warning Microsoft.PowerShell.Utility PS C:\Users\JohnDoe>

The Get-Command cmdlet can also return the commands that use the given verb or noun, for example:

PS C:\Users\JohnDoe> Get-Command -CommandType cmdlet -Verb Select; CommandType Name ModuleName ----------- ---- ---------- Cmdlet Select-Object Microsoft.PowerShell.Utility Cmdlet Select-String Microsoft.PowerShell.Utility Cmdlet Select-Xml Microsoft.PowerShell.Utility PS C:\Users\JohnDoe> Get-Command -CommandType cmdlet -Noun Xml; CommandType Name ModuleName ----------- ---- ---------- Cmdlet ConvertTo-Xml Microsoft.PowerShell.Utility Cmdlet Select-Xml Microsoft.PowerShell.Utility PS C:\Users\JohnDoe>

If you cannot remember the cmdlet that you require, you can use the -Name parameter with wildcards:

PS C:\Users\JohnDoe> Get-Command -CommandType cmdlet -Name *html*; CommandType Name ModuleName ----------- ---- ---------- Cmdlet ConvertTo-Html Microsoft.PowerShell.Utility PS C:\Users\JohnDoe>

Finally, to list the cmdlets exposed by a specific module, you can use the -Module parameter:

PS C:\Users\JohnDoe> Get-Command -CommandType cmdlet -Module BitsTransfer; CommandType Name ModuleName ----------- ---- ---------- Cmdlet Add-BitsFile BitsTransfer Cmdlet Complete-BitsTransfer BitsTransfer Cmdlet Get-BitsTransfer BitsTransfer Cmdlet Remove-BitsTransfer BitsTransfer Cmdlet Resume-BitsTransfer BitsTransfer Cmdlet Set-BitsTransfer BitsTransfer Cmdlet Start-BitsTransfer BitsTransfer Cmdlet Suspend-BitsTransfer BitsTransfer PS C:\Users\JohnDoe>

As mentioned above, PowerShell can be extended by means of importing modules.   The Import-Module cmdlet loads the required module(s) into the current PowerShell shell (i.e.: into the existing POWERSHELL.EXE process).

The PSModulePath environment variable holds the search path for available modules.  By default, the search path includes the $HOME\Documents\WindowsPowerShell\Modules and $PSHOME\Modules directories, where $HOME is a built-in variable specifying the current user's profile directory and $PSHOME is the root directory of the PowerShell installation.

The Get-Module cmdlet can be used to list the loaded modules or to list the available modules:

PS C:\Users\JohnDoe> Get-Module; ModuleType Version Name ExportedCommands ---------- ------- ---- ---------------- Manifest BitsTransfer {Add-BitsFile, Complete-BitsTransfer, Get-BitsTransfer, Re... Script ise {Get-IseSnippet, Import-IseSnippet, New-IseSnippet} Manifest Microsoft.PowerShell.Management {Add-Computer, Add-Content, Checkpoint-Computer, Clear-Con... Manifest Microsoft.PowerShell.Security {ConvertFrom-SecureString, ConvertTo-SecureString, Get-Acl... Manifest Microsoft.PowerShell.Utility {Add-Member, Add-Type, Clear-Variable, Compare-Object...} Manifest Microsoft.WSMan.Management {Connect-WSMan, Disable-WSManCredSSP, Disconnect-WSMan, En... PS C:\Users\JohnDoe> Get-Module -ListAvailable; Directory: C:\Windows\system32\WindowsPowerShell\v1.0\Modules ModuleType Version Name ExportedCommands ---------- ------- ---- ---------------- Manifest ActiveDirectory {Set-ADOrganizationalUnit, Get-ADDomainControllerPasswordR... Manifest BitsTransfer {Add-BitsFile, Remove-BitsTransfer, Complete-BitsTransfer,... Manifest CimCmdlets {Get-CimAssociatedInstance, Get-CimClass, Get-CimInstance,... Script ISE {New-IseSnippet, Import-IseSnippet, Get-IseSnippet} Manifest Microsoft.PowerShell.Diagnostics {Get-WinEvent, Get-Counter, Import-Counter, Export-Counter... Manifest Microsoft.PowerShell.Host {Start-Transcript, Stop-Transcript} Manifest Microsoft.PowerShell.Management {Add-Content, Clear-Content, Clear-ItemProperty, Join-Path... Manifest Microsoft.PowerShell.Security {Get-Acl, Set-Acl, Get-PfxCertificate, Get-Credential...} Manifest Microsoft.PowerShell.Utility {Format-List, Format-Custom, Format-Table, Format-Wide...} Manifest Microsoft.WSMan.Management {Disable-WSManCredSSP, Enable-WSManCredSSP, Get-WSManCredS... Binary 1.0 PSDesiredStateConfiguration {Set-DscLocalConfigurationManager, Start-DscConfiguration,... Script PSDiagnostics {Disable-PSTrace, Disable-PSWSManCombinedTrace, Disable-WS... Binary PSScheduledJob {New-JobTrigger, Add-JobTrigger, Remove-JobTrigger, Get-Jo... Manifest PSWorkflow {New-PSWorkflowExecutionOption, New-PSWorkflowSession, nwsn} Manifest PSWorkflowUtility Invoke-AsWorkflow Manifest TroubleshootingPack {Get-TroubleshootingPack, Invoke-TroubleshootingPack} PS C:\Users\JohnDoe>

To import a module, simply use the Import-Module cmdlet, specifying the required module using the -Name parameter:

PS C:\Users\JohnDoe> Import-Module -Name PSDiagnostics; PS C:\Users\JohnDoe>

You can also create your own modules to organise and share your procedures, functions and cmdlets.   This will be covered in the section.

The next thing that distinguishes PowerShell is the "pipeline".  The pipeline is essentially an extension of the already familiar behaviour of piping data between commands, where the pipe symbol (|) is used to take the output of one command and pass it to another command as input.    Almost all PowerShell cmdlets accept objects as piped input.  Equally, almost all PowerShell cmdlets generate object-based output.   This behaviour, combined with a number of filtering and manipulation cmdlets makes it possible to perform some very powerful operations from either an interactive shell, or from a PowerShell script.

PowerShell therefore makes it very easy to achieve the goal of most human-computer interactions, that is, get some information, filter out the information that you are not interested in, manipulate the information (e.g.: perform a sort operation) and then either output the information for human consumption (e.g.: in the form of a report), or execute subseqsequent commands based on the information.

We're getting ahead of ourselves here, but let's quickly demonstrate PowerShell's pipeline (we'll explain all of the cmdlets involved later on):

PS C:\Users\JohnDoe> Get-Process | Sort-Object -Property WorkingSet -Descending | Select-Object -First 5 -Property ProcessName, Id, WorkingSet | ConvertTo-Html | Out-File -FilePath c:\temp\cpu.html; PS C:\Users\JohnDoe>

In this example, we get a list of active process objects (Get-Process), we then sort the list by working set size, in descending order ().   We then select the top five processes and retrieve just their process name, process ID and working set sizes ().   Finally, we render the output to an HTML report (ConvertTo-HTML and Out-File).

To perform this operation without PowerShell would require a considerable number of lines of VBScript, Perl or Python code.   PowerShell's pipeline is discussed in more depth in section .