PowerShell Logo Small

about_Classes



This is the built-in help made by Microsoft for the document 'about_Classes', in PowerShell version 5 - as retrieved from Windows version 'Microsoft Windows Server 2012 R2 Standard' PowerShell help files on 2016-06-24.

For PowerShell version 3 and up, where you have Update-Help, this command was run just before creating the web pages from the help files.

Search powershellhelp.space

about_Classes
TOPIC
about_Classes

SHORT DESCRIPTION
Describes how you can use classes to develop in Windows PowerShell

LONG DESCRIPTION
Starting in Windows PowerShell 5.0, Windows PowerShell adds language
for defining classes and other user-defined types, by using formal syntax
and semantics that are similar to other object-oriented programming
languages. The goal is to enable developers and IT professionals to
embrace Windows PowerShell for a wider range of use cases, simplify
development of Windows PowerShell artifacts--such as Windows PowerShell
Desired State Configuration (DSC) resources--and accelerate coverage
of management surfaces.


SUPPORTED SCENARIOS
-- Define DSC resources and their associated types by using the
Windows PowerShell language.
-- Define custom types in Windows PowerShell by using familiar object-
oriented programming constructs, such as classes, properties, methods,
inheritance, etc.
-- Debug types by using the Windows PowerShell language.
-- Generate and handle exceptions by using formal mechanisms, and at the
right level.


DEFINE DSC RESOURCES WITH CLASSES
Apart from syntax changes, the major differences between a class-defined
DSC resource and a cmdlet DSC resource provider are the following.

-- A MOF file is not required.
-- A DSCResource subfolder in the module folder is not required.
-- A Windows PowerShell module file can contain multiple DSC resource
classes.

The following is an example of a class-defined DSC resource provider;
this is saved as a module, MyDSCResource.psm1. Note that you must always
include a key property in a class-defined DSC resource provider.

enum Ensure
{
Absent
Present
}

<#
This resource manages the file in a specific path.
[DscResource()] indicates the class is a DSC resource
#>

[DscResource()]
class FileResource
{
<#
This property is the fully qualified path to the file that is
expected to be present or absent.

The [DscProperty(Key)] attribute indicates the property is a
key and its value uniquely identifies a resource instance.
Defining this attribute also means the property is required
and DSC will ensure a value is set before calling the resource.

A DSC resource must define at least one key property.
#>
[DscProperty(Key)]
[string]$Path

<#
This property indicates if the settings should be present or absent
on the system. For present, the resource ensures the file pointed
to by $Path exists. For absent, it ensures the file point to by
$Path does not exist.

The [DscProperty(Mandatory)] attribute indicates the property is
required and DSC will guarantee it is set.

If Mandatory is not specified or if it is defined as
Mandatory=$false, the value is not guaranteed to be set when DSC
calls the resource. This is appropriate for optional properties.
#>
[DscProperty(Mandatory)]
[Ensure] $Ensure

<#
This property defines the fully qualified path to a file that will
be placed on the system if $Ensure = Present and $Path does not
exist.

NOTE: This property is required because [DscProperty(Mandatory)] is
set.
#>
[DscProperty(Mandatory)]
[string] $SourcePath

<#
This property reports the file's create timestamp.

[DscProperty(NotConfigurable)] attribute indicates the property is
not configurable in DSC configuration. Properties marked this way
are populated by the Get() method to report additional details
about the resource when it is present.

#>
[DscProperty(NotConfigurable)]
[Nullable[datetime]] $CreationTime

<#
This method is equivalent of the Set-TargetResource script function.
It sets the resource to the desired state.
#>
[void] Set()
{
$fileExists = $this.TestFilePath($this.Path)
if($this.ensure -eq [Ensure]::Present)
{
if(-not $fileExists)
{


$this.CopyFile()
}
}
else
{
if($fileExists)
{
Write-Verbose -Message "Deleting the file $($this.Path)"
Remove-Item -LiteralPath $this.Path -Force
}
}
}

<#

This method is equivalent of the Test-TargetResource script function.
It should return True or False, showing whether the resource
is in a desired state.
#>
[bool] Test()
{
$present = $this.TestFilePath($this.Path)

if($this.Ensure -eq [Ensure]::Present)
{
return $present
}
else
{
return -not $present
}
}

<#
This method is equivalent of the Get-TargetResource script function.
The implementation should use the keys to find appropriate resources.
This method returns an instance of this class with the updated key
properties.
#>
[FileResource] Get()
{
$present = $this.TestFilePath($this.Path)

if ($present)
{
$file = Get-ChildItem -LiteralPath $this.Path
$this.CreationTime = $file.CreationTime
$this.Ensure = [Ensure]::Present
}
else
{
$this.CreationTime = $null
$this.Ensure = [Ensure]::Absent
}
return $this
}

<#
Helper method to check if the file exists and it is correct file
#>
[bool] TestFilePath([string] $location)
{
$present = $true

$item = Get-ChildItem -LiteralPath $location -ea Ignore
if ($item -eq $null)
{
$present = $false
}
elseif( $item.PSProvider.Name -ne "FileSystem")
{
throw "Path $($location) is not a file path."
}
elseif($item.PSIsContainer)
{
throw "Path $($location) is a directory path."
}
return $present
}

<#
Helper method to copy file from source to path
#>
[void] CopyFile()
{
if(-not $this.TestFilePath($this.SourcePath))
{
throw "SourcePath $($this.SourcePath) is not found."
}

[System.IO.FileInfo] $destFileInfo = new-object System.IO.FileInfo($this.Path)
if (-not $destFileInfo.Directory.Exists)
{
Write-Verbose -Message "Creating directory $($destFileInfo.Directory.FullName)"

#use CreateDirectory instead of New-Item to avoid code
# to handle the non-terminating error
[System.IO.Directory]::CreateDirectory($destFileInfo.Directory.FullName)
}

if(Test-Path -LiteralPath $this.Path -PathType Container)
{
throw "Path $($this.Path) is a directory path"
}

Write-Verbose -Message "Copying $($this.SourcePath) to $($this.Path)"

#DSC engine catches and reports any error that occurs
Copy-Item -LiteralPath $this.SourcePath -Destination $this.Path -Force
}
}
# This module defines a class for a DSC "FileResource" provider.


enum Ensure
{
Absent
Present
}




<# This resource manages the file in a specific path.
[DscResource()] indicates the class is a DSC resource
#>

[DscResource()]
class FileResource{

<# This is a key property
[DscResourceKey()] also means the property is required.
It is guaranteed to be set, other properties may not
be set if the configuration did not specify values.
#>
[DscResourceKey()]
[string]$Path

<#
[DscResourceMandatory()] means the property is required.
It is guaranteed to be set, other properties may not be set
if the configuration did not specify values.
#>
[DscResourceMandatory()]
[Ensure] $Ensure

<#
[DscResourceMandatory()] means the property is required.
#>
[DscResourceMandatory()]
[string] $SourcePath

[DscResource

<#
This method replaces the Set-TargetResource DSC script function.
It sets the resource to the desired state.
#>
[void] Set()
{
$fileExists = Test-Path -path $this.Path -PathType Leaf
if($this.ensure -eq [Ensure]::Present)
{
if(-not $fileExists)
{
$this.CopyFile()
}
}
else
{
if($fileExists)
{
Write-Verbose -Message "Deleting the file $this.Path"
Remove-Item -LiteralPath $this.Path
}
}
}


<#

This method replaces the Test-TargetResource function.
It should return True or False, showing whether the resource
is in a desired state.
#>

[bool] Test()
{
if(Test-Path -path $this.Path -PathType Container)
{
throw "Path '$this.Path' is a directory path."
}

$fileExists = Test-Path -path $this.Path -PathType Leaf

if($this.ensure -eq [Ensure]::Present)
{
return $fileExists
}

return (-not $fileExists)
}

<#
This method replaces the Get-TargetResource function.
The implementation should use the keys to find appropriate resources.
This method returns an instance of this class with the updated key properties.
#>

[FileResource] Get()
{
$file = Get-item $this.Path
return $this
}

<#
Helper method to copy file from source to path.
Because this resource provider run under system,
Only the Administrators and system have full
access to the new created directory and file
#>
CopyFile()
{
if(Test-Path -path $this.SourcePath -PathType Container)
{
throw "SourcePath '$this.SourcePath' is a directory path"
}

if( -not (Test-Path -path $this.SourcePath -PathType Leaf))
{
throw "SourcePath '$this.SourcePath' is not found."
}

[System.IO.FileInfo] $destFileInfo = new-object System.IO.FileInfo($this.Path)
if (-not $destFileInfo.Directory.Exists)
{
Write-Verbose -Message "Creating directory $($destFileInfo.Directory.FullName)"

#use CreateDirectory instead of New-Item to avoid lines
# to handle the non-terminating error
[System.IO.Directory]::CreateDirectory($destFileInfo.Directory.FullName)
}

if(Test-Path -path $this.Path -PathType Container)
{
throw "Path '$this.Path' is a directory path"
}

Write-Verbose -Message "Copying $this.SourcePath to $this.Path"

#DSC engine catches and reports any error that occurs
Copy-Item -Path $this.SourcePath -Destination $this.Path -Force
}
}

After creating the class-defined DSC resource provider, and saving it as a
module, create a module manifest for the module. To make a class-based resource
available to the DSC engine, you must include a DscResourcesToExport statement
in the manifest file that instructs the module to export the resource. In this
example, the following module manifest is saved as MyDscResource.psd1.

@{

# Script module or binary module file associated with this manifest.
RootModule = 'MyDscResource.psm1'

DscResourcesToExport = 'FileResource'

# Version number of this module.
ModuleVersion = '1.0'

# ID used to uniquely identify this module
GUID = '81624038-5e71-40f8-8905-b1a87afe22d7'

# Author of this module
Author = 'Microsoft Corporation'

# Company or vendor of this module
CompanyName = 'Microsoft Corporation'

# Copyright statement for this module
Copyright = '(c) 2014 Microsoft. All rights reserved.'

# Description of the functionality provided by this module
# Description = ''

# Minimum version of the Windows PowerShell engine required by this module
PowerShellVersion = '5.0'

# Name of the Windows PowerShell host required by this module
# PowerShellHostName = ''

}

Deploy the new DSC resource provider by creating a MyDscResource folder for
it in $pshome\Modules or $env:SystemDrive\Program Files\WindowsPowerShell\Modules.
You do not need to create a DSCResource subfolder. Copy the module and module
manifest files (MyDscResource.psm1 and MyDscResource.psd1) to the MyDscResource
folder.

From this point, you create and run a configuration script as you would with
any DSC resource. The following is a configuration that references the
MyDSCResource module. Save this as a script, MyResource.ps1.


INHERITANCE IN WINDOWS POWERSHELL CLASSES

Declare base classes for Windows PowerShell classes
You can declare a Windows PowerShell class as a base type for another Windows
PowerShell class, as shown in the following example, in which "fruit" is a
base type for "apple".

class fruit
{
[int]sold() {return 100500}
}

class apple : fruit {}
[apple]::new().sold() # return 100500

Declare implemented interfaces for Windows PowerShell classes
You can declare implemented interfaces after base types, or immediately
after a colon (:) if there is no base type specified. Separate all type
names by using commas. This is similar to C# syntax.

class MyComparable : system.IComparable
{
[int] CompareTo([object] $obj)
{
return 0;
}
}

class MyComparableTest : test, system.IComparable
{
[int] CompareTo([object] $obj)
{
return 0;
}
}

Call base class constructors
To call a base class constructor from a subclass, add the "base" keyword,
as shown in the following example.

class A {
[int]$a
A([int]$a)
{
$this.a = $a
}
}

class B : A
{
B() : base(103) {}
}

[B]::new().a # return 103

If a base class has a default constructor (that is, no parameters),
you can omit an explicit constructor call, as shown.
class C : B
{
C([int]$c) {}
}

Call base class methods
You can override existing methods in subclasses. To do this, declare
methods by using the same name and signature.

class baseClass
{
[int]days() {return 100500}
}
class childClass1 : baseClass
{
[int]days () {return 200600}
}

[childClass1]::new().days() # return 200600

To call base class methods from overridden implementations, cast to the
base class ([baseclass]$this) on invocation.

class childClass2 : baseClass
{
[int]days()
{
return 3 * ([baseClass]$this).days()
}
}

[childClass2]::new().days() # return 301500

All Windows PowerShell methods are virtual. You can hide non-virtual .NET
methods in a subclass by using the same syntax as you do for an override:
declare methods with same name and signature.

class MyIntList : system.collections.generic.list[int]
{
# Add is final in system.collections.generic.list
[void] Add([int]$arg)
{
([system.collections.generic.list[int]]$this).Add($arg * 2)
}
}

$list = [MyIntList]::new()
$list.Add(100)
$list[0] # return 200

Current limitations with inheritance
The following are known issues with class inheritance:

-- At this time, there is no syntax to declare interfaces in Windows PowerShell.


CONFIGURATION TEST
After saving the class and manifest files in the folder structure as described
earlier, you can create a configuration that uses the new resource. For
information about how to run a DSC configuration, see Get Started with Windows
PowerShell Desired State Configuration (http://technet.microsoft.com/library/dn249918.aspx).
The following configuration will check to see whether the file at c:\test\test.txt
exists, and, if not, copies the file from c:\test.txt (you should create c:\test.txt
before you run the configuration).

Configuration Test
{
Import-DSCResource -module MyDscResource
FileResource file
{
Path = "C:\test\test.txt"
SourcePath = "C:\test.txt"
Ensure = "Present"
}
}
Test
Start-DscConfiguration -Wait -Force Test


Run this as you would any DSC configuration script. To start the configuration,
in an elevated Windows PowerShell console, run the following.

PS C:\test> .\MyResource.ps1

DEFINING CUSTOM TYPES IN WINDOWS POWERSHELL
Windows PowerShell 5.0 introduces the following language elements.

Class keyword
Defines a new class. This is a true .NET Framework type.
Class members are public.
class MyClass
{
}

Enum keyword and enumerations
Support for the enum keyword has been added; this is a breaking change.
The enum delimiter is currently a newline. A workaround for those who
are already using enum is to insert an ampersand (&) before the word.
Current limitations: you cannot define an enumerator in terms of itself,
but you can initialize enum in terms of another enum, as shown in the
following example. The base type cannot currently be specified; it is always
[int].
enum Color2
{
Yellow = [Color]::Blue
}
An enumerator value must be a parse time constant; you cannot set it to
the result of an invoked command.
enum MyEnum
{
Enum1
Enum2
Enum3 = 42
Enum4 = [int]::MaxValue
}
Enums support arithmetic operations, as shown in the following example.
enum SomeEnum { Max = 42 }
enum OtherEnum { Max = [SomeEnum]::Max + 1 }

Hidden keyword
The Hidden keyword, new in Windows PowerShell 5.0, hides class members
from default Get-Member results. Specify the hidden property as shown
in the following line:
hidden [type] $classmember = <value>

Hidden members are not displayed by using tab completion or IntelliSense,
unless the completion occurs in the class that defines the hidden member.

A new attribute, System.Management.Automation.HiddenAttribute, has been
added, so that C# code can have the same semantics within Windows PowerShell.

For more information about Hidden, see about_Hidden.

Import-DscResource
Import-DscResource is now a true dynamic keyword. Windows PowerShell
parses the specified module’s root module, searching for classes that
contain the DscResource attribute.

Properties
A new field, ImplementingAssembly, has been added to ModuleInfo. It
is set to the dynamic assembly created for a script module if the script
defines classes, or the loaded assembly for binary modules. It is not
set when ModuleType = Manifest.

Reflection on the ImplementingAssembly field discovers resources in a
module. This means you can discover resources written in either
Windows PowerShell or other managed languages.

Fields with initializers:
[int] $i = 5
Static is supported; it works like an attribute, as do the type constraints,
so it can be specified in any order.
static [int] $count = 0
A type is optional.
$s = "hello"

All members are public. Properties require either a newline or semicolon.
If no object type is specified, the property type is “object.”

Constructors and instantiation
Windows PowerShell classes can have constructors; they have the same
name as their class. Constructors can be overloaded. Static constructors
are supported. Properties with initialization expressions are initialized
before running any code in a constructor. Static properties are initialized
before the body of a static constructor, and instance properties are
initialized before the body of the non-static constructor. Currently, there
is no syntax for calling a constructor from another constructor (like the
C# syntax ": this()"). The workaround is to define a common Init method.

The following are ways of instantiating classes.
Instantiating by using the default constructor. Note that New-Object is not
supported in this release.
$a = [MyClass]::new()

Calling a constructor with a parameter
$b = [MyClass]::new(42)

Passing an array to a constructor with multiple parameters
$c = [MyClass]::new(@(42,43,44), "Hello")

For this release, the type name is only visible lexically,
meaning it is not visible outside of the module or script that defines the
class. Functions can return instances of a class defined in Windows
PowerShell, and instances work well outside of the module or script.

Get-Member -Static lists constructors, so you can view overloads like
any other method. The performance of this syntax is also considerably
faster than New-Object.

The pseudo-static method named new works with .Net types, as shown in
the following example.

[hashtable]::new()

You can now see constructor overloads with Get-Member, or as shown in
this example:

PS> [hashtable]::new
OverloadDefinitions
-------------------
hashtable new()
hashtable new(int capacity)
hashtable new(int capacity, float loadFactor)

Methods
A Windows PowerShell class method is implemented as a ScriptBlock that
has only an end block. All methods are public. The following shows an
example of defining a method named DoSomething.
class MyClass
{
DoSomething($x)
{
$this._doSomething($x) # method syntax
}
private _doSomething($a) {}
}

Method invocation:
$b = [MyClass]::new()
$b.DoSomething(42)

Overloaded methods--that is, those that are named the same as an
existing method, but differentiated by their specified values--are also supported.

Invocation
See "Method invocation" in this list.

Attributes
Three new attributes, DscResource, DscResourceKey, and DscResourceMandatory,
have been added.

Return types
Return type is a contract; the return value is converted to the expected
type. If no return type is specified, the return type is void. There
is no streaming of objects; objects cannot be written to the pipeline
either intentionally or by accident.

Lexical scoping of variables
The following shows an example of how lexical scoping works in this
release.
$d = 42 # Script scope

function bar
{
$d = 0 # Function scope
[MyClass]::DoSomething()
}

class MyClass
{
static [object] DoSomething()
{
return $d # error, not found dynamically
return $script:d # no error

$d = $script:d
return $d # no error, found lexically
}
}

$v = bar
$v -eq $d # true


EXAMPLE
The following example creates several new, custom classes to implement
an HTML dynamic stylesheet language (DSL). Then, the example adds helper
functions to create specific element types as part of the element class,
such as heading styles and tables, because types cannot be used outside
the scope of a module.

# Classes that define the structure of the document
#
class Html
{
[string] $docType
[HtmlHead] $Head
[Element[]] $Body

[string] Render()
{
$text = "<html>`n<head>`n"
$text += $Head
$text += "`n</head>`n<body>`n"
$text += $Body -join "`n" # Render all of the body elements
$text += "</body>`n</html>"
return $text
}
[string] ToString() { return $this.Render() }
}

class HtmlHead
{
$Title
$Base
$Link
$Style
$Meta
$Script
[string] Render() { return "<title>$Title</title>" }
[string] ToString() { return $this.Render() }
}

class Element
{
[string] $Tag
[string] $Text
[hashtable] $Attributes
[string] Render() {
$attributesText= ""
if ($Attributes)
{
foreach ($attr in $Attributes.Keys)
{
$attributesText = " $attr=`"$($Attributes[$attr])`""
}
}

return "<${tag}${attributesText}>$text</$tag>`n"
}
[string] ToString() { return $this.Render() }
}

#
# Helper functions for creating specific element types on top of the classes.
# These are required because types aren’t visible outside of the module.
#
function H1 { [Element] @{ Tag = "H1" ; Text = $args.foreach{$_} -join " " }}
function H2 { [Element] @{ Tag = "H2" ; Text = $args.foreach{$_} -join " " }}
function H3 { [Element] @{ Tag = "H3" ; Text = $args.foreach{$_} -join " " }}
function P { [Element] @{ Tag = "P" ; Text = $args.foreach{$_} -join " " }}
function B { [Element] @{ Tag = "B" ; Text = $args.foreach{$_} -join " " }}
function I { [Element] @{ Tag = "I" ; Text = $args.foreach{$_} -join " " }}
function HREF
{
param (
$Name,
$Link
)

return [Element] @{
Tag = "A"
Attributes = @{ HREF = $link }
Text = $name
}
}
function Table
{
param (
[Parameter(Mandatory)]
[object[]]
$Data,
[Parameter()]
[string[]]
$Properties = "*",
[Parameter()]
[hashtable]
$Attributes = @{ border=2; cellpadding=2; cellspacing=2 }
)

$bodyText = ""
# Add the header tags
$bodyText += $Properties.foreach{TH $_}
# Add the rows
$bodyText += foreach ($row in $Data)
{
TR (-join $Properties.Foreach{ TD ($row.$_) } )
}


$table = [Element] @{
Tag = "Table"
Attributes = $Attributes
Text = $bodyText
}
$table
}
function TH { ([Element] @{ Tag = "TH" ; Text = $args.foreach{$_} -join " " }) }
function TR { ([Element] @{ Tag = "TR" ; Text = $args.foreach{$_} -join " " }) }
function TD { ([Element] @{ Tag = "TD" ; Text = $args.foreach{$_} -join " " }) }

function Style
{
return [Element] @{
Tag = "style"
Text = "$args"
}
}

# Takes a hash table, casts it to and HTML document
# and then returns the resulting type.
#
function Html ([HTML] $doc) { return $doc }

SEE ALSO
about_DesiredStateConfiguration
about_Language_Keywords
about_Methods
Writing a custom DSC resource with PowerShell classes (http://technet.microsoft.com/library/dn948461.aspx)