Plaster Baby Steps

Just a quick note… started to get addicted to plaster. One other thing I learned but not fully. I wanted to include the PowerShell Version to the plaster process. I made changes and the template started failing. It would appear there is some case sensitivity:

powerShellVersion='$PLASTER_PARAM_ModulePSVer'
The “p” in powerShellVersion appears to be lowercase only. I have to figure out the parameter names and case sensitivity. I found this by trial and error but I need to get more fluent with it.

PowerShell Plaster Baby Steps

I have created modules, normally just for a demo showing how easy it would be to distribute PowerShell. They were simply a script I renamed to psm1 or a psm1 I created and threw some functions in it.

With the current role in, I see a greater need for a few modules. I could go with a bunch of functions in a script, or load scripts during runtime of my main script. I do not want to clutter my script with a large number of functions or even a few lines like:

. .\script1.ps1
. .\script2.ps1

Now I have to admit I have use Sapien’s PowerShell Studio to create a few modules. While I love the product I do not have access to it. That said it creates basic/static module files.

I saw the plaster module, read a few articles about it and at first my response was “meh” but hey it is prompting me for some interesting items so I must be missing something. I spent a day or two but just couldn’t figure something out like adding the Company Name at build time.

I was using Twitter to follow the news coming from the 2018 PowerShell summit. A post announced that there was going to be a presentation regarding Plaster. I liked the post and mentioned that I can’t wait to see the presentation when it was posted.

Two days later I received a link to the presentation. Major thanks to  for facilitating @rjpleau sending me a link to the presentation materials which can be found on github here.

Using this as a practical reference I was able to figure out what I was doing wrong with just get the company name as a runtime option. I know, nothing monumental but I write my own modules but at work I want to ensure I record my employers company name.

Sorry for the formatting of the XML is not great. Basically I copied an existing template (finding that folder is not easy (start looking in $env:userprofile either .vscode or .vscode-insiders then find the powershell module, then modules folder then plaster and then the templates folder). I copied the NewPowerShellScriptModule then renamed it. Then I edited the plastermanifest.xml to what you see below.

<?xml version="1.0" encoding="utf-8"?>
<plasterManifest
    schemaVersion="1.1"
    templateType="Project" xmlns="http://www.microsoft.com/schemas/PowerShell/Plaster/v1">
    <metadata>
        <name>JJK</name>
        <id>dd02bf66-9960-4014-a6fc-f09d5387c189</id>
        <version>1.0.0</version>
        <title>JJK Module Template</title>
        <description>Customized Manifest for creating Modules</description>
        <author>Kavanagh</author>
        <tags>Automation</tags>
    </metadata>
        <parameters>
                <parameter name="ModuleFullName" type="text" prompt="Module author's name" />
                <parameter name="ModuleName" type="text" prompt="Name of your module" />
                <parameter name="ModuleDesc" type="text" prompt="Brief description on this module" />
                <parameter name="Version" type="text" prompt="Initial module version" default="0.0.1" />
                <parameter name="ModuleCompanyName" type="text" prompt="Company name" default='N/A' />
                <parameter name="ModuleScripts" type="choice" prompt="Create a scripts folder for non function scripts?" default='1'>
                        <choice label="&amp;Yes" help="Creates a en-US folder within the module root" value="Yes" />
                        <choice label="&amp;No" help="Does not create a en-US folder within the module root" value="No" />
                </parameter>
        </parameters>
    <content>
        <message>

Scaffolding your PowerShell Module...


</message>
                <newModuleManifest destination='${PLASTER_PARAM_ModuleName}.psd1'
                                                     author = '$PLASTER_PARAM_ModuleFullName'
                                                     moduleVersion='$PLASTER_PARAM_Version'
                                                     rootModule='${PLASTER_PARAM_ModuleName}.psm1'
                                                     companyName='$PLASTER_PARAM_ModuleCompanyName'
                                                     encoding='UTF8-NoBOM'
                                                     openInEditor="true"/>
                <file source='Module.psm1'
                            destination='${PLASTER_PARAM_ModuleName}.psm1'
                            openInEditor="true"/>
                <message>Your new PowerShell module project '$PLASTER_PARAM_ModuleName' has been created.</message>
    </content>
</plasterManifest>

What I learned, and some of this is just take the example and following naming convenstions, in order to get something like a company name value in the resulting psd1 you have to create a parameter value and then include it in the newModuleManifest destination section To call the parameter which in this example is ModuleCompanyName you use $PLASTER_PARAM_ModuleCompanyName.

Cut to the end, in my resulting module’s psd1 you will find:

# Company or vendor of this module
CompanyName = 'KavanaghTech'

Which is the value I entered when I started the invoke-plaster (even easier in VSCode as it is simply availabe in the command palette) using my new template and during the initial process that is the value I entered for the Company Name.

Sorry for the rambling but I just wanted to share what was a major frustration for me. I also wanted to share the greatness that is the PowerShell community.

Better way to Reboot a computer

I saw a post of how to use the restart-computer cmdlet. They used wait to pause the process until the computer was back online. This post is just how to take it one step further. If I want my script to wait for the reboot to occur it is normally because I want to perform more actions against it. In this post I am using the restart-computer cmdlet but I am extending it to wait but I am also specifying what it will wait For.  In this case I am waiting for WinRM to come online so that I can connect to CIM.

Yes, I splatted it because I love splatting parameters for readability and flexibility.

#Requires -Version 5
<# .SYNOPSIS     Better way to reboot computers .DESCRIPTION     Really it is just an demonstration of the flexibility of restart-computer. Being able to tell the cmdlet to     wait for a specific element to be online before continuing can help with workflows that require a reboot and     then further action. .PARAMETER ServerName     Name of the computer to be restarted. .EXAMPLE     C:\PS>.\better-rebootcomputer.ps1 -servername testmachine
    Example of how to use this cmdlet
.Link
    https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.management/restart-computer
.NOTES
    ===========================================================================
    Created with: 	Visual Studio Code
    Created on:   	05.01.2017
    Created by:   	John Kavanagh
    Organization: 	TekSystems
    Filename:     	better-rebootcomputer.ps1
    ===========================================================================
    date initials: Enter first comment here
#>

[CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')]
Param(
     [Parameter(Mandatory = $true,
     ValueFromPipeline = $true,
     Position = 1,
     HelpMessage = "Enter the computer name to be rebooted")]
     [ValidateScript({test-connection -Computername $_ -Count 1 -Quiet })]
     [System.String]$servername
)
$args = @{
    ComputerName = $servername
    Wait         = $True
    For          = "WinRM"
    Force        = $True
}
restart-computer @args
# Now let's test - yes I am using CIM so For has to be WinRM, WMI is up first but CIM
# requires WinRM
$sess = New-CimSession -computer $servername
Get-CimInstance -classname win32_operatingsystem -CimSession $sess<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>

 

PoSH–vscode analyzer and parameters

The more I work with Visual Studio code the more I like it, especially for PowerShell. The Integrated Terminal just gets better and better. It just makes working with scripts much easier and makes me better at crossing the t’s and dotting the i’s.

One thing I came across recently was how the ScriptAnalyzer (a tool not just for vscode ) and Visual Studio Code work together. I was working with some colleagues on taking some code for a project and assembling it into a script. Of course that meant adding advanced functionality.  I wanted to provide parameters for the input that is needed. I started adding a password parameter. While it isn’t a formal credential but rather a simple string applied to a step within the script I used the word password in the parameter name. Then I noticed green squiggly lines for the complete parameter statement. Understanding that this was just a recommendation I messed around with it a little. As soon as I changed the parameter name to something other than “password” the warning/suggestion indicator disappeared. Since I want the operator to understand what the parameter is I kept the name and will live with the green squiggly lines but I just thought that was a nice implementation.

param-detection

Powershell, Visual Studio Code and Extensions

While getting the feel for, and getting even more comfortable with, Visual Studio code I have been playing with a good number of Extensions. While fun, this can be overwhelming as there are a great number of extensions available depending on what you plan on using Visual Studio Code for. The ones I am favoring so far:

I am leaving out themes as I still have not found the Theme for me but there are some interesting choices.

Just some quick code:

Begin {
    $extPath = "C:\Program Files (x86)\Microsoft VS Code Insiders\resources\app\extensions"
}
Process {
    $codeExtensions = get-childitem -Path $extPath -Directory | sort-object -Property Name
    ForEach ($ext in $codeExtensions) {
        $ext.Name
    }
}

I am using Open Live Writer to write blog posts, still hoping a Code Syntax plugin becomes available because in my opinion this a a great blogging tool.