ISEPresenter

PowerShell ISE Presenter

As a Microsoft Certified Trainer, mainly teaching Windows PowerShell courses, I spend a lot of my time presenting demos in the PowerShell ISE. During demos, I’m facing some problems within the PowerShell ISE – maybe this looks similar to you:

  • Putting the cursor on the right line
  • Selecting the correct statement to execute
  • Just hit F8 to execute the line
  • Never hit F5 (or add a break statement to the first line)
  • Execute a line twice on accident
  • Don’t forget on which line I was
  • and so on …

As a presenter, you have to take care of all of that besides commenting it in a useful way. So a demo may fail even if the code is fine – just because of the execution. The other challenge during demos: I have to be behind the screen to operate m the keyboard and mice.

To improve the demo experience for me as a teacher and for the students, I’ve developed a tool which should meet the following requirements:

  • Providing guidance during demo by executing statement by statement
  • Make the current statement visible by selecting/highlighting it
  • Be flexible to go back and forward
  • Enable remote control of the PowerShell ISE

ISEPresenter Add-On Module

As a solution, I’ve developed a PowerShell ISE Add-On module called ISEPresenter a while ago. With ISEPresenter, it’s possible to play demos with a remote control like the Logitech Presenter R400 or a (wireless) keyboard. The ISEPresenter Add-On will take care of highlighting the current statement, executing the highlighted statements and provides the possibility to go back and forward.

PowerShell ISEPresenter

Of course you can download and install it from the PowerShell Gallery.

Install-Module ISEPresenter

# Execute within the ISE
Import-Module ISEPresenter

To start a presentation, just load a script into the ISE. In ideal case, the script should be prepared to run step by step from top to bottom. To control the ISE with the ISEPresenter, you can use the Play, Pause and Stop buttons. While the presenter is active, it will override the built-in keys of the ISE like F5 and F8 and redirect them to the presenter. The presenter has four basic actions:

  • Run
    Executes the currently selected line and, if selected, highlight the next statement after completion.
  • Clear
    Clear the output screen of the console. As normally in the ISE, it will not reset the console.
  • Back
    Select the previous line.
  • Forward
    Select the next line.

PowerShell ISEPresenter

The ISEPresenter does automatically parse the script into a list of statements, not lines. So multi-line statements, like hash tables or script blocks can be, are supported. Depending on the selected device, the basic actions can be controlled by keyboard (F5, F8, DEL, Page Up, Page Down) or by the Logitech Presenter R400 with the dedicated buttons.

I hope this is useful and therefore I’ve put it on GitHub. Contributions, especially for other remote devices, are very welcome. Wish you happy presenting, with or without ISEPresenter.

What's New in SCOM 2016 Technical Preview 5

What’s New in SCOM 2016 Technical Preview 5

Microsoft has released a new Technical Preview 5 of Windows Server 2016 and System Center 2016 a few days ago. Rumors say, that this will be the last technical preview before RTM. About time to take a look on the likely new features of System Center Operations Manager 2016.

Built-in Scheduled Maintenance

This feature is in the preview since TP 2. The scheduled maintenance mode is one of the customers most requested features for the next SCOM version. It’s accessible at the Administration / Maintenance Schedules section inside the Operations Console. As in the instant maintenance mode, you have to select the target objects first. You can decide, if only the object itself or all contained objects will be put into maintenance mode.

SCOM 2016 TP 5 - Scheduled Maintenance Mode

On the next page, you can define the schedule, as we are used to do from the task scheduler.

SCOM 2016 TP 5 - Scheduled Maintenance Mode

Finally, enter a name and the desired category for the maintenance mode. As soon as you’ve finshed the wizard, the scheduled maintenance mode is active. If you temporary don’t need the scheduled maintenance mode, you can disable the entry.

SCOM 2016 TP 5 - Scheduled Maintenance Mode

In addition, the scheduled maintenance mode can be managed throught Windows PowerShell. Microsoft has added a few new cmdlets to the OperationsManager module.

SCOM 2016 TP 5 - Scheduled Maintenance Mode

Tune Management Packs

Another new feature is the Management Pack tuning option. In the past, it was very triky to find out, which rules and monitors make most noice on the system. Now SCOM 2016 TP5 makes the life easier for admins – it has a build-in Management Pack tuning setting. First, go to the Administration / Tune Management Packs page and select the Identify Management Packs To Tune task on the right side. You can select a time frame and a minimum thrshold for thrown alerts per Management Pack.

SCOM 2016 TP 5 - Tune Management Packs

It will list all Management Packs which match the time range and the alert threshold. Now you can select the Tune Alerts task on the Management Pack you want to tune. It will show all alerts thrown by the selected Management Pack.

SCOM 2016 TP 5 - Tune Management Packs

SCOM 2016 TP 5 - Tune Management Packs

As you are used to, these alerts can now be fine tuned by overrides directly out of this window. With this feature, we have a much easier and quicker way to tune a SCOM environment.

Recommended Management Packs

The next very usefull new features also is connected to Management Packs. With the new page Administration / Updates and Recommendations, SCOM shows all Management Packs wich have a new udpated version available for installation. No guessing or search on the internet for each Management Pack if there is a new version available any more.

SCOM 2016 TP 5 - Recommended Management Packs

In addition, SCOM now propose new Management Packs which could add monitorng value for the current environment but are not installed. Thanks to this new feautre, such new Management Packs can be installed directly throught the wizard, including all dependencies.

SCOM 2016 TP 5 - Recommended Management Packs

This new feature should help on a daily basis to keep the Management Pack up to date.

Nano Server Agent

The last new feature I want to point out is the support for the Nano Server SKU of Windows Server 2016. Currently the Nano Server Agent can not be installed with the Discovery Wizard inside the Operations Console (push mode). Instead, we have to use the PowerShell script on the installation media: NanoAgent\NanoServer\InstallNanoServerScomAgentOnline.ps1. This scripts uses PowerShell Remoting to install the SCOM Agent. It’s important to start the PowerShell session as Administrator on the Management Server. You have to provide the Management Server, the Management Group, the Nano Server Name and the path to the Nano Agent folder on the media.

.\InstallNanoServerScomAgentOnline.ps1 -ManagementServerFQDN '<MS>' -ManagementGroupName '<MG>' -NanoServerFQDN '<NS>' -BinaryFolder 'C:\Path\To\NanoAgent\'

The script then does the SCOM Agent installation manually on the target system: update firewall, copy files, set registry settings, register services, etc.

SCOM 2016 TP 5 - Nano Server Agent

More Information

More infomation about the whole System Center 2016 site is available on the latest video of Microsoft Mechanics: https://www.youtube.com/watch?v=OpRGKIUy37s

Gears

Using ScriptConfig to enhance PowerShell Controller Scripts

If you are creating PowerShell Controller scripts, you often have to deal with constant configuration value. As an example, you create a script called “New-CorporateUser” for creating new user account, enable the mailbox and initialize the permissions on user home shares in your company. For this script, you will have two different types of input values:

  • Input values which change with every new user, like his name or employee id
  • Input values which are static for the target system over a long time, like the domain name or the mailbox servers

For input values which change with every execution, you will use the native PowerShell param() block to provide them as parameters to your script. They will be set every time you execute your script. But what about the static values – it’s not reasonable to pass them as parameters too: Hard-code them somewhere in the script? Initialize configuration variables on top of the script? Use parameters with default values?

In any case, you have to change your script, if any of the static configuration values changes. When you use version control, which you by the way should at least for scripts in production, you will end up with a new version of your script every time a static value changes. Maybe this is what you are looking for – but, if not, have a look at my ScriptConfig module.

The goal behind this ScriptConfig module is to separate the actual code and the configuration data. While the actual codes exists inside the .ps1 script file and it’s depended modules, the configuration lays right next to your controller script in a dedicated configuration file. I’ve re-used the concept of application configuration files from .NET for PowerShell, but with a different file format. The module currently contains just one simple cmdlet: Get-ScriptConfig.

Install and use ScriptConfig module

First, get the ScriptConfig module from my GitHub repo or with PowerShell 5, you can install it directly from the PowerShell Gallery:

Install-Module ScriptConfig

Now, as the ScriptConfig module is installed on your system, you are able to integrate it into your scripts. In the following code snipped, you can find an example how you can leverage a configuration file for the demo script New-CorporateUser.ps1 and use the configuration values next to the parameters for adding a new user account to the domain. I recommend the #Requires -Modules <ModuleName> statement on the top of your scripts, because then you are sure, that all depended modules are installed on the local system.

#Requires -Modules ScriptConfig, ActiveDirectory

param
(
    [Parameter(Position=0,Mandatory=$true)]
    [String] $Account,

    [Parameter(Position=1,Mandatory=$true)]
    [String] $GivenName,

    [Parameter(Position=2,Mandatory=$true)]
    [String] $Surname
)

# Load script configuration
$Config = Get-ScriptConfig -Path "$PSScriptRoot\New-CorporateUser.ps1.config" -Format JSON

# Create active diretory user
$ADUserAttribute = @{
    Name              = "{0} {1}" -f $Surname, $GivenName
    Path              = $Config.UserOU
    SamAccountName    = $Account
    UserPrincipalName = "{0}@{1}" -f $Account, $Config.UserUPN

    DisplayName       = "{0} {1}" -f $Surname, $GivenName
    GivenName         = $GivenName
    Surname           = $Surname
}
New-ADUser @ADUserAttribute 

# Add user to groups
foreach ($Group in $Config.Groups)
{
    Add-ADGroupMember -Identity $Group -Members $Account
}

The script loads the configuration on line 16 from the specified configuration file. The format of the configuration file must be specified with the -Format parameter. The function does not guess depending on the file extension, what format it should use. Afterwards, the configuration is available inside the $Config variable as a ScriptConfig.Configuration object, which is basically a simple PSCustomObject with the configuration values as note properties. You can access the configuration values by using the dot-notation.

The ScriptConfig module supports multiple types as configuration values. They are all supported with any available configration file format:

  • String
    All settings are stored as a string values by default.
  • Integer
    If the setting value is a valid integer, it will be casted into an integer.
  • Boolean
    By specifying the key words True or False, it will be casted to a boolean type.
  • Array
    An array of strings can be specified.
  • Hashtable
    A dictionary of key-value-pairs is supported too. The key and values will be a string.

Configuration File Formats: JSON, XML, INI

The module accepts different config file format. Currently it’s JSON, XML and INI. But it can be easily extended. To support all value types as specified in the previous list, the format is specified tightly. In the following you will find an example for each file format which matches the New-CorporateUser.ps1 script.

The XML schema is tightly specified and does not exactily match with the application configuration files from .NET. The XML config file is the safest but also must verbose option, because everything is specified including the type:

<?xml version="1.0" encoding="utf-8"?>
<Configuration>
    <Settings>
        <Setting Type="string" Key="UserOU" Value="OU=CorpUsers,DC=contoso,DC=com" />
        <Setting Type="string" Key="UserUPN" Value="contoso.com" />
        <Setting Type="array" Key="Groups">
            <Item Value="All Employees" />
            <Item Value="Intranet Access" />
        </Setting>
    </Settings>
</Configuration>

JSON config files support the different types like arrays and hashtables out of the box. Be aware, deeper configuration values are not supported

{
  "UserOU": "OU=Test,DC=spizzi,DC=work",
  "UserUPN": "spizzi.work",
  "Groups":  [
               "All Employees",
               "Intranet Access"
             ]
}

The last supported format is an INI file. Because the core INI file specification does not provide support for arrays or hashtable, I’ve introduced the use of [ and ] to support these types.

UserOU=OU=CorpUsers,DC=contoso,DC=com
UserUPN=contoso.com
Groups[]=All Employees
Groups[]=Intranet Access

Conclusion

With the ScriptConfig module you are able to separate configuration values from actual code. It’s compatible back to Windows PowerShell 3.0. Thanks to the module you can start to develop a controller script right away without bother the configuration file handling. If you need more information, have a lock at the GitHub repository: ScriptConfig.

Introduction to PowerShell 5.0 Classes

Introduction to PowerShell 5.0 Classes

Since the first release of Windows 10 back in July 2015, PowerShell 5.0 is available for production usage. The backwards compatible Windows Management Framework 5.0, which includes PowerShell 5.0 for older Windows Operating Systems, was released on February 2016.

The new PowerShell 5.0 brings along many great new features, all described in a dedicated TechNet article: What’s New in Windows PowerShell. In this post, I will cover the new possibility of creating custom objects based on classes. To understand how important the new possibility is, we have to look back how we’ve use custom objects in the past.

Custom objects in the past

Since PowerShell 1.0, custom objects can be created with the New-Object cmdlet combined with the PSObject class. Because creating custom objects without any properties makes no sense, the Add-Member cmdlet was the only way to add these custom properties:

$MyCar = New-Object -TypeName PSObject
$MyCar | Add-Member -MemberType NoteProperty -Name 'Number' -Value 'CAR0001'
$MyCar | Add-Member -MemberType NoteProperty -Name 'Color' -Value 'Red'

With the following version 2.0, the New-Object cmdlet got a new parameter called -Property. With this new parameter, the properties can be initialize during the custom object construction. The properties have to be specified inside a hashtable, where the key is the property name and the value will be the property value.

$MyCar = New-Object -TypeName PSObject -Property @{
    Number = 'CAR-0001'
    Color  = 'Red'
}

One problem with this approach was,the desired order of the specified properties was not be kept after creation. The root cause is, that the used hashtable (type of System.Collections.Hashtable) is not ordered. To solve this problem, a new accelerator PSCustomObject was introduced in PowerShell 3.0. It does the same job as shown in the example before, but it will keep the order of the properties. And in addition, it’s shorter to write which makes the code easier to read.

$MyCar = [PSCustomObject] @{
    Number = 'CAR-0001'
    Color  = 'Red'
}

All three previous examples will create custom objects which are of type System.Management.Automation.PSCustomObject. In general, this is no problem until it’s important to distinguish the created objects by their types. As an example, the object type is relevant when its used together with PowerShell format files.

To add a custom type, a small trick or hack is available, as you can see in the next code block. By using the Insert() method on the PSTypeNames object property, a custom type can be injected. If you enumerate the custom object with Get-Member, the new type was shown. But under the hood, the object was still of type PSCustomObject. You can check that with the GetType() .NET method.

$MyCar = [PSCustomObject] @{
    Number = 'CAR-0001'
    Color  = 'Red'
}

$MyCar.PSTypeNames.Insert(0, 'Car')

$MyCar | Get-Member
$MyCar.GetType()

Classes

With PowerShell 5.0, finally, we have a new language keyword called class to defined real classes nut just custom objects. If you are familiar with the object-oriented programming concept, this will be just a new syntax, PowerShell hasn’t reinvent the wheel.

First, let us create a custom class to replace the Car example we’ve used before. The first line defines the class and it’s name. On the following lines, the class members are specified. As best practice, the type for all members should be defined. Because we are still using PowerShell, some concept off the advanced functions can be reused with classes. In this case, the color is validated with the annotation [ValidateSet()]. It will throw an error, if we try to assign any different value as listed in the validation set.

class Car
{
    [String] $Number

    [ValidateSet('White', 'Black', 'Red')]
    [String] $Color
}

$MyCar = [Car]::new()

$MyCar.Number = 'CAR-0001'
$MyCar.Color  = 'Red'

After the class definition itself, which is surrounded by { and }, a new object of the Car class can be instantiate. To do this, PowerShell has introduced a new static method called new(), which is available on the class type itself.

Now we have our first object based on a PowerShell class. You can verify the type with the Get-Member cmdlet and the GetType() .NET method, as we’ve used before. You will see, our object is of type Car. All members we specify will be public. It’s currently not possible to add private or protected members. Next, we extend our class with a constructor.

class Car
{
    [String] $Number

    [ValidateSet('White', 'Black', 'Red')]
    [String] $Color

    Car([String] $Number, [String] $Color)
    {
        $this.Number = $Number
        $this.Color  = $Color
    }
}

$MyCar = [Car]::new('CAR-0001', 'Car')

Thanks to the constructor, which has the same name as the class itself, we are now able to initialize the class members at creation time. The values can be passed to the new() method. The last missing core concept off classes are the methods. Methods can be specified the same way as the constructors. In addition, the methods have a defined return type. This can be any type. In our case, we will not return anything, therefore we use the void type.

class Car
{
    [String] $Number

    [ValidateSet('White', 'Black', 'Red')]
    [String] $Color

    [Int32] $Milage = 0

    Car([String] $Number, [String] $Color)
    {
        $this.Number = $Number
        $this.Color  = $Color
    }

    [void] Drive([UInt32] $Distance)
    {
        $this.Milage += $Distance
    }
}

$MyCar = [Car]::new('CAR-0001', 'Red')

$MyCar.Drive(10)

$MyCar.Milage

Enumerations

Instead of using the color property with a validation set, since PowerShell 5.0, we are also able to use enumerations. Therefore the language keyword enum has been introduced. The following example shows, how an enumeration is defined inside PowerShell, which then can be used inside the script.

enum CarColor
{
    White
    Black
    Red
}

class Car
{
    [String] $Number

    [CarColor] $Color

    [Int32] $Milage = 0

    Car([String] $Number, [CarColor] $Color)
    {
        $this.Number = $Number
        $this.Color  = $Color
    }

    [void] Drive([UInt32] $Distance)
    {
        $this.Milage += $Distance
    }
}

$MyCar = [Car]::new('CAR-0001', [CarColor]::Red)

Class Inheritance

In object-oriented programming languages, the inheritance of classes is one of the most powerful features. This is available inside PowerShell too. This following example gives you an idea, how the generic Car class can be extended.

class Car
{
    [String] $Number

    [String] $Type

    Car([String] $Number, [String] $Type)
    {
        $this.Number = $Number
        $this.Type   = $Type
    }
}

class SportCar : Car
{
    [Int32] $Horsepower

    SportCar([String] $Number, [Int32] $Horsepower) : base($Number, 'SportCar')
    {
        $this.Horsepower = $Horsepower
    }
}

class Minivan : Car
{
    [Int32] $Seats

    Minivan([String] $Number, [Int32] $Seats) : base($Number, 'Minivan')
    {
        $this.Seats = $Seats
    }
}

$MySportCar = [SportCar]::new('CAR-0001', 250)
$MyMinivan  = [Minivan]::new('CAR-0002', 10)

Conclusion

This new feature does not mean, that we should always use classes for each custom objects. The previous methods with PSCustomObject are still valid. Especially for objects which are more or less only used to store or transfer data, the PSCustomObject is a good choise. If you create multiple complex functions updating or accessing the properties of one single object, then the new class feature of PowerShell is very handy.

Due to the current low spread of Windows 10 and WMF 5.0 installations, this feature can rarely be used yet. But if your script runs inside a PowerShell 5.0 environment, you are free to use it and replace the old PSCustomObjects, where it makes sense.

As usual in PowerShell, there is also a dedicated help file available for classes which is available inside the TechNet PowerShell portal: about_Classes.

Bucherseeli, Golzernalpen, Uri, Switzerland

Claudio Spizzi’s Blog

Welcome! Long planned and finally created, my own blog is online at https://spizzi.net. I’m opening this blog with a picture taken close to my hometown, precisely because it is probably the last view of nature on my blog.

I intend to write about my experiences and success stories during my daily IT work. I will focus the content around Windows PowerShell, as I’m a declared Windows PowerShell enthusiast. Of course, it will be connected with various other technologies.

Thank you for visiting my blog. I would be glad to see you again.