Lability tutorial

A tutorial for working with Lability

View project on GitHub

Chapter 4: Expanding our simple example

We expand on the lab built in Chapter 2. We keep the single VM and the external Hyper-V switch, and add a discussion of lab prefixes, custom resources, and DSC modules and versions.

Last tested: NEVER

On this page

The external Hyper-V switch

If you haven’t followed Chapter 2, note that the Hyper-V switch you must create at the beginning of that chapter is used here. I called mine WiFi-HyperV-VSwitch; if you have a different name for the external Hyper-V switch you wish to use, make sure to replace it in the config data below.

For more information about Hyper-V switch types, see Hyper-V switch types

For more information about using different types of Hyper-V switches in Lability, see the about_Networking help topic.

Lab prefixes

You can set a lab prefix in the configuration data like so:

@{
    NonNodeData = @{
        Lability @{
            EnvironmentPrefix = "PrefixValue-"
        }
    }
}

This prefix will apply to everything, including VMs and switches.

Because this chapter uses an already existing external switch created in Chapter 2, we do not use a prefix in this chapter, because any prefix will apply to our external switch as well.

That is, if we have configuration data like this:

@{
    AllNodes = @(
        @{
            NodeName = "ExampleNode"
            Lability_SwitchName = "External-Switch"
        }
    )
    NonNodeData = @{
        Lability @{
            EnvironmentPrefix = "PrefixValue-"
        }
    }
}

… then our VM will look for an existing switch called PrefixValue-External-Switch, rather than merely External-Switch. This means that if we use a switch created ahead of time with the name External-Switch, we cannot use the EnvironmentPrefix in the Lability key for the NonNodeData section of our configuration data.

Therefore, in this chapter, we do not use the EnvironmentPrefix key.

Custom resources

We add a custom resource to download the Firefox installer which we can use in our VM. This is accomplished via a Resources key under the Lability key in NonNodeData.

In this chapter, we define a custom resource for the Firefox installer. That resource is specified like this in the configuration data:

@{
    AllNodes = @(
        @{
            NodeName = "Example"
            Resources = @('Firefox')
        }
    )
    NonNodeData = @{
        Resources = @(
            Id = 'Firefox';
            Filename = 'Firefox-Latest.exe';
            # This URI redirects to the latest version of the Firefox installer:
            Uri = 'https://download.mozilla.org/?product=firefox-latest-ssl&os=win64&lang=en-US';
        )
    }
}

And used in our configuration script like this:

Script "InstallFirefox" {
    GetScript = { return @{ Result = "" } }
    TestScript = {
        Test-Path -Path "C:\Program Files\Mozilla Firefox"
    }
    SetScript = {
        $process = Start-Process -FilePath "C:\Resources\Firefox-Latest.exe" -Wait -PassThru -ArgumentList @('-ms')
        if ($process.ExitCode -ne 0) {
            throw "The Firefox installer at exited with code $($process.ExitCode)"
        }
    }
}

DSC modules and versions

You can define a DSCResources subkey of NonNodeData to declare the names and versions of the DSC resources you wish to use with your nodes.

If this subkey is not defined in your configuration data, Lability will whatever version of the DSC resource is installed on your Hyper-V host.

That said, it is best practice to define the version in your configuration data, because doing so allows you to specify a specific resource version rather than simply using whatever is installed locally. Lability will automatically download any (specified version of) a module in DSCResources, and save it to $env:LabilityResourcePath. This makes your configurations more portable, and protects against accidentally installing a new version of the resource that may include breaking changes.

In the DSCResources section of this chapter, we declare that we will use two external resources:

  1. The xComputerManagement resource,
  2. The xNetworking resource

Both of these resources are published by Microsoft. However, they are not published with Powershell DSC itself, and must be installed from the PSGallery. Fortunately, Lability handles this for us - by defining the resources here in this way, we instruct Lability to automatically download the modules from the PSGallery and install them on our VM’s VHD before starting the VM.

One further note: the x prefix is a Microsoft convention indicating an eXperimental resource which may change its API as new versions are released. You may also see resources whose names are prefixed with c, which indicates a Community resource. Resources with no name prefix ship with DSC, and do not require declaration in the configuration data.

Lab exercises and files

  1. Deploy the lab and log on. Launch Firefox and visit a website.

  2. Explore custom Lability resources that get copied to the VM under C:\Resources

  3. Add another custom resource, redeploy, log on, test the resource.

    Make sure to add the custom Lability resource to NonNodeData, and also to use it in Configure.SIMPLEX.ps1 by referencing it in a DSC resource.

    This can be anything, but you might want to pick something that is relatively small for a quick download. For instance, you might add the SysinternalsSuite zipfile as a custom Lability resource, and then use the DSC Script resource to start procexp.exe on logon.

  4. Explore custom DSC resources that get copied to the VM under C:\Program Files\WindowsPowerShell\Modules

  5. Add and use another DSC resource. You might consider trying to add the cChoco module, which contains resources like cChocoInstaller to install Chocolatey, and cChocoPackageInstall to install Chocolatey packages.

ConfigurationData.SIMPLEX.psd1

@{
    AllNodes = @(
        @{
            NodeName                    = 'CLIENT1';
            Role                        = 'CLIENT';
            InterfaceAlias              = 'Ethernet';
            AddressFamily               = 'IPv4';
            Lability_SwitchName         = "Wifi-HyperV-VSwitch";
            Lability_Media              = 'WIN10_x64_Enterprise_EN_Eval';
            Lability_ProcessorCount     = 1;
            Lability_StartupMemory      = 2GB;
            Lability_Resource           = @('Firefox')
            PSDscAllowPlainTextPassword = $true;
        }
    );
    NonNodeData = @{
        Lability = @{
            EnvironmentPrefix = 'SIMPLEX-';
            DSCResource = @(
                @{ Name = 'xComputerManagement'; RequiredVersion = '1.9.0.0'; }
                @{ Name = 'xNetworking'; RequiredVersion = '3.2.0.0'; }
            );
            Resource = @(
                @{
                    Id = 'Firefox';
                    Filename = 'Firefox-Latest.exe';
                    Uri = 'https://download.mozilla.org/?product=firefox-latest-ssl&os=win64&lang=en-US';
                }
            )
        };
    };
};

Configure.SIMPLEX.ps1

Configuration SimpleExpandedConfig {
    param ()

    Import-DscResource -Module PSDesiredStateConfiguration

    Import-DscResource -Module xComputerManagement -ModuleVersion 4.1.0.0
    Import-DscResource -Module xNetworking -ModuleVersion 5.7.0.0

    # Common configuration for all nodes
    node $AllNodes.Where({$_.Role -in 'CLIENT'}).NodeName {

        # Configure the DSC LocalConfigurationManager (LCM)
        # In general, Lability configs will use an LCM section like this
        # Details for configuring the LCM can be found at
        # <https://docs.microsoft.com/en-us/powershell/dsc/metaconfig>
        LocalConfigurationManager {
            RebootNodeIfNeeded   = $true;
            AllowModuleOverwrite = $true;
            ConfigurationMode    = 'ApplyOnly';
        }

        # Enable ICMP ECHO (aka ping) requests over IPv4
        xFirewall 'FPS-ICMP4-ERQ-In' {
            Name        = 'FPS-ICMP4-ERQ-In';
            DisplayName = 'File and Printer Sharing (Echo Request - ICMPv4-In)';
            Description = 'Echo request messages are sent as ping requests to other nodes.';
            Direction   = 'Inbound';
            Action      = 'Allow';
            Enabled     = 'True';
            Profile     = 'Any';
        }

        # Enable ICMP ECHO (aka ping) requests over IPv6
        xFirewall 'FPS-ICMP6-ERQ-In' {
            Name        = 'FPS-ICMP6-ERQ-In';
            DisplayName = 'File and Printer Sharing (Echo Request - ICMPv6-In)';
            Description = 'Echo request messages are sent as ping requests to other nodes.';
            Direction   = 'Inbound';
            Action      = 'Allow';
            Enabled     = 'True';
            Profile     = 'Any';
        }

        # Set the VM's hostname
        xComputer 'Hostname' {
            Name = $node.NodeName;
        }

        Script "InstallFirefox" {
            GetScript = { return @{ Result = "" } }
            TestScript = {
                Test-Path -Path "C:\Program Files\Mozilla Firefox"
            }
            SetScript = {
                $process = Start-Process -FilePath "C:\Resources\Firefox-Latest.exe" -Wait -PassThru -ArgumentList @('-ms')
                if ($process.ExitCode -ne 0) {
                    throw "The Firefox installer at exited with code $($process.ExitCode)"
                }
            }
        }
    }

}

Deploy-SIMPLEX.ps1

[CmdletBinding()] Param(
    [SecureString] $AdminPassword = (Read-Host -AsSecureString -Prompt "Admin password"),
    [string] $ConfigurationData = (Join-Path -Path $PSScriptRoot -ChildPath ConfigurationData.SIMPLEX.psd1),
    [string] $ConfigureScript = (Join-Path -Path $PSScriptRoot -ChildPath Configure.SIMPLEX.ps1),
    [string] $DscConfigName = "SimpleExpandedConfig",
    [switch] $IgnorePendingReboot
)

$ErrorActionPreference = "Stop"

. $ConfigureScript
& $DscConfigName -ConfigurationData $ConfigurationData -OutputPath $env:LabilityConfigurationPath -Verbose
Start-LabConfiguration -ConfigurationData $ConfigurationData -Path $env:LabilityConfigurationPath -Verbose -Password $AdminPassword -IgnorePendingReboot:$IgnorePendingReboot
Start-Lab -ConfigurationData $ConfigurationData -Verbose