reosoftproductions.com
RODNEY AND ARLYN'S WEB SITE

PowerShell

Windows10 PowerShell

PowerShell Basics

Introduction to PowerShell

Windows PowerShell is a Microsoft .NET Framework-connected environment designed for administrative automation. Windows PowerShell provides a new approach to building commands, composing solutions, and creating graphical user interface-based management tools.

Windows PowerShell enables a system administrator to automate the administration of system resources by the execution of commands either directly or through scripts.

The version of Windows used for this class is Windows Server 2012 R2.

PowerShell is a command line environment.

Why Use PowerShell?

The PowerShell Interface

Windows PowerShell is a 64-bit application. Windows PowerShell (x86) is the 32-bit version of PowerShell.

Right clicking on the Windows PowerShell icon opens a context menu that allows you to execute Windows PowerShell with various options. For example, it is possible to execute PowerShell as an administrator to perform certain elevated tasks.

Windows Integrated Scripting Environment, or ISE, is a 64-bit application that is a GUI that allows for the development of scripts. Windows ISE (x86) is the 32-bit version. A script is a series of PowerShell commands that are linked together through the use of a single file. Commands can be executed sequentially with no user involvement.

Basic PowerShell Syntax

PowerShell has a reputation of being complex. However, this is not true. Microsoft has attempted to make the syntax as uniform as possible. The syntax is a verb-noun cmdlet. To see a list of all the commands that can be used, use Get-Command to get a comprehensive list of every command in the default module.

To get a list of commands that start with Get, use the command Get-Command Get-*.

To obtain a better idea of the verb coverage, you can use the Get-Command cmdlet and pipe the results to the Group-Object cmdlet as shown here:

Get-Command -CommandType cmdlet | Group-Object -Property Verb |
Sort-Object -Property count -Descending

When the previous command is run, the resulting output is displayed in the following list. The command is run on Windows Vista and includes only the default cmdlets; no modules are loaded. As shown in the listing, the verb Get is used the most often by the default cmdlets, followed distantly by Set, New, and Remove.

Count Name                        Group
----- ----                        -----
   46 Get                         {Get-Acl, Get-Alias, Get-AuthenticodeSignatu...
   19 Set                         {Set-Acl, Set-Alias, Set-AuthenticodeSignatu...
   16 New                         {New-Alias, New-Event, New-EventLog, New-Ite...
   14 Remove                      {Remove-Computer, Remove-Event, Remove-Event...
    8 Export                      {Export-Alias, Export-Clixml, Export-Console...
    8 Write                       {Write-Debug, Write-Error, Write-EventLog, W...
    7 Import                      {Import-Alias, Import-Clixml, Import-Counter...
    7 Out                         {Out-Default, Out-File, Out-GridView, Out-Ho...
    6 Add                         {Add-Computer, Add-Content, Add-History, Add...
    6 Start                       {Start-Job, Start-Process, Start-Service, St...
    6 Invoke                      {Invoke-Command, Invoke-Expression, Invoke-H...
    6 Clear                       {Clear-Content, Clear-EventLog, Clear-Histor...
    5 Test                        {Test-ComputerSecureChannel, Test-Connection...
    5 Stop                        {Stop-Computer, Stop-Job, Stop-Process, Stop...
    4 ConvertTo                   {ConvertTo-Csv, ConvertTo-Html, ConvertTo-Se...
    4 Register                    {Register-EngineEvent, Register-ObjectEvent,...
    4 Format                      {Format-Custom, Format-List, Format-Table, F...
    4 Disable                     {Disable-ComputerRestore, Disable-PSBreakpoi...
    4 Enable                      {Enable-ComputerRestore, Enable-PSBreakpoint...
    3 ConvertFrom                 {ConvertFrom-Csv, ConvertFrom-SecureString, ...
    3 Wait                        {Wait-Event, Wait-Job, Wait-Process}
    3 Update                      {Update-FormatData, Update-List, Update-Type...
    3 Select                      {Select-Object, Select-String, Select-Xml}
    3 Rename                      {Rename-Computer, Rename-Item, Rename-ItemPr...
    2 Unregister                  {Unregister-Event, Unregister-PSSessionConfi...
    2 Restart                     {Restart-Computer, Restart-Service}
    2 Move                        {Move-Item, Move-ItemProperty}
    2 Copy                        {Copy-Item, Copy-ItemProperty}
    2 Measure                     {Measure-Command, Measure-Object}
    1 Tee                         {Tee-Object}
    1 Suspend                     {Suspend-Service}
    1 Debug                       {Debug-Process}
    1 Sort                        {Sort-Object}
    1 Show                        {Show-EventLog}
    1 Checkpoint                  {Checkpoint-Computer}
    1 Split                       {Split-Path}
    1 Disconnect                  {Disconnect-WSMan}
    1 Use                         {Use-Transaction}
    1 Pop                         {Pop-Location}
    1 Where                       {Where-Object}
    1 Trace                       {Trace-Command}
    1 Exit                        {Exit-PSSession}
    1 Enter                       {Enter-PSSession}
    1 Undo                        {Undo-Transaction}
    1 Receive                     {Receive-Job}
    1 Read                        {Read-Host}
    1 Compare                     {Compare-Object}
    1 Convert                     {Convert-Path}
    1 Connect                     {Connect-WSMan}
    1 Join                        {Join-Path}
    1 Push                        {Push-Location}
    1 Complete                    {Complete-Transaction}
    1 Limit                       {Limit-EventLog}
    1 Resume                      {Resume-Service}
    1 ForEach                     {ForEach-Object}
    1 Send                        {Send-MailMessage}
    1 Reset                       {Reset-ComputerMachinePassword}
    1 Group                       {Group-Object}
    1 Restore                     {Restore-Computer}
    1 Resolve                     {Resolve-Path}

To clear the screen, use cls.

To get a list of commands that deal with Service, use the command Get-Command *-Service.

Get-Service VSS | Start-Service

Getting Help

Get-Help display help information.

To get help on a specific cmdlet, use Get-Help cmdletname. As an example, you can issue the command Get-Help Get-VM.

If the command is unknown, try using a search engine on the Internet.

Microsoft also has a website dedicated to PowerShell.

The PowerShell Gallery is a repository of third-party code. Note: In order to use the Microsoft PS Gallery as a trusted repository, use the following command:

  Set-PSRepository -Name PSGallery -InstallationPolicy Trusted

Predicting a Command's Behavior

You may find a PowerShell command that may do what you want, but are unsure as to what the consequences would be, this makes it difficult to use. There is a command that shows you what will happen if a command is executed. This is the -whatif argument. As an example:

Start-Service -Name VSS -whatif

This does not execute the command. What it does do is show you messages as if the command was executed.

You can tell PowerShell to ask for confirmation before it attempts to perform the command. This is done through the -confirm argument.

-whatif and -confirm cannot be used on all commands. To return a list of commands that accept the -whatif argument, use:

Get-Command | Where {$_.Definition -Like "*whatIf*"}
Get-Command | Where {$_.Definition -Like "*Confirm*"}

Working with PowerShell Cmdlets

A cmdlet is a small bit of executable code that performs some administrative task such as deleting a file, adding a user, or changing the registry. Cmdlets are named with a verb-noun syntax with strict guidelines for verb naming. An example cmdlet is Get-Process, which returns information about processes running on a machine.

To ensure consistency, the set of verbs that developers can use is restricted through the use of formal guidance (and runtime checking that emits an error if unapproved verbs are used in a cmdlet). That helps to ensure that the "get" verb has the same semantics in Active Directory as in Exchange - and that's the same semantics for Get-Process.

Cmdlet nouns can vary more because they are task-specific. A cmdlet's noun, however, should always be singular, possibly with a prefix to avoid collision (where two product groups produce similarly named cmdlets that do potentially different things). Quest's Active Directory tools use the noun prefix QAD, whereas Microsoft's Active Directory cmdlets use the prefix AD. So, although both cmdlet sets provide a way to get a user in the AD, Quest's tool uses Get-QADuser, whereas Microsoft's cmdlet is Get-AdUser.

To some degree, learning the verbs Windows PowerShell uses for any given task domain is easy - these are standard (Get, New, Remove, and so on). What differs are the nouns, which are in effect the task domain objects. Thus, in Active Directory (AD), you work with users (Get-AdUser), groups (Get-AdGroup), and domains (Get-AdDomain), whereas in Lync Server you work with topology (Enable-CSTopology), analog device (Get-CSAnalogDevice), location policy (Get-CSLocationPolicy), and so on.

Cmdlets can have aliases - shortcut names to simplify typing, particularly at the command prompt. Thus, GPS is an alias for Get-Process. Windows PowerShell comes with some built-in aliases, but you can easily add your own aliases in profile files that run each time you run Windows PowerShell.

Cmdlets can take parameters that tell the cmdlet how to work. The Get-Process cmdlet has a property, -Name, which is used to tell Windows PowerShell the name of the processes you want information about. Cmdlet property names always begin with a hyphen (-) and are separated from the parameter value and other parameters by a space.

Windows PowerShell provides you with parameter value globbing; that is, specifying a parameter value with wildcards to match potentially more than one object. Thus, you could issue the cmdlet Get-Process -Name P*W to get all the processes that begin with a "p" and have a "w" somewhere later in the process name.

Parameter full names, which can get long in some cases, can also be abbreviated. Windows PowerShell lets you use the fewest number of characters necessary to distinguish one parameter name from all the others.

Commonly Used Cmdlets

Get-Process

This command is used to retrieve information about processes.

To see a list of processes and the amount of memory used, use the following command:

Get-Process | Select-Object Name, WS

WS is short for working set.

To see a list of processes and sort by the amount of memory used, use the following command:

Get-Process | Sort-Object WS

To see a list of processes and sort by the amount of memory used in descending order, use the following command:

Get-Process | Sort-Object WS -Descending | Select-Object Name, WS

To see a list of processes and sort by the amount of memory used in descending order and limit the list to the last five entries, use the following command:

Get-Process | Sort-Object WS -Descending | Select-Object Name, WS -Last 5

Get-Service

To get service name, display name and status for a particular service, like VSS, use the following:

Get-Service VSS | Select-Object Name, DisplayName, Status

To get service name, display name and status, format in a list, for a particular service, like VSS, use the following:

Get-Service VSS | Select-Object Name, DisplayName, Status | Format-List

To get service name, display name and status, format in a table, for a particular service, like VSS, use the following:

Get-Service VSS | Select-Object Name, DisplayName, Status | Format-Table

To start a service, like VSS, use the following:

Start-Service VSS

Type

To send the contents of a file to the screen, use

Type C:\Data\readme.txt

Get-Content

To send the contents of a file to the screen, use

Get-Content C:\Data\readme.txt

CLS

To clear the screen, use

CLS

Clear-Host

To clear the screen, use

Clear-Host

Copy-Item

To copy an item, like a file, use:

Copy-Item C:\Data\Readme.txt C:\Scripts

Get-ChildItem

This command is equivalent to the old DOS command dir.

To view the directory entry for a file, use

Get-ChildItem C:\Scripts\Readme.txt

To get a listing for the current directory and the child directories, use the following:

Get-ChildItem -Recurse

Remove-Item

To delete a file, use

Remove-Item C:\Scripts\Readme.txt

Get-History

Display a list of all commands issued during this session, use:

Get-History

Objects and Attributes

PowerShell commands are able to perform and show much more information than what the GUI is able to provide. To select the objects that you want to have returned from a command, use the Select-Object command. For example:

Get-Process | Select-Object *

This will return all of the information associated with a process. There are many more attribute available through PowerShell that are not available in Windows GUI.

The names of columns don't always match up to the names used in PowerShell. For instance, the Windows column named Description is callled DisplayName in the PowerShell command. To examine the services using columns Status, Name, and DisplayName, use:

Get-Services

To use the same command with all the columns, use:

Get-Services | Select-Object *

To use PowerShell to get a list of service dependencies use:

Get-Services | Select-Object Name, Status, ServicesDependedOn

To use PowerShell to get a list of service dependencies in table format use:

Get-Services | Select-Object Name, Status, ServicesDependedOn | Format-Table
Get-Services | Select-Object Name, Status, ServicesDependedOn | FT

To use PowerShell to get a list of service dependencies in list format use:

Get-Services | Select-Object Name, Status, ServicesDependedOn | Format-List
Get-Services | Select-Object Name, Status, ServicesDependedOn | FL

Working with Variables

All variables have a name. That name must start with a '$'. To create a string variable X and set it to 1, use:

$X="1"

To view the contents of a variable, just type the name:

$X

You can also use the following syntax:

Write-Host $X

To concatenate two string variables, use:

$X="1"
$Y="1"
$X + $Y

This returns a string value of "11".

To add to variables, use:

$X=1
$Y=1
$X + $Y

This returns a numerical value of 2.

To perform variable substitution, use the following:

$X=1
$Y=1
Write-Host $X + $Y

This returns the value '1 + 1'.

To perform the math, use:

$X=1
$Y=1
$Z = $X + $Y
Write-Host $Z

This will return the sum of the two values...2.

$X="1"
$Y="1"
[int]$X + [int]$Y

This will treat the two string values as numbers and add them together.

Variables do not span PowerShell sessions.

Array variables

An array is 0-based.

$MyArray = "A", "B", "C", "D"
Write-Host $MyArray
Write-Host $MyArray[3]
$CN = Get-Command

This places each command into an entry in the array.

The followng command will display the number of PowerShell commands available on this machine:

$CN = Get-Command
$CN.count

To build a list of virtual machines in an array:

$VirtualMachine = Get-VM
$VirtualMachine
$VirtualMachine.count

PowerShells Built-In Variable

You can enumerate PowerShell's variables with this command:

  Get-Variable | Format-Table name, value -auto
  Name                          Value
----                          -----
$                             }
?                             True
^                             Get-WmiObject
_
args                          {}
ConfirmPreference             High
ConsoleFileName
DebugPreference               SilentlyContinue
Error                         {}
ErrorActionPreference         Continue
ErrorView                     NormalView
ExecutionContext              System.Management.Automation.EngineIntrinsics
false                         False
FormatEnumerationLimit        4
HOME                          C:\Users\Rodney
Host                          System.Management.Automation.Internal.Host.InternalHost
input                         System.Collections.ArrayList+ArrayListEnumeratorSimple
Matches                       {0}
MaximumAliasCount             4096
MaximumDriveCount             4096
MaximumErrorCount             256
MaximumFunctionCount          4096
MaximumHistoryCount           64
MaximumVariableCount          4096
MyInvocation                  System.Management.Automation.InvocationInfo
NestedPromptLevel             0
null
OutputEncoding                System.Text.ASCIIEncoding
PID                           2956
PROFILE                       C:\Users\Rodney\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
ProgressPreference            Continue
PSBoundParameters             {}
PSCulture                     en-US
PSEmailServer
PSHOME                        C:\Windows\System32\WindowsPowerShell\v1.0
PSSessionApplicationName      wsman
PSSessionConfigurationName    http://schemas.microsoft.com/powershell/Microsoft.PowerShell
PSSessionOption               System.Management.Automation.Remoting.PSSessionOption
PSUICulture                   en-US
PSVersionTable                {CLRVersion, BuildVersion, PSVersion, WSManStackVersion...}
PWD                           C:\Scripts
ReportErrorShowExceptionClass 0
ReportErrorShowInnerException 0
ReportErrorShowSource         1
ReportErrorShowStackTrace     0
ShellId                       Microsoft.PowerShell
StackTrace
this
true                          True
VerbosePreference             SilentlyContinue
WarningPreference             Continue
WhatIfPreference              False

$_. Variable

Constructions such as ... | Where {$_.name -Match "win"} are incredibly useful in PowerShell. Definitions such as: '$_ means in this pipeline', are a bit stuffy. The best way to understand $_ is to work through examples.

First, $_ is a variable or placeholder. Consider the following:

Get-Service | Where-Object {$_.name -Match "win"}

In this example, we are getting the services, where the service name matches 'Win'. $_ saves us repeating Get-Service, or whatever else may be to the left of ... | Where{$_. The .dot command introduces a property.

In the next example, list all the WMI Objects that have the word 'Network' in the name:

Get-WmiObject -List | Where-Object {$_.name -Match 'Network'}

Introduction to PowerShell Modules

Windows PowerShell 2.0 introduced the concept of modules. A module is a package that contains Windows PowerShell cmdlets, aliases, functions, variables, and even providers. In short, a Windows PowerShell module can contain the types of items that you might put into your profile.

In its most basic form, a Windows PowerShell module is a file that contains the same type of code written in a PowerShell script. Many Windows PowerShell modules begin as a PowerShell script and end as modules, with little or no modification other than changing the file extension and location of the file.

Windows PowerShell modules exist in two states: loaded and unloaded. To display a list of all loaded modules, you can use the Get-Module cmdlet without any parameters as shown here.

To display the current default module that is currently loaded, use:

Get-Module

This will return the following:

ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Manifest   3.1.0.0    Microsoft.PowerShell.Management     {Add-Computer, Add-Content, Checkpoint-Computer, Clear-Con...

PowerShell 2.0

If no modules are loaded, nothing is displayed to the Windows PowerShell console. No errors are displayed, and there is no confirmation that the command was actually run as shown here.

PS C:\> Get-ModulePS
C:\>

To get the information for a specific module, use:

Get-Module -Name Microsoft.PowerShell.Management | Format-List

This will return the following:

Name              : Microsoft.PowerShell.Management
Path              : C:\windows\system32\windowspowershell\v1.0\Modules\Microsof
                    t.PowerShell.Management\Microsoft.PowerShell.Management.psd
                    1
Description       :
ModuleType        : Manifest
Version           : 3.1.0.0
NestedModules     : {Microsoft.PowerShell.Commands.Management.dll}
ExportedFunctions :
ExportedCmdlets   : {Add-Computer, Add-Content, Checkpoint-Computer,
                    Clear-Content...}
ExportedVariables :
ExportedAliases   :

To load a module, use the following command:

Import-Module Hyper-V
Import-Module ServerManager

At this point, if the list of modules is listed again, there are additional modules loaded.

When a command is executed, PowerShell attempts to locate modules that contains that command. When found, it loads that module and then executes the command. Older versions of PowerShell do not have this funtionality. Also PowerShell needs to know about the modules before this functionality can be used.

To remove a module, use the following command:

Remove-Module -Name Hyper-V

To list all of the commands that are present in a module, use:

Get-Command -Module Hyper-V

A more complex example:

$VM = Get-VM -Name "Exch3"
$VMHost = Get-VMHost -ComputerName "Hyper-V-2.mgmt.com"
$HostRating = Get-VMHostRating -VM $VM -VMHost $VMHost
$HostRating

Making Sense of Error Messages

Basic PowerShell Scripting

Building PowerShell Scripts

A script is a text file that has a file extension of .ps1. That script contains one or more PowerShell commandlets. Scripts can be stored in any directory. But as a Best Practice, it is best to store scripts in a central repository. A good place to store them is C:\Scripts.

To execute a script from within PowerShell, use:

./scriptname.ps1

Configuring Execution Policies

An execution policy is a security measure used to prevent malicious scripts from executing. Depending on your execution policy, it may prevent your scripts from executing. To view the current execution policy, use:

Get-ExecutionPolicy

The Set-ExecutionPolicy cmdlet changes the user preference for the Windows PowerShell execution policy. To set the current execution policy, use:

PowerShell 2.0

Set-ExecutionPolicy [-ExecutionPolicy] [Restricted|AllSigned|RemoteSigned|Unrestricted]

PowerShell 5.0

Set-ExecutionPolicy [-ExecutionPolicy] [Restricted|AllSigned|RemoteSigned|Unrestricted|Bypass|Undefined]

Note: Some forms of this command may require an elevated, or administrative, level of permission. To resolve this issue, PowerShell must be started from the command line as administrator. This would be evident with a message such as:

Set-ExecutionPolicy : Access to the registry key 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft
.PowerShell' is denied.
At line:1 char:20
+ Set-ExecutionPolicy <<<<  -ExecutionPolicy Unrestricted -Scope LocalMachine
    + CategoryInfo          : NotSpecified: (:) [Set-ExecutionPolicy], UnauthorizedAccessException
    + FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.SetExecutionPolicyComma
   nd

The possible execution policy values are:

The scope of an execution policy defines what the execution policy effects.

To set the current Windows PowerShell process to unrestrictive, use:

Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope Process

To see the scope of the current execution policy, use:

Get-ExecutionPolicy -List

Adding Functions to PowerShell Scripts

We want to create a function to clear the screen and write the string 'Hello World!' on the screen.

#******************************************************************************
#* This is a comment line.                                                    *
#******************************************************************************
Function Display-HelloWorld
{
  Write-Host "The function is now executing."
  Write-Host "Hello World!"
}
CLS
Write-Host "The main script body is now executing."
Display-HelloWorld
Write-Host "The function has completed and the main body is now executing."

The concept and use of returning values in functions is unusual. In Windows PowerShell, the results of each statement are returned as output, even without a statement that contains the Return keyword. The Return keyword really just indicates a lgical exit point. Consider the following example:

$price
return

has the exact same effect as:

return $price

Example Add the number 5 and return the value:

function demoadd 
{
  param ($value)

  "Adding five"
  $value += 5
  return $value
}

C:\PS> $result = demoadd 2
C:\PS>
C:\PS> $result
Adding five
7

The key point to note in the above example is that the "Adding 5" string is not displayed, but is instead assigned to the $result variable and returned along with the number.

Silencing Errors

What are common parameters? These are the common parameters that are associated with a vast number of commandlets. To make an error disappear, use the argument -ErrorAction SilentlyContinue. If you use the option -ErrorAction Stop, the commandlet halts execution when an issue is raised. The -ErrorAction Continue can show an error and continue processing. When -ErrorAction Inquire is used, the user is queried every time an error occurs.

Using Interactive Authentication

Authentication errors can occur if a script is executed by somebody who is not authorized. A script could query the user for creditials when needed:

$Cred = Get-Credential
Get-WmiObject Win32-DiskDrive -ComputerName "mydemo-dc" -Credential $Cred

Using Automatic Authentication

Instead of relying on a user to supply the script a password every time it executes, a secure passworld file could be used.

To read input from the screen and output that information to a secure password file, use:

Read-Host -AsSecureString | ConvertFrom-SecureString | Out-File C:\Scripts\password.txt

This will wait for the user to input a series of keys that will be captured and written to the password.txt file. If the text file is opened, it will contain a cryptic character string that represents password. Now go back to the script used in the last section.

$Username = "MyDemo\Administrator"
$Password = Get-Content C:\Scripts\password.txt | ConvertTo-SecureString

$Cred = New-Object -Typename System.Management.Automation.PSCredential -ArgumentList $Username, $Password

Get-WmiObject Win32-DiskDrive -ComputerName "mydemo-dc" -Credential $Cred

Enhancing PowerShell Scripts

Passing Variables to Functions

#******************************************************************************
#* This is a comment line.                                                    *
#******************************************************************************
Function Get-MyVMs($Server)
{
  Write-Host
  Write-Host "Hyper-V Host Server Name is: "
  Write-Host $Server
  Write-Host "The virtual machines on this server are:"
  Get-VM -ComputerName $Server | Select-Object Name
}

$Server = "Hyper-V-1"
Get-MyVMs $Server

$Server = "Hyper-V-12
Get-MyVMs $Server

Global Variables and Local Variables

Creating Loops

$Cars = @("Ford", "Chevy", "Dodge")
ForEach ($Car in $Cars)
{
  Write-Host $Car
}
Ford
Chevy
Dodge

Let's revisit an earlier script and convert it to a loop:

#******************************************************************************
#* This is a comment line.                                                    *
#******************************************************************************
Function Get-MyVMs($Servers)
{
  Write-Host
  ForEach ($Server in $Servers)
  {
    Write-Host "Hyper-V Host Server Name is: "
    Write-Host $Server
    Write-Host
    Write-Host "The virtual machines on this server are:"
    Get-VM -ComputerName $Server | Select-Object Name
  }
}
#******************************************************************************
#* Main script body starts here.                                              *
#******************************************************************************
  Write-Host
  $Servers = @("Hyper-V-1", "Hyper-V-2", "Hyper-V-3")
  Get-MyVMs $Servers

Working with .NET Integraton

PowerShell is perfectly capable of performing math functions. For instance, on a PowerShell command line, entering 2+2 will yield the result of 4. Subsequently, subtraction, multiplication and division all work. However, when it comes time to use exponents, 2^2 will generate an error. PowerShell can only do basic arithmetic. However, by tapping into .NET, it is possible to extend PowerShell's capabilities.

PowerShell utilizes a hierarchtical structure. It is:

NameSpaces
  Assemblies
    Classes
      Methods

To extend PowerShell, the concept of Classes and Methods must be understood. A class is a unit of functionality. A method is an inidividual component within that class. The Math class will be used here.

To find the squareroot of 64, call the class' static method:

[Math]::SQRT(64)

This will return the value of 8. The [Math] is the name of the class that we wish to use. The next part was the method name. So, the command structure is:

[classname]::methodname()

To determine the methods that are available for a class, use:

[System.Math].GetMethods()
[System.Math].GetMethods() | Select-Object Name
[System.Math].GetMethods() | Select-Object Name -Unique

To view a method that is overloaded with multiple parameter sets, use:

[System.IO.File]::ReadAllText

A constructor is used along with New-Object to actually build a class with some values already defined. A class might have multiple constructors in it to allow for various approaches to building out the class object. So how can we determine what kind of constructors are available? Search for the class on the MSDN website. You can also use the following command:

Get-Constructor -TYPE Net.Sockets.TCPClient

PowerShell 5.0

There is a built-in method applied to all of the classes called New(). It is used to build an object vs. using New_Object. If you do not supply the parenthesis, it will actually display all of the available constructors.

[Net.Sockets.TCPClient]::New()

We can bring this all together by creating an object using a constructor and then making use of one of the methods to perform an action. For this example, I will make use of the System.DateTime class to create a class and then make use of the method available in the class.

#******************************************************************************
#* Create the object using a constructor with a Year, Month and Day           *
#* parameter.                                                                 *
#******************************************************************************
$DateTime = New-Object System.DateTime -ArgumentList 2015, 10, 10

#******************************************************************************
#* Display the object.                                                        *
#******************************************************************************
$DateTime 

#******************************************************************************
#* View all of the properties.                                                *
#******************************************************************************
$DateTime | Select-Object -Property *

#******************************************************************************
#* Use a method to convert the DateTime to a FileTime type.                   *
#******************************************************************************
$DateTime.ToFileTime()

#******************************************************************************
#* Add seven days to the currently defined Date.                              *
#******************************************************************************
$DateTime.AddDays(7)

To determine the version of .NET that you are using using the following commands:

PowerShell 1.0

[System.Environment]::Version

PowerShell 2.0

$PSVersionTable.CLRVersion

Building Stand-Alone Functions

It is possible to take a function that you have written and make it available to other scripts. This is done through the creation of a module. This will extend PowerShell's functionality.

A module can live anywhere. However, by putting modules in one of two predefined locations, Windows PowerShell is able to import the module more easily. These locations are stored in the $env:PSModulePath environment variable, which can be changed to include additional locations. By default, $env:PSModulePath includes locations at $psHome\Modules and $env:UserProfile\Documents\WindowsPowerShell\Modules.

By default, the modules are located and search in the following order:

C:\Users\username\Documents\WindowsPowerShell\Modules
C:\Program Files\WindowsPowerShell\Modules
C:\Windows\System32\WindowsPowerShell\v1.0\Modules

Create a directory for your module. That folder name must use the same name as the module. The create a text file in that directory with the same name. The file extension must be .psm1. A module can contain one or more functions.

Function Test-Code
{
  Write-Host
  Write-Host "The function works!"
  Write-Host
}

Export-ModuleMember -Function 'Test-Code'

Once the text file is created and saved, the module would need to be imported:

Import-Module MyModule

To get a list of commandlets that are included in a module, use:

Get-Command -Module MyModule

To obtain a listing of all modules that are available on the system but are not loaded into the Windows PowerShell console, you can use the Get-Module cmdlet with the -ListAvailable parameter as shown here.

Get-Module -ListAvailable
Import-Module Hyper-V
Get-Module
Get-Command -Module Hyper-V

Interacting with Active Directory

Querying Active Directory from PowerShell

Creating Active Directory User Accounts with PowerShell

Modifying Active Directory User Accounts with PowerShell

Working with Active Directory Groups from Powershell

Automating PowerShell Scripts

Making Scripts Run Automatically

Let's say there is a Windows service that is either not starting or shutting down unexpectedly. You need to be notified when this occurs. This cal be done with a script that execute periodically that checks the status of that service.

$VSS = Get-Service VSS
$VSS.Status
If ($VSS.Status -EQ 'Stopped')
{
  Start-Service VSS
  #****************************************************************************
  #* We need a delay here.  The -S signifies 'seconds' and the 10 indicates   *
  #* 10 units.  so the -S 10 is '10 seconds'.  We are doing this to give the  *
  #* service ample time to start.                                             *
  #****************************************************************************
  Start-Sleep -S 10
  Get-Service Vss
}

Now that we have a script that starts the service if it is stopped, the next step is to use the Windows Task Scheduler. To set this up, on the Action menu (right side), click on Create Task... This will open the Create Basic Task Wizard. Enter a name and description. Tell the task to execute daily at any particular time and to recur daily. For the Action, tell the task to start a program. The Program/script is set to powershell.exe. In the Arguments text box, type -File c:\Scripts\script.ps1. Click next to the Finish screen. Click the Finish button.

Sending E-Mail Messages from PowerShell Scripts

The first thing to do is to create a password file. Chances are, this script will need to generate an email and will need to run in an automated fashion. Therefore, a password file is needed.

Read-Host -AsSecureString | ConvertFrom-SecureString | Out-File C:\Scripts\password.txt

Next, build a script:

$Username = "servername\Administrator"
$Password = Get-Content C:\Scripts\password.txt | ConvertTo-SecureString
$Cred = New-Object -Typename System.Management.Automation.PSCredential -ArgumentList $Username, $Password

Send-MailMessage -To [email protected] -From [email protected] -Subject "Test Message" -Body "This message was generated by PowerShell." -Credential $Cred -SMTPServer Exch1.mail.com

Generating Meaningful E-Mail Messages

The script used in Lesson 6-1 and Lesson 6-2 can be combined to create a script that is both useful and meaningful.

$EmailTo = "[email protected]"
$EmailFrom = "[email protected]"
$Subject = "VSS Service Health"
$SMTPServer = "Exch1.mail.com"
$Username = "servername\Administrator"
$Password = Get-Content C:\Scripts\password.txt | ConvertTo-SecureString
$Cred = New-Object -Typename System.Management.Automation.PSCredential -ArgumentList $Username, $Password

Function Send-Notice
{
 Send-MailMessage -To $EmailTo -From $EmailFrom -Subject $Subject -Body $Body -Credential $Cred -SMTPServer $SMTPServer
}

Function Check-ServiceStatus
{
  $VSS = Get-Service VSS
  $VSS.Status
  If ($VSS.Status -EQ 'Stopped')
  {
    $Body = "The VSS Service has stopped."
    Send-Notice $Body
    Start-Service VSS
    #**************************************************************************
    #* We need a delay here.  The -S signifies 'seconds' and the 10 indicates *
    #* 10 units.  So the -S 10 is '10 seconds'.  We are doing this to give    *
    #* the service ample time to start.                                       *
    #**************************************************************************
    Start-Sleep -S 10
  }

  $VSS = Get-Service VSS
  If ($VSS.Status -EQ 'Running')
  {
    $Body = "The VSS Service is running."
    Send-Notice $Body
  }
}

Check-ServiceStatus

Best Practices for PowerShell Scripting

PowerShell best practices are vague and very individual. There are no rigid set of best practices available.

#******************************************************************************
#* We need a delay here.  The -S signifies 'seconds' and the 10 indicates     *
#* 10 units.  So the -S 10 is '10 seconds'.  We are doing this to give the    *
#* service ample time to start.                                               *
#******************************************************************************

# Declare variables

$EmailTo = "[email protected]"
$EmailFrom = "[email protected]"
$Subject = "VSS Service Health"
$SMTPServer = "Exch1.mail.com"
$Username = "servername\Administrator"
$Password = Get-Content C:\Scripts\password.txt | ConvertTo-SecureString
$Cred = New-Object -Typename System.Management.Automation.PSCredential -ArgumentList $Username, $Password

#******************************************************************************
#* This function receives the $Body variable, which contains the message      *
#* body.  It then sends an E-mail message to the recipient defined by the     *
#* $EmailTo variable.                                                         *
#******************************************************************************
Function Send-Notice
{
  Send-MailMessage -To $EmailTo -From $EmailFrom -Subject $Subject -Body $Body -Credential $Cred -SMTPServer $SMTPServer
}

#******************************************************************************
#* This function checks to see if the VSS service is running.                 *
#******************************************************************************
Function Check-ServiceStatus
{
  $VSS = Get-Service VSS
  $VSS.Status
  If ($VSS.Status -EQ 'Stopped')
  {
    $Body = "The VSS Service has stopped."
    Send-Notice $Body
    Start-Service VSS
    #**************************************************************************
    #* We need a delay here.  The -S signifies 'seconds' and the 10 indicates *
    #* 10 units.  so the -S 10 is '10 seconds'.  We are doing this to give    *
    #* the service ample time to start.                                       *
    #**************************************************************************
    Start-Sleep -S 10
  }

  $VSS = Get-Service VSS
  If ($VSS.Status -EQ 'Running')
  {
    $Body = "The VSS Service is running."
    Send-Notice $Body
  }
}

#******************************************************************************
#* Script body.                                                               *
#******************************************************************************
Check-ServiceStatus

Using PowerShell as a Reporting Tool

Basic PowerShell Reporting

Creating CSV Files

Creating Text Files

Creating HTML Files

Adding Color and Formatting to HTML Reports

Creating Graphical Reports

Creating Simple Charts Using PowerShell

Changing Chart Types

Importing Data Into PowerShell Charts

Using PowerShell Remoting

Introduction to PowerShell Remoting

PowerShell is Windows preferred method for server management. Remote management allows someone to manage each of those servers without having to phyically log on to each of those servers. It is possible to execute a command once on a group of servers.

The following command returns the name of the host computer:

Get-VMHost

There are three methods to redirect a command to another server. The first method uses the -ComputerName parameter. However, not every cmdlet support the use of the -ComputerName parameter. The next method is something called the invoke command. The invoke command can be used to send multiple commands to a single server. The third method is something called a PS Session. PS Session is essentially a remote PowerShell session. The entire console remotes itself to another machine. Anything typed into the console is executed on that remote machine.

Establishing Remote Sessions

In order to establish a session on a remote system, it is necessary to enable this functionality on the remote system. To do this, log on to the remote Windows machine, open up PowerShell and execute the following command:

Enable-PSRemoting -Force

Let's get back to the task at hand, establishing a remote session. Back on your system, open up PowerShell and drop down to the root folder:

cd \

Next, generate a list of machines. In this example, we are using virtual machines, so use:

Get-VM

Here are the next commands:

$Cred=Get-Credential

This opens a dialog to enter in a user name and password.

  User Name:  mgmt\Administrator
  Password: **********

The user name and password are now in a variable called $Cred. Next:

Enter-PSSession -ComputerName Hyper-V-3 -Credential $Cred

If all goes well, your prompt will change and you will now be connected to your remote system. You are now within a console on that machine. To get out of your remote session, use:

Exit-PSSession

You are now back to your local machine.

If there are any issues that prevent a connection to a remote machine, the information on this website proved to be extremely helpful in fixing the problem.

Tip: Enable and Use Remote Commands in Windows PowerShell

Running Cmdlets on Remote Systems

Compiling Data from Remote Servers

There is a trick to using variables in a remote session and making that information available in local sessions. It is not hard...but there is a trick to it.

Consider the following script:

$Session = New-PSSession -ComputerName Hyper-V-3
Invoke-Command -Session $Session -ScriptBlock
{
  $myVar = Get-VM
  Write-Host "The script is currently executing on a remote session."
  $myVar | Select-Object Name
  Exit-PSSession
}
Write-Host "The script is not curretly executing a remote session."
$myVar | Select-Object Name

The last line will NOT display a value for $myVar because it is out of scope. The following code will fix the issue.

$Session = New-PSSession -ComputerName Hyper-V-3
Invoke-Command -Session $Session -ScriptBlock
{
  $myVar = Get-VM
  Write-Host "The script is currently executing on a remote session."
  $myVar | Select-Object Name
  Exit-PSSession
}
$LocalResult = Invoke-Command -Session $Session - ScriptBlock {$myVar}
Exit-PSSession
Write-Host "The script is not curretly executing a remote session."
$LocalResult | Select-Object Name

Building Your Own PowerShell GUI

Creating Basic GUIs

Adding Text Boxes

Working with Buttons

Working with Drop-Down Lists

How to start the Windows PowerShell 2.0 Engine

When you start Windows PowerShell the newest version starts by default. To start Windows PowerShell with the Windows PowerShell 2.0 Engine, use the Version parameter of PowerShell.exe. You can run the command at any command prompt, including Windows PowerShell and Cmd.exe.

PowerShell.exe -version 2

Windows API

Commands

Cmdlet Alias Module
Add-Content ac Microsoft.PowerShell.Management
Clear-Host
ConvertFrom-SecureString Microsoft.PowerShell.Security
ConvertTo-SecureString Microsoft.PowerShell.Security
Enter-PSSession etsn Microsoft.PowerShell.Core
Exit-PSSession exsn Microsoft.PowerShell.Core
Export-ModuleMember Microsoft.PowerShell.Core
Format-Table ft Microsoft.PowerShell.Utility
Get-ChildItem ls, dir, gci Microsoft.PowerShell.Management
Get-Credential   Microsoft.PowerShell.Security
Get-Date Microsoft.PowerShell.Utility
Get-ExecutionPolicy   Microsoft.PowerShell.Security
Get-Module gmo Microsoft.PowerShell.Core
Get-PSDrive gdr Microsoft.PowerShell.Management
Get-PSProvider   Microsoft.PowerShell.Management
Get-Service gsv Microsoft.PowerShell.Management
Get-Variable
Get-VM   Hyper-V
Get-WmiObject gwmi Microsoft.PowerShell.Management
Import-Module ipmo Microsoft.PowerShell.Core
Invoke-Command icm Microsoft.PowerShell.Core
New-Object
Read-Host Microsoft.PowerShell.Utility
Remove-Module rmo Microsoft.PowerShell.Core
Select-Object select Microsoft.PowerShell.Utility
Set-ExecutionPolicy   Microsoft.PowerShell.Security
Set-PSRepository   PowerShellGet
Set-Variable set, sv Microsoft.PowerShell.Utility
Start-Service sasv Microsoft.PowerShell.Management
Start-Sleep sleep Microsoft.PowerShell.Utility
Stop-Service spsv Microsoft.PowerShell.Management
Test-Connection Microsoft.PowerShell.Management
Write-Host