Git Product home page Git Product logo

plaster's People

Contributors

abbgrade avatar andrewpla avatar b4art avatar bgelens avatar brantb avatar davegreen avatar daviwil avatar erikgraa avatar fflaten avatar gaelcolas avatar gerane avatar gitter-badger avatar glober777 avatar hdansou avatar heyitsgilbert avatar jbruett avatar jdhitsolutions avatar johlju avatar justingrote avatar kjacobsen avatar marckassay avatar martinsgill avatar mikefrobbins avatar muzzar78 avatar pauby avatar psjamesp avatar rkeithhill avatar tomlarse avatar x-guardian avatar zloeber avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

plaster's Issues

PowerShell Output Error in VS Code

If I open the InvokePester.ps1 file in VS Code I get an error in the PowerShell Output. Anytime I swap between another file and InvokePester.ps1 this error occurs.

Suppression Message Attribute error at line 16 in InvokePlaster.ps1 : Cannot find any Targets ModifyContent that match the Scope Function to apply the SuppressMessageAttribute.

Test-PlasterManifest : the help section was not updated

This is now false :

.OUTPUTS
    System.Boolean
    Returns "True" when the plaster manifest file is valid and "False" when
    it isn't valid.

Could you please add an example about the use of the Verbose parameter (ValidationEventHandler event) ?

Erroneous display when a file is outside the Plaster destination path

I try to create an xml file outside the path destination :

    <templateFile source='Templates\ShelLibrary-ms.T.xml'
        destination='${Env:AppData}\Microsoft\Windows\Libraries\${PLASTER_PARAM_ProjectName}.library-ms'
        encoding='UTF8'/>  

I know this it not supported, but the file name displayed is not the used file name :
bug-filepath1
With -verbose :
bug-filepath2

For this operation i must create a post installation script.

Invoke-Plaster Fails

When running Invoke-Plaster I get the following error:
Create FooUtils.psd1
Microsoft.PowerShell.Management\Get-ChildItem : Cannot find path 'C:\Users\Stefan\RecurseTest'
because it does not exist.
At C:\users\Stefan\Documents\GitHub\Plaster\InvokePlaster.ps1:473 char:22

  • ... $files = Microsoft.PowerShell.Management\Get-ChildItem @gciParams
  •              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : ObjectNotFound: (C:\Users\Stefan\RecurseTest:String) [Get-ChildItem]
      , ItemNotFoundException
    • FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

plastertest

Provide a way to store common parameter values for templates

Reading through the project and I stumbled on this:

After having run the Invoke-Plaster command for a few days, I'mm already pining for a Yeoman like store feature where I can add parameter attribute to say that the parameter can be stored and then its value recalled as the default value. So after I've entered my name or copyright notice once, it can be stored and used as the default value instead of the template provided default value.

I was just wondering if there you could leverage the built in powershell default parameters for this?

The module localization is not supported

The localization is not yet supported :

cd 'C:\Users\Laurent\Downloads\Plaster-master\Examples\NewModuleTemplate'
Import-Module ..\..\Plaster.psd1
# Import-LocalizedData : Cannot find the Windows PowerShell data file 'PlasterResources.psd1' in directory
# 'C:\Users\Laurent\Downloads\Plaster-master\fr-FR\', or in any parent culture directories.
# At C:\Users\Laurent\Downloads\Plaster-master\Plaster.psm1:32 char:1
# + Import-LocalizedData LocalizedData -FileName PlasterResources
# + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#     + CategoryInfo          : ObjectNotFound: (C:\Users\Lauren...rResources.psd1:String) [Import-LocalizedData], PSInv
#    alidOperationException
#     + FullyQualifiedErrorId : ImportLocalizedData,Microsoft.PowerShell.Commands.ImportLocalizedData

Get-Culture
# LCID             Name             DisplayName
# ----             ----             -----------
#1036             fr-FR            Français (France)
$PSVersionTable
# Name                           Value
# ----                           -----
# PSVersion                      5.0.10586.117
# PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0, 5.0.10586.117}
# BuildVersion                   10.0.10586.117
# CLRVersion                     4.0.30319.42000
# WSManStackVersion              3.0
# PSRemotingProtocolVersion      2.3
# SerializationVersion           1.1.0.1

Invoke-Plaster no longer works with the example

Following the latest commit, Invoke-Plaster throw an exception :

[STA] C:\Users\Laurent\Downloads\Plaster-master\Examples\NewModuleTemplate> Invoke-Plaster @PlasterParams -Force
Invoke-Plaster : A parameter cannot be found that matches parameter name 'FullName'.

in xml :

        <parameter name='FullName' type='author' store='encrypted' prompt='Enter your fullname'/>

in InvokePlaster.ps1 the code in dynamicparam do not manage the 'author' type.

What about for nested template ?

Have you plan to implement nested template ?

        <parameter name='Options' type='multichoice' default='0,1,2' store='text' prompt='Select desired options'>
            <choice label='P&amp;Sake build script'
                    help="Adds a PSake build script that generates the module directory for publishing to the PSGallery."
                    value="PSake"/>
          ...
        </parameter>

         <!-- Invoke a Plaster template (PSakeDirectoryTemplate\plasterManifest.xml) -->
        <NestedTemplate condition="$PLASTER_PARAM_Options -contains 'PSake'" Value='PSakeDirectoryTemplate'>

File recurse does not work anymore

This code does not work as expected :

        <!-- Recursively copy all *files* into the corresponding directory structure under dest dir Recurse -->
        <file source='RecurseTest\**'
              destination='Recurse'
              template='true'/>
Scaffold a PowerShell Module with the

   Create FooUtils.psd1
   Expand Recurse\README.md  ********
   Create Recurse\README.md   ********
   Create FooUtils.psm1
   Create .gitignore
   Expand LICENSE.txt
   Create LICENSE.txt

See
c2d171b#diff-deaa637a88a56ef9e9a0eecb4a57f438

[edit]
May be change this line :

 #function ExpandFileSourceSpec(
$srcPath = Join-Path $TemplatePath $parent

to

$srcPath = Join-Path $TemplatePath $srcRelPath

The Invoke-Plaster Get-Content happens before the condition

This result in an error because the file does not exist when using ISE for instance.
image

Moving line 349 after the condition block would solve the problem (easier for you to fix than for me to branch + fix + PR, but happy to do tomorrow if you guys are busy).

Looking for guidance

I'm setting up a new module to publish to the gallery.

I've got a process that works. Probably can be improved and I figured maybe a good fit for plaster.

I usually start with a ps1 to try out an idea. Once it is reasonably stable, I move to make it a module, prep it to be published and versioned in a public git repo. This means creating a properly named psd1, psm1 in a new git directory. I have an InstallModule.ps1 and PublishToGallery.ps1. InstallModule.ps1 simulates Install-Module so I can smoke test it before publishing. PublishToGallery.ps1 does just that.

It be great if I could plaster this entire thing. Varying the name and scaffolding the rest.

Is this a fit for Plaster? Can it be easily templated today?

Thanks

Messages to localize

Could you to localize these following lines ?

# InvokePlaster.ps1
  Write-Verbose "Creating destination dir for module manifest: $manifestDir"

  throw "Expected parameter DstPath value to be an absolute path, got '$DstPath'"

  throw "$Path must contain $fullDestPath"  

Template Distribution.

I think it is worth starting a serious discussion on how these templates are going to be distributed and how Plaster could potentially detect installed templates. I have been seeing several people getting interested about Plaster, and the problem of distribution and just finding Plaster templates is becoming evident.

PSGallery

I think the best distribution method would likely be the PSGallery and add a flag or something for plaster. However, I feel there is an issue with this that conflicts with the prevention of Code Execution in the Plaster Templates. If you install a module from the PSGallery, you just bypassed any attempt at preventing Code execution. If you are wanting to be malicious just have the code run at module installation and/or module import. The same goes with any other module, if you want to be malicious, just have it execute at module installation.

Template Detection

If Templates are distributed as modules, I think it would be beneficial for Plaster to be able to detect those templates in the module directories in some way. Maybe you have a standard folder name or other signal that Plaster can find. Instead of supplying a template path, I think it would be beneficial to either have a new command that prompts the user of template choices, or add a new method to invoke plaster that searches for installed templates and prompts the user.

I just wanted to get a dedicated discussion going on this and see what peoples thoughts were.

Enable support for localized templates

Today it is impossible to use a hashtable into a template :

Import-LocalizedData -BindingVariable PLASTER_MyTemplate -Filename MyTemplate.psd1
Invoke-Plaster ...

  #Xml template
<message>$($PLASTER_MyTemplate.VcsTask)</message>
<message>$($PLASTER_MyTemplate.$PLASTER_PARAM_License)</message>


 #Module.T.ps1
$ModuleManifestName = '<%=$PLASTER_PARAM_ModuleName%>.psd1'
# <%=${PLASTER_GUID1}%> - testing use of PLASTER predefined variables.
# <%=$PLASTER_MyTemplate.ManifestComment%> -

Adding this feature would be appreciated.

Validation of a 'parameter' node

All 'parameter' nodes with "type='input'" are [string] type :
I can declare this :

cd 'C:\Users\Laurent\Downloads\Plaster-master\Examples\NewModuleTemplate'
Import-Module ..\..\Plaster.psd1

$PlasterParams = @{
    TemplatePath = $PWD
    Destination = '..\Out'
    ModuleName = ''
    FullName = 'John Q. Doe'
    Version = '-1'
    Options = 'PSake','Pester','Git','None'
    Editor = 'VSCode'
    License = 'MIT'               
}

Invoke-Plaster @PlasterParams
  • 'ModuleName' is a correct string, but not a valid filename.
  • 'Version' is a valid string, but not a valid version.
  • 'Options' is a valid set, but the values seems inconsistent.

How to control these cases ?
How to known the valid values for a 'Powershell Gallery' template ?

Allow conditionial parameter input

It might be useful to allow the parameters to be requested based on conditions, similar to what you do in the content section.

That way, you could have context specific parameters such as:

if ! PLASTER_PARAM_useDHCP
- ask for vm_ip
- ask for subnet mask.

Multichoice PromptForChoice does not work as intended in ISE or VS Code.

I have posted some examples here: https://gist.github.com/gerane/b40a4755fc249ed420c49ae8fef947f9

When specifying [Int[]] for Default value in order to take Multiple selections, it breaks the GUI portion of the Prompts and forces it to console.

In ISE you can still use it, but it might be confusing to users to have some prompts in a GUI and some in console.

The bigger issue is in an Editor like VSCode. If the user doesn't have their output open, they won't even see their options. They are in the console, but being prompted by a blank prompt that only has a ":". I think this will really confuse most users.

Here is a gif showing what it looks like.

Question about Encoding attribute

The xsd documentation says :

  <xs:simpleType name="EncodingType">
    <xs:annotation>
      <xs:documentation>
        The encoding to use for writing to a file.
      </xs:documentation>
    </xs:annotation>

What about for the encoding to use for reading a file ?

Plaster Use Cases

I wanted to start a thread here where folks can see our initial list of use cases. Propose others for debate and eventually wind up with a set of supported use cases for the initial release. Here is the set of use cases I have been working off of for the preview.

  1. Create files for the user.
    This may be an empty PSM1 file or an about_${ModuleName}.help.txt file with some boiler plate text in it or a module manifest file filled in with information gathered from the user.
  2. Create folders where necessary to provide required (or desired) structure.
    For instance, projects targeting VSCode that supply tasks.json file need to put that file in a .vscode directory and if that directory doesn't exist, it needs to be created. Similarly a module manifest Pester test might go in a Tests folder.
  3. Modify existing files.
    Templates are just for initial project scaffolding. You can use them throughout project (module/dsc resource) development to: Add a new DSC resource or add PSake build support to a pre-existing module. Some additions might require modifications to existing files, like adding a new task to the VSCode tasks.json file.

I know some folks have wanted arbitrary code execution. This is something we're currently going out of our way to prevent. We want users who are expecting "scaffolding" i.e. the creation of files & folders, to be able to trust that the template isn't do something else. In fact, I haven't implemented it yet but I'd like for a user to be able to trust that the template will not modify anything outside of the DestinationPath they've specified. That said, if there are important use cases we're giving up, I'd like to know.

How to use the default values stored ?

How to use the default values stored ?

cd 'C:\Users\Laurent\Downloads\Plaster-master\Examples\NewModuleTemplate'
Import-Module ..\..\Plaster.psd1
$PlasterParams = @{
    TemplatePath = $PWD
    Destination = '..\Out'
    ModuleName = 'FooUtils'
    FullName = 'John Q. Doe'
    Version = '1.2.0'
    Options = 'Git','PSake','Pester'
    Editor = 'VSCode'
    License = 'MIT'
}

Invoke-Plaster @PlasterParams -Force
#Ok.

Invoke-Plaster -TemplatePath . -Destination ..\Out
# DEBUG: Loading default value store from
# 'C:\Users\Laurent\AppData\Local\Plaster\NewModuleTemplate-0.1.0-38bd80d9-3a47-4916-9220-bed383d90876'.
#No default Value
# from DesignNotes.md : "You could invoke the template like so and get prompted for each parameter:"
#Ok

$PlasterParams = @{
    TemplatePath = $PWD               
    Destination = '..\Out'
    ModuleName = 'FooUtils'
    FullName = 'John Q. Doe'
    Version = '1.2.0'
    Options = 'Git','PSake','Pester'
       #Editor = 'VSCode'   Default value ?
    License = 'MIT'
}
Invoke-Plaster -TemplatePath . -Force @PlasterParams 
#No default Value
# Which editor do you use
# [I] ISE  [C] Visual Studio Code  [N] None  [?] Help (default is "I"):

The store feature is under development ?

Example / standard template organization

Hi!

This might seem superficial at first glance, but given that end users may end up using examples / typical module templates the most, it might be worth some extra thought on their organization.

Two initial thoughts:

  • Consider a separate module folder. Given that many CI/CD solutions like you to dump configuration files in the root of a repo, IMHO it would be a better practice to have an independent YourModuleName folder under the root folder, specifically for module content.
  • Tests are awesome to have available, but IMHO should not be included with a typical download. It might be handy to leave these outside of the aforementioned YourModuleName subfolder, and have a Tests folder in the root. This way you could still distribute tests via github, without packaging them up, or having to write logic to avoid packaging them up.

Those are the biggest that stand out - love the idea of the tool, thanks for putting this together!

Cheers!

Add support for UTF8-noBOM encoding

Hi,
The Set-Content in PowerShell use UTF-8 with BOM, which fails when consumed in tools such as Test-Kitchen (might be a ruby thing?).
Could you add support in Plaster for an encoding UTF8-NOBOM?

I found this workaround:

$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)
[System.IO.File]::WriteAllLine($filePath, $PLASTER_FileContent, $Utf8NoBomEncoding)

Thanks,
Gael

Plaster build script tasks for signing files

Hello,

I've been using some of the ideas from the Build.ps1 script in my psake build script and I added a few tasks to enable script signing that I use on some other projects.

I can create a PR to add/merge some of the work that I've done on the build script i use. It could probably use a bit of work but I wanted to know whether this was something that you thought plaster could provide functionality for.

Thanks,
Dave Green

Plaster corrupts binaries

There are multiple parts to this issue.

If Plaster processes a file like an exe, it will corrupt it even if it doesn't modify anything.

function ProcessTemplate([string]$Path, $encoding) {
            if ($PSCmdlet.ShouldProcess($Path, $LocalizedData.ShouldProcessTemplateFile)) {
                $content = Get-Content $Path -Raw
                $pattern = '(<%=)(.*?)(%>)'
                $newContent = [regex]::Replace($content, $pattern, {
                    param($match)
                    $expr = $match.groups[2].value
                    Write-Verbose "Replacing template expr $expr in '$Path'"
                    ExpandString $expr
                },  @('IgnoreCase', 'SingleLine', 'MultiLine'))

                if ($Content -ne $newContent)
                {
                    Set-Content -Path $Path -Value $newContent -Encoding $encoding
                }
            }
        }

Every file Plaster processes it uses Set-Content with $Encoding even if there were no changes made to the file. Something like an exe might not have had a utf8 encoding so this will corrupt the exe.

Where this becomes problematic is when using Recurse on a directory. If you have files in those directories, one might add template = 'true' so the template files in that directory are processed.

A fix that so far seems to work for me is to add a simple check

                if ($Content -ne $newContent)
                {
                    Set-Content -Path $Path -Value $newContent -Encoding $encoding
                }

Instead of setting the content every single time, which creates unneeded room for error, I just added a check to see if $Content was actually altered via the Regex replace.

However, now that there is Recurse type functionality, is this fix enough? Here are a few things to consider when dealing with Recurse.

  • Should Plaster have a filetype ignore list?
  • Should Plaster attempt to determine the File's current encoding and Set-Content using that encoding?
  • Should we add a new property to the File Node that lets us specify certain files inside of a Recursed folder for Template.

I am pretty sure you could do the recurse without template = 'true' and then add other File Nodes with template = 'true' for files inside of the Recursed folder that need to be edited. The issue here is we will likely have users who do not know to do it this way and might use template = 'true' in the folder Recurse.

I am thinking I may go ahead and push the patch for the Set-Content, but wanted to discuss what I mentioned above as well.

-Force should indicate when it overwrites a file

Into this file "Plaster/examples/README.md" it is say :
"If you run the Invoke-Plaster command a second time, you see Plaster's file conflict handling.
You can use the -Force parameter to automatically overwrite existing files."

But today the -Force parameter displaying 'Conflict' state and not 'Create' state.

And the use of the 'newModuleManifest' element should not displayed 'Conflict' but 'Create'( or 'Overwrite' ?) :
conflict-newmodulemanifest

Moreover, after the call to Invoke-Plaster, one can not know what it is happened.

Add the delayed variable substitution

My goal is to create a plaster manifest template.
I try to prevent the substitution of a pattern variable in a template file :

$VcsPathRepository="<!%=${PLASTER_DestinationPath}%>"
[Environment]::SetEnvironmentVariable("<%=${PLASTER_PARAM_ProjectName}%>Profile",$VcsPathRepository, "User") }

the result :

$VcsPathRepository="<%=${PLASTER_DestinationPath}%>"
[Environment]::SetEnvironmentVariable("PlasterTestProfile",$VcsPathRepository, "User") }

I combine a templatefile element and a modify element :

        <templateFile source='Templates\Project_Clone.T.Ps1'
            destination='Project_Clone.ps1'
            encoding='UTF8'/> 

        <modify path='Project_Clone.ps1'>
            <replace >
                <original><![CDATA[(?s)(<!%=)(.*?)(%>)]]></original>
                <substitute><![CDATA[<%=$2$3]]></substitute>
            </replace>
        </modify> 

This works.
But, if I want to edit multiple files I must duplicate the element Modify
Is it possible to add multiple processing for the Modify element and/or add the delayed variable substitution ?

Consider MIT License as default license

Hi!

Not all organizations care about licenses, but some do. For the sake of folks like Justin, it might be worth leaning towards a simple, permissive license like the MIT license as a default, rather than None.

I can see arguments in both directions, but if one is specified by default, it will make it harder for folks to just ignore it, or be scared off without realizing there's a decent boiled down overview.

Cheers!

Variable for date and time.

I would like to see a variable that inserts creation date or creation date and time when plaster is invoked. Either give separate variables for the different formats or give a way to specify format for the variable.

How to create empty directories ?

Is the 'File' element can manage this case ?

Import-Module Plaster

cd G:\PS\Plaster
md FabrikamNewModule

$PlasterParams = @{
    TemplatePath = "$PWD\FabrikamNewModule"
    Destination = "$PWD\Out\FabrikamNewModule"
    ModuleName = 'MapPSCode'
    FullName = 'John Q. Doe'
    Version = '1'
    Options = 'PSake','Pester','Git',
    Editor = 'VSCode'
    License = 'MIT'               
}

$Directories=@(
  'Demos',
  'en-US',
  'fr-FR',
  'Help',
  'Tests',
  'Tools',
  'Bin',
  'FormatData',
  'Modules',
  'Setup',
  'TypeData'
)

md $PlasterParams.Destination
Push-Location $PlasterParams.Destination 
$Directories|
Foreach {
 md $_ -Verbose -ea SilentlyContinue > $null
} 
Pop-Location

#Invoke-Plaster @PlasterParams ...

Remarks around the localization of the ' PlasterRessources.psd1' file

I am localizing the PlasterRessources.psd1 file and I have some remarks about it.

PlasterResources.psd1
The key 'ManifestNotValid_F1' is for a valid Xml file.
the key 'ManifestNotValidXml_F1' is for a not well-formed Xml file.

Key 'UnrecognizedAttribute_F2' -> Unrecognized manifest attribute {0} on element {1}.
Unrecognized manifest attribute is managed by the XSD.
May be rename it to 'UnrecognizedContentTypeAttribute_F2'

Likewise for 'UnrecognizedParameterType_F2' -> Unrecognized parameter type '{0}' on parameter name '{1}'.

The key 'UnrecognizedContentElement_F1','UnrecognizedParametersElement_F1' are managed by the XSD ?
May be rename it to 'NotImplementedElement' ?

InvokePlaster.ps1
I know is temporary, but 'Create' is not localized :

  # TODO: Temporary - remove this when this function makes use of ProcessFile
  WriteOperationStatus 'Create' (ConvertToDestinationRelativePath $dstPath)

TestPlasterManifest.ps1
Is it possible to save the original exception ?

   Write-Error ($LocalizedData.ManifestNotValidXml_F1 -f $Path)

   #Something like this
   $Ex= (new-object System.ApplicationException(($LocalizedData.ManifestNotValidXml_F1 -f $Path),$_.Exception))
   $Er=New-Object System.Management.Automation.ErrorRecord(
         $Ex, 
         "InvalidFormat", 
         "InvalidData",
         ("[{0}]" -f $Path)
       )             
   Write-Error -ErrorRecord $Er

PlasterManifest-v1.xsd
The following element is not yet documented (xs:documentation) :

 <xs:attribute name="store" type="ptd:StoreFormatType"/>

The following xml is valid for Test-PlasterManifest

<?xml version="1.0" encoding="utf-8"?>
<plasterManifest>
  <metadata>
    <id>string</id>
    <version>string</version>
    <description>string</description>
    <tags>string</tags>
  </metadata>
  <content/>
</plasterManifest>

Invoke-Plaster does nothing :-)

$PlasterParams = @{
    TemplatePath = "$PWD"
    DestinationPath='..\out'
}
Invoke-Plaster @PlasterParams

Help understanding/documenting parts of the Manifest

There are parts of the manifest that I haven't been able to figure out yet. I was hoping to get more information on certain portions. I was just noting everything as I was going through and trying to get a good understanding of everything. Figured I might get some feedback and maybe this could be added to the documentation once refined.

I tried to leave questions I had in bold. I think it would be beneficial to have a list of the Nodes and their potential values etc. It would also be nice to have a place for proposed or potential ones as well. I did see one potential issue that I am going to file a bug report for with the Module Manifest.

PlasterManifest

Metadata

  • id - Unique ID to for the Package
  • title - Name of Package to Show in UIs
  • description - Description message for UIs
  • version - Package version
  • tags - I am assuming these will be searchable if there is eventually a gallery type store or when searching through your own templates?

Parameters:

  • Is the parameters section where you want a User to set a Custom variable? You could add a new type called Define or similar and they could so something like the following:
<parameter name='CustomDateFormat' type='define' default="$(([DateTime]::Now).ToString('yyyyMMdd'))" store='true'/>
<parameter name='StaticVariable' type='define' default="NoPromptStaticVariableValue" store='true'/>

I am not exactly sure what you had decided on with Code Execution and how that would impact this. If a user needed access to something like a Custom DateTime format, they could create their own variable like above. You could also just define variables without prompts. These could also be defined in a config file, but do you plan to give the ability to define variables in a config file without them needing a prompt

  • The possible types and/or planned types
    • input - Prompts user for input
    • choice - Prompts user to select 1 choice
    • mulitchoice - Prompts user to select 1 or multiple choices
  • required - The Parameter is required
  • store - I'm not quite sure yet, I am guessing this has something to do with stored variables in a config file that is not fully implemented yet. I didn't see anything in invokeplaster.ps1 at first glance.
  • prompt - What is prompted to the user. Is this Required? Can it be omitted? If omitted will the user still be prompted with a blank prompt?

Parameter Choice

  • The Choices for a choice or multichoice Type. These are used with a $host.ui.PromptforChoice dialogue that should work in editors as well.
  • label - Value Shown in Prompt to User
  • help - Small Help Messahe explaining Choice
  • value - The Actual Value

Dependencies

  • id - Potential Dependency IDs based on package metadata IDs

Content

  • This section defines the scaffolding to be built.
  • Content Elements:
  • file
    • source - Source File that will be copied.
    • destination - Destination where the file will be copied
    • condition - Condition that must be met for this to be invoked.
    • encoding - File encoding
    • template - Templates will have Plaster Variables that will be replaced.
  • newModuleManifest - Creates a new Module Manifest for the Project.
    • destination - Module psd1
    • moduleVersion - Package version
    • rootModule - Module psm1
    • author - Author of the Module
    • condition - A little confused on the condition for newModuleManifest. $FileNode.condition is referenced to define the condition, but newModuleManifest is its own node and not a FileNode. If you add a condition to the Manifest, it will not respect it. I would need to test if creating a File Node for a Manifest and setting the condition to false would carry over to the newModuleManifest Node
  • modify - Modifies Content with options for Conditions.
    • path - Path to file being modified
    • encoding - Encoding of the File (Should this be validated?)
    • condition - Condition that must be met for this to be invoked.
      • Replacement - Replaces content via pattern.

What about invalid Filename or PSdrive ?

Have you plan to manage this cases ?

HKLM:\> Invoke-Plaster -TemplatePath . -Destination ..\Out -verbose
#Error  : PathNotFound,Expand-Archive

..Plaster-master\Examples\NewModuleTemplate > Invoke-Plaster -TemplatePath . -Destination ..\Out -verbose
#With PLASTER_PARAM_ModuleName = Aux
#Error : FileOpenFailure,Microsoft.PowerShell.Commands.NewModuleManifestCommand

..Plaster-master\Examples\NewModuleTemplate > Invoke-Plaster -TemplatePath . -Destination ..\Aux -verbose
#Error : CreateDirectoryArgumentError,Microsoft.PowerShell.Commands.NewItemCommand

New-ModuleManifest : Could not find a part of the path

**********************
Windows PowerShell transcript start
Start time: 20160517085134
Machine:  (Microsoft Windows NT 10.0.10240.0)
Host Application: C:\windows\System32\WindowsPowerShell\v1.0\powershell.exe
Process ID: 7284
PSVersion: 5.0.10240.16384
WSManStackVersion: 3.0
SerializationVersion: 1.1.0.1
CLRVersion: 4.0.30319.42000
BuildVersion: 10.0.10240.16384
PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0.10240.16384
PSRemotingProtocolVersion: 2.3
**********************
Transcript started, output file is tryPlaster.txt
PS C:\Users\dfinke\Documents\GitHub\Plaster\Examples\NewModuleTemplate> Invoke-Plaster -TemplatePath . -Destination ..\Out
PS C:\Users\dfinke\Documents\GitHub\Plaster\Examples\NewModuleTemplate> Invoke-Plaster -TemplatePath . -Destination ..\O
ut

Enter the name of the module (): mymod
Enter the version number for the module (1.0.0):
Enter your fullname (): Doug
Select desired options
[P] Pester test support
[S] PSake build script
[G] Git
[?] Help
(default choices are P,S,G)
Choice[0]: g
Choice[1]:
Which editor do you use
[I] ISE  [V] Visual Studio Code  [N] None  [?] Help (default is "N"): v
Select a license for your module
[A] Apache  [M] MIT  [N] None  [?] Help (default is "N"): m

PS C:\Users\dfinke\Documents\GitHub\Plaster\Examples\NewModuleTemplate> TerminatingError(New-ModuleManifest): "Could not find a part of the path 'C:\Users\dfinke\Documents\GitHub\Plaster\Examples\Out\mymod.psd1'."
New-ModuleManifest : Could not find a part of the path 
'C:\Users\dfinke\Documents\GitHub\Plaster\Examples\Out\mymod.psd1'.
At C:\Users\dfinke\Documents\GitHub\Plaster\InvokePlaster.ps1:239 char:17
+ ...             New-ModuleManifest -Path $dstPath -ModuleVersion $moduleV ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OpenError: (:) [New-ModuleManifest], DirectoryNotFoundException
    + FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.NewModuleManifestCommand
New-ModuleManifest : Could not find a part of the path
'C:\Users\dfinke\Documents\GitHub\Plaster\Examples\Out\mymod.psd1'.
At C:\Users\dfinke\Documents\GitHub\Plaster\InvokePlaster.ps1:239 char:17
+ ...             New-ModuleManifest -Path $dstPath -ModuleVersion $moduleV ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OpenError: (:) [New-ModuleManifest], DirectoryNotFoundException
    + FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.NewModuleManifestCommand

Get-Content : Cannot find path 'C:\Users\dfinke\Documents\GitHub\Plaster\Examples\Out\mymod.psd1' because it does not 
exist.
At C:\Users\dfinke\Documents\GitHub\Plaster\InvokePlaster.ps1:240 char:28
+                 $content = Get-Content -LiteralPath $dstPath -Raw
+                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\Users\dfinke...\Out\mymod.psd1:String) [Get-Content], 
ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand
Get-Content : Cannot find path 'C:\Users\dfinke\Documents\GitHub\Plaster\Examples\Out\mymod.psd1' because it does not
exist.
At C:\Users\dfinke\Documents\GitHub\Plaster\InvokePlaster.ps1:240 char:28
+                 $content = Get-Content -LiteralPath $dstPath -Raw
+                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\Users\dfinke...\Out\mymod.psd1:String) [Get-Content], ItemNotFoundEx
   ception
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand

Set-Content : Could not find a part of the path 'C:\Users\dfinke\Documents\GitHub\Plaster\Examples\Out\mymod.psd1'.
At C:\Users\dfinke\Documents\GitHub\Plaster\InvokePlaster.ps1:241 char:17
+ ...             Set-Content -LiteralPath $dstPath -Value $content -Encodi ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\Users\dfinke...\Out\mymod.psd1:String) [Set-Content], 
DirectoryNotFoundException
    + FullyQualifiedErrorId : GetContentWriterDirectoryNotFoundError,Microsoft.PowerShell.Commands.SetContentCommand
Set-Content : Could not find a part of the path 'C:\Users\dfinke\Documents\GitHub\Plaster\Examples\Out\mymod.psd1'.
At C:\Users\dfinke\Documents\GitHub\Plaster\InvokePlaster.ps1:241 char:17
+ ...             Set-Content -LiteralPath $dstPath -Value $content -Encodi ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\Users\dfinke...\Out\mymod.psd1:String) [Set-Content], DirectoryNotFo
   undException
    + FullyQualifiedErrorId : GetContentWriterDirectoryNotFoundError,Microsoft.PowerShell.Commands.SetContentCommand

   Create
mymod.psm1
   Create
.gitignore
   Create
LICENSE.txt
   Expand
LICENSE.txt
   Create
en-US\about_mymod.help.txt
   Expand
en-US\about_mymod.help.txt
   Create
.vscode\tasks.json
PS C:\Users\dfinke\Documents\GitHub\Plaster\Examples\NewModuleTemplate> Stop-Transcript
**********************
Windows PowerShell transcript end
End time: 20160517085153
**********************

Recurse does not work if Invoking Plaster from outside of Template Directory

When invoking Plaster from a directory outside of the template directory, it is resolving the relative path against the working directory.

Instead of:

$PSCmdlet.GetUnresolvedProviderPathFromPSPath('C:\path\to\template\foldertorecurse)

It is resolving

$PSCmdlet.GetUnresolvedProviderPathFromPSPath('foldertorecurse)

Which resolves to the current working directory + the folder to recurse.

Issues in the Design Draft

I know these are just an example, but it was a bit confusing to me when trying to create a custom manifest. I think you have a typo here in the 'CreateRootFolder', but also these are missing the required='true'

<parameters>
        <parameter name='ModuleName' required='true' prompt='Enter the name of the module'/>
        <parameter name='Version' default='1.0.0' store='true' prompt='Enter the version number for the module'/>
        <parameter name='CreateRootFoler' default='Yes' prompt='Do you want to create the root folder for the project'/>
</parameters>

Also, I am looking through the invokeplaster.ps1 and I am guessing the CreateRootFolder is no longer a valid parameter? What I would like to be able to do, is provide a Destination Path, and then it create a new Directory in the Destination Path with my ModuleName or other Template variable. Is this currently possible?

Allow command execution, for everything not supported out of the box

First of all, great idea!

I believe there are things that you won't be able to provide a (safe) plaster interface for, and there will always be some repetitive execution that we'll want to automate.
It's good to not have execution embedded in manifest files (XML, JSON, PSD1) but IMO it should still provide the flexibility to 'run arbitrary code', just not from the manifest, from a ps1 file, to make reviewing easier.
One way to implement this could be that the manifest only provides 'reference' to psake tasks. So if you want to run any arbitrary task, it's in a psake file, making reviewing the module easier and quicker.

One example is that I often add one of my repo, as a git submodule on my projects, so that it lives under moduleName/lib/subLibName.
To do so, I want to have an option when I create a new module (similar to what Plaster offers), but that option will do something like:

cd ./lib/
git submodule add [email protected]:Project.git

I don't think Plaster could support 'safe' templating with those functionality for all eventuality (git submodule, other SCM, Creating Github/bitbucket repo through API/Module, opening JIRA project...), so what are we trying to keep 'safe'?

I understand that you'd want the templates to be as safe as possible to avoid malicious injection, but how's that different from the modules in the PowerShell Gallery? Installing someone else's module and using it is not safe. Using 'yet another nuget repository' will not help, and although it might be nice to have separation of 'duty', I don't think it's very scalable (you won't have a different nuget repo for every type of packaging, or you'd have a different one for DSC resources, and that would require a different security model?), and the security of a Module template should probably be treated the same as the one from a Module (which can be malicious as well).

The creation of a specialist package for this sounds like a nice idea, but I'd probably wrap it inside a PowerShell module. What's the gallery need would be more METADATA to support this new 'Type'.

The alternative to this, obviously, is that you keep it safe, and someone (or many people, independently) will leverage it and wrap around to add the 'arbitrary execution'.

Hope that's clear, feel free to ask for clarifications.

Add the possibility to create a parameter(variable) without require a keyboard input.

I try to create a profile for my project.
This file contain miscellaneous variables declaration, this variables are used inside a PSake script.
Today create a parameter/variable $Plaster requires a keyboard input.

<parameter name='ProjectName' type='input' store='text' prompt='Enter the project name'/>
<parameter name='Root' type='input' store='text' prompt='Enter the root of the project name'/>

  <!-- assert : the xml parsing is sequential -->
<Parameter name='ProjectRoot' type='NoInput' Value='${PLASTER_PARAM_Root}\${PLASTER_PARAM_ProjectName}'/>
<parameter name='Setup' type='NoInput' Value='${PLASTER_PARAM_ProjectRoot}\Setup'/>
...
<file source='Profile\Profile.T.ps1'
      destination='Profile\${PLASTER_PARAM_ProjectName}_profile.ps1'
      template='true'/>

With Profile\Profile.T.ps1 :

#Profile for the project <%=${PLASTER_PARAM_ProjectName}%>'
 param (
     [Parameter(Mandatory=$false)]
   [int]$Scope=1
 )#param

New-Variable -Name "<%=${PLASTER_PARAM_ProjectName}%>Setup" -Value '<%=${PLASTER_PARAM_Setup}%>'  -Option Constant -Scope $Scopee
...

GenerateModuleManifest checks for $Filenode.condition but is note a FileNode

This function checks for a condition using $FileNode.condition but I believe that is going to always return false since it is a newModuleManifest instead of a FileNode

$condition  = $FileNode.condition
if ($condition) {
    if (!(EvaluateCondition $condition)) {
        Write-Verbose "Skipping module manifest generation for '$dstPath', condition evaluated to false."
        return
    }
}

I would think you would need the following, but I wasn't sure if I was missing something.

$condition = ExpandString $NewModuleManifestNode.condition

Then you could add a Manifest condition like this:

<newModuleManifest destination='${PLASTER_PARAM_ModuleName}.psd1'
    moduleVersion='$PLASTER_PARAM_Version'
    rootModule='${PLASTER_PARAM_ModuleName}.psm1'
    author='$PLASTER_PARAM_FullName'
    condition="$PLASTER_PARAM_Manifest -eq 'Yes'"/>
<parameter name='Manifest' type='choice' default='0' prompt='Create a Module Manifest?'>
    <choice label='&amp;Yes'
            help="Adds Manifest."
            value="Yes"/>
    <choice label='&amp;No'
            help="Skips Manifest."
            value="No"/>
</parameter>

Currently, if you set a condition like the example above, it ignores the condition and makes the manifest regardless.

Naming Conventions for Template (xxx.T.ps1)

I have these files :

..\ProcessTemplate\Template\TestExpand.T.ps1
..\ProcessTemplate\Template\TestExpand2.T.ps1

I can use this manifest :

<?xml version="1.0" encoding="utf-8"?>
<plasterManifest schemaVersion="0.2" xmlns="http://www.microsoft.com/schemas/PowerShell/Plaster/v1">
    <metadata>
        <id>5dfd8d94-b2ea-419d-8a80-23a87024b359</id>
        <title>Process Template</title>
        <description>Expand a template file.</description>
        <version>0.2.0</version>
        <tags>TemplateFile</tags>
    </metadata>
    <parameters>
        <parameter name='FileName' type='input' prompt='Enter the name of the file to expand (%Name%.T.ps1)'/>
    </parameters>
    <content>
        <message>Expand the template ${PLASTER_PARAM_FileName}</message>
        <file source='${PLASTER_PARAM_FileName}.T.ps1'
              destination='${PLASTER_PARAM_FileName}.ps1'
              template='true'
              encoding='UTF8'/> 
    </content>
</plasterManifest>
$PlasterParams = @{
  TemplatePath = "$Pwd"
  Destination = "..\Out\ProcessTemplate"
  FileName="Template\TestExpand"
}

Invoke-Plaster @PlasterParams

The result is :

..\ProcessTemplate\Out\ProcessTemplate\TestExpand.ps1

But when I use this manifest :

<?xml version="1.0" encoding="utf-8"?>
<plasterManifest schemaVersion="0.2" xmlns="http://www.microsoft.com/schemas/PowerShell/Plaster/v1">
    <metadata>
        <id>5dfd8d94-b2ea-419d-8a80-23a87024b359</id>
        <title>Process Template</title>
        <description>Expand a template file.</description>
        <version>0.2.0</version>
        <tags>TemplateFile</tags>
    </metadata>
    <content>
        <message> Expand alls template '${PLASTER_PARAM_Templatepath}\Template' </message> 
        <file source='Template\**'
              destination='Code'
              template='true'
              encoding='UTF8'/>              
    </content>
</plasterManifest>
$PlasterParams = @{
  TemplatePath = "$Pwd"
  Destination = "..\Out\ProcessTemplate"
}

Invoke-Plaster @PlasterParams

The result is :

..\ProcessTemplate\Out\ProcessTemplate\Code\TestExpand.T.ps1
..\ProcessTemplate\Out\ProcessTemplate\Code\TestExpand2.T.ps1

I can not manage the files extension.
The source code must it evolve to manage this case or the namming convention is unnecessary ?

What is the effort?

I've been going through PowerShell, psake etc creating Build, Test and Deploy steps. This can include ARM templates and inserting JSON snippets into the overall provisioning steps. I know 80% can be done with convention over configuration. I'm wondering what the effort would be to leverage Plaster to do this?

Brain dump of initial thoughts/ideas

Hi guys,

I just saw the news about the Plaster project. Very cool concept! I haven't tried it yet, but had some ideas immediately come to mind that I wanted to share, so typing frantically while the mental iron is hot! :)

First, I personally feel that there are many not-so-obvious module extension points in PowerShell that people overlook that are worth considering. One of my personal favorite extension points is to extend functionality within PowerShell automatically via inclusion of a file structure underneath a particular module. Modules are already the vehicle for broad distribution of PowerShell artifacts, and we have PackageManagement plus the Gallery to facilitate that. Why not then have a tool like Plaster automatically discover Plaster templates that are located in any module in a Plaster folder that is under the root folder of a module? The same could be done for Pester, with tests being automatically discovered and invocable by name if they are in a Tests folder (great for reuse of tests across modules). Or DSC even, where DSC resources/configurations could be defined as an extension to a module (makes sense when both use resources in the same module). But those ships have sailed, and this ship is brand new. I personally love the idea of new PowerShell extensions that bring some new file structure or DSL to the mix being located in modules themselves, because I get all of the module goodness I'm already used to: versioning, discoverability, auto-load, PowerShellGet support, etc.

For example, I could create a module (SnippetPx -- already exists even) that includes a Plaster subfolder under the root that defines templates that can be used in Plaster. Then if that module was installed but not loaded, I could invoke Get-PlasterTemplate and get a list of all Plaster templates that are located in modules on my system. Templates can be overridden (sometimes a user may want to override a specific template) by leveraging their WindowsPowerShell\Plaster path. I already set this up for SnippetPx so that I could have a discovery mechanism that just lights up new functionality when a module containing Snippet definitions is on the system with no additional work to manage the registration/location/path/etc., and I've been meaning to share that code as part of a broader PowerShell extension library.

Going further (again, I haven't tried Plaster yet), maybe under my Plaster folder in my module I have two subfolders: templates and extensions. In templates I can offer Plaster templates that are ready to use. In extensions can I have extensions to the Plaster engine, allowing me to define Snippets as a feature that can be used in Plaster and providing whatever metadata/commands are necessary to make that happen, and my templates can automatically use the extensions in my module. If PowerShell commands are involved in those extensions, I can define them within my module and everything will just work because the entire package is just a module.

Thinking beyond that, DSLs come to mind as a nice way to consume templates. Hashtables/splatting works, but it might be nice to see a mini-DSL that can be used in place of Invoke-Plaster or that perhaps offers features that go further than Invoke-Plaster that provides interesting options that users may want. DSLs are great for structured output (generating files is a great example), and there may be some interesting ideas here that can be best realized by using a DSL.

I'm happy to discuss these at length here or in the PowerShell Slack channel, or demonstrate what I'm talking about via a Skype session anytime. Just say the word and I'll make time for it in my schedule.

How do you consider a tied variable inside the plaster context ?

In this file, it is says :
"In a future release, we may allow a template to execute arbitrary script but that will be inside a special directive perhaps called < script>."

How do you consider a tied variable inside the plaster context ? Is it safe or not ?

#Tied Variable
class GuidVariable : System.Management.Automation.PSVariable { 
  GuidVariable():base("Guid", 0, "ReadOnly,AllScope") {}

  [object] get_Value(){ return [System.Guid]::NewGuid() } 
} 
#create $Guid Variable
$ExecutionContext.SessionState.PSVariable.Set([GuidVariable]::new()) 

Invoke-Plaster...

into the xml template :

  <message>`n1 : $Guid </message>
  <message>`n2 : $Guid </message>

This use could it be forbidden ?

Add a way to add files without specifying them in Manifest.

If I am dealing with a project that has a very large number of files that are static and don't need to be edited or controlled by a condition, it makes using Plaster very cumbersome. This is especially true if you have a template directory that changes often or has new files added often.

I think a better way to address this might be to have a directory inside of the Root of the zip that Represents your directory structure and any static files that are always going into your project. Then have any Template and Conditional files in another location that are added based on the criteria.

Another option would be to automatically add everything in the zip, and then edit the template files and remove any items that don't meet a condition. Instead of adding the ones that meet conditions, we would be doing the opposite. I like this sort of option best.

Another would be to at least allow adding folders with wildcards for all items under that folder. Maybe something like the example below.

<file source='Root\Dir1\*'
        destination='Root\Dir1\*'/>
<file source='Root\Dir2\*'
        destination='Root\Dir2\*'/>

Need better error handling for TemplatePath parameter and invalid manifest files

When the template path exist, but not the 'plasterManifest.xml' file, this error is trapped :

Import-Module Plaster
$VerbosePreference='Continue'
cd c:\temp
Invoke-Plaster -DestinationPath 'C:\temp'
#    ...Plaster...
#The Plaster manifest file 'C:\temp\plasterManifest.xml' was not found.

Invoke-Plaster -TemplatePath 'C:\temp' -DestinationPath 'C:\temp'
#    ...Plaster...
#The Plaster manifest file 'C:\temp\plasterManifest.xml' was not found.

But when the template path do not exist, the behavior is different :

Invoke-Plaster -TemplatePath 'C:\temp\Notexist' -DestinationPath 'C:\temp'
# Get-Item : Cannot find path 'C:\temp\Notexist' because it does not exist.
# At C:\Users\Laurent\Documents\WindowsPowerShell\Modules\Plaster\Plaster.psm1:47 char:13
# +     $item = Get-Item -LiteralPath $TemplatePath
# +             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#     + CategoryInfo          : ObjectNotFound: (C:\temp\Notexist:String) [Get-Item], ItemNotFoundException
#     + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand
# 
# VERBOSE: Préparation de la décompression...
# VERBOSE: Error processing dynamic parameters: Le chemin d'accès C:\temp\Notexist n'existe pas ou n'est pas un chemin
# d'accès au système de fichiers valide.
#
#    ...Plaster...
#
# Get-Item : Cannot find path 'C:\temp\Notexist' because it does not exist.
# At C:\Users\Laurent\Documents\WindowsPowerShell\Modules\Plaster\Plaster.psm1:47 char:13
# +     $item = Get-Item -LiteralPath $TemplatePath
# +             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#     + CategoryInfo          : ObjectNotFound: (C:\temp\Notexist:String) [Get-Item], ItemNotFoundException
#     + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand
# 
# VERBOSE: Préparation de la décompression...
# Microsoft.PowerShell.Archive\Expand-Archive : Le chemin d'accès C:\temp\Notexist n'existe pas ou n'est pas un chemin
# d'accès au système de fichiers valide.
# At C:\Users\Laurent\Documents\WindowsPowerShell\Modules\Plaster\Plaster.psm1:58 char:16
# + ...      [void](Microsoft.PowerShell.Archive\Expand-Archive -LiteralPath  ...
# +                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#     + CategoryInfo          : InvalidArgument: (C:\temp\Notexist:String) [Expand-Archive], InvalidOperationException
#     + FullyQualifiedErrorId : ArchiveCmdletPathNotFound,Expand-Archive
# 
# The Plaster manifest file 'C:\Users\Laurent\AppData\Local\Temp\3zxu2ded.kxa\plasterManifest.xml' was not found.
# At C:\Users\Laurent\Documents\WindowsPowerShell\Modules\Plaster\InvokePlaster.ps1:196 char:17
# + ...             throw ($LocalizedData.ManifestFileMissing_F1 -f $manifest ...
# +                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#     + CategoryInfo          : OperationStopped: (The Plaster man... was not found.:String) [], RuntimeException
#     + FullyQualifiedErrorId : The Plaster manifest file 'C:\Users\Laurent\AppData\Local\Temp\3zxu2ded.kxa\plasterManifest.xml' was not found.

An another case :

$PlasterParams = @{
    TemplatePath = 'C:\temp\Notexist'
    DestinationPath = 'C:\temp'
    ProjectName ='Project'
}

Invoke-Plaster @PlasterParams -Force
# Get-Item : Cannot find path 'C:\temp\Notexist' because it does not exist.
# At C:\Users\Laurent\Documents\WindowsPowerShell\Modules\Plaster\Plaster.psm1:47 char:13
# +     $item = Get-Item -LiteralPath $TemplatePath
# +             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#     + CategoryInfo          : ObjectNotFound: (C:\temp\Notexist:String) [Get-Item], ItemNotFoundException
#     + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand
# 
# VERBOSE: Préparation de la décompression...
# VERBOSE: Error processing dynamic parameters: Le chemin d'accès C:\temp\Notexist n'existe pas ou n'est pas un chemin
# d'accès au système de fichiers valide.
#
# Invoke-Plaster : A parameter cannot be found that matches parameter name 'ProjectName'.
# At line:1 char:16
# + Invoke-Plaster @PlasterParams -Force
# +                ~~~~~~~~~~~~~~
#     + CategoryInfo          : InvalidArgument: (:) [Invoke-Plaster], ParameterBindingException
#     + FullyQualifiedErrorId : NamedParameterNotFound,Invoke-Plaster

When the xml file is not well-formed :

        <file source='Module.psm1''
              destination='${PLASTER_PARAM_ModuleName}.psm1'/>

the real reason is not displayed :

$PlasterParams = @{
    TemplatePath = 'G:\PS\Plaster\ProjectProfile'
    DestinationPath = 'G:\PS\Plaster\Out\ProjectProfile'
    ProjectName ='Project'
}

Invoke-Plaster @PlasterParams -Force 
# VERBOSE: Error processing dynamic parameters: The Plaster manifest 'G:\PS\Plaster\ProjectProfile\plasterManifest.xml'
# is not a well-formed XML file. Cannot convert value "System.Object[]" to type "System.Xml.XmlDocument". Error: "Le
# caractère ''', valeur hexadécimale 0x27, ne peut pas commencer un nom. Ligne 23, position 58."
#
# Invoke-Plaster : A parameter cannot be found that matches parameter name 'ProjectName'.
# At line:1 char:16
# + Invoke-Plaster @PlasterParams -Force
# +                ~~~~~~~~~~~~~~
#     + CategoryInfo          : InvalidArgument: (:) [Invoke-Plaster], ParameterBindingException
#     + FullyQualifiedErrorId : NamedParameterNotFound,Invoke-Plaster

For this cases, is it possible to have adequate messages : 'the file do not exist' or 'the xml file is not well-formed' or 'the xml file is invalid' ?

Detect parameter defaults where possible

It would be a nice convenience feature, e.g. if no previous value is stored (#9) to try and guess a good default value.

for example for an Author/Name field:

git config user.name

or worst case:

$env:USERNAME

The same for email etc.

This may require custom parameter types (i.e. author-name, instead of string), so that it's available to use in template choices.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.