From f6d2777ad5fbd2981df31bd8021c611e9a7281be Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Wed, 9 Mar 2016 22:31:56 -0700 Subject: [PATCH 1/4] Modified Examples dir to provide a preview of PSake based module publishing. --- examples/.gitignore | 5 + examples/.vscode/tasks.json | 52 +++- examples/Build.ps1 | 226 ++++++++++++++++++ examples/DebugTest.ps1 | Bin 662 -> 924 bytes examples/PathProcessingNoWildcards.ps1 | 23 +- examples/PathProcessingNonExistingPaths.ps1 | 23 +- examples/PathProcessingWildcards.ps1 | 30 ++- examples/README.md | 41 +++- examples/ReleaseNotes.md | 11 + examples/SampleModule.psd1 | Bin 0 -> 7694 bytes examples/SampleModule.psm1 | 4 + examples/Stop-Process2.ps1 | 24 +- examples/StopTest.ps1 | 1 - examples/{ => Tests}/PathProcessing.Tests.ps1 | 59 ++--- examples/Tests/SampleModule.Tests.ps1 | 9 + examples/en-US/about_SampleModule.help.txt | 15 ++ 16 files changed, 450 insertions(+), 73 deletions(-) create mode 100644 examples/.gitignore create mode 100644 examples/Build.ps1 create mode 100644 examples/ReleaseNotes.md create mode 100644 examples/SampleModule.psd1 create mode 100644 examples/SampleModule.psm1 rename examples/{ => Tests}/PathProcessing.Tests.ps1 (50%) create mode 100644 examples/Tests/SampleModule.Tests.ps1 create mode 100644 examples/en-US/about_SampleModule.help.txt diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 0000000000..a89a881917 --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1,5 @@ +# Don't checkin this output dir +Release/ + +# Auto-generated test file +foo[1].ps1 diff --git a/examples/.vscode/tasks.json b/examples/.vscode/tasks.json index 912b450b12..2082b04be0 100644 --- a/examples/.vscode/tasks.json +++ b/examples/.vscode/tasks.json @@ -1,9 +1,10 @@ // A task runner that invokes Pester to run all Pester tests under the // current workspace folder. -// NOTE: This Pester task runner requires an updated version of Pester (>=3.4.0) +// NOTE: This Test task runner requires an updated version of Pester (>=3.4.0) // in order for the problemMatcher to find failed test information (message, line, file). -// If you don't have that version, you can update Pester from the PSGallery like so: +// If you don't have that version, you can update Pester from the PowerShell Gallery +// with this command: // // PS C:\> Update-Module Pester // @@ -14,6 +15,12 @@ // PS C:\> Install-Module Pester -Scope CurrentUser -Force // +// NOTE: The Clean, Build and Publish tasks require PSake. PSake can be installed +// from the PowerShell Gallery with this command: +// +// PS C:\> Install-Module PSake -Scope CurrentUser -Force +// + // Available variables which can be used inside of strings. // ${workspaceRoot}: the root folder of the team // ${file}: the current opened file @@ -21,7 +28,6 @@ // ${fileDirname}: the current opened file's dirname // ${fileExtname}: the current opened file's extension // ${cwd}: the current working directory of the spawned process - { "version": "0.1.0", @@ -34,17 +40,45 @@ // Show the output window always "showOutput": "always", - "args": [ - "-NoProfile", "-ExecutionPolicy", "Bypass", - "Write-Host 'Invoking Pester...'; Invoke-Pester -PesterOption @{IncludeVSCodeMarker=$true};", - "Invoke-Command { Write-Host \"Completed all tasks in task runner: $($args[0])\" } -args" - ], + "args": [ + "-NoProfile", "-ExecutionPolicy", "Bypass" + ], // Associate with test task runner "tasks": [ { - "taskName": "Pester", + "taskName": "Clean", + "suppressTaskName": true, + "args": [ + "Write-Host 'Invoking PSake...'; Invoke-PSake build.ps1 -taskList Clean;", + "Invoke-Command { Write-Host \"Completed Clean task in task runner.\" }" + ] + }, + { + "taskName": "Build", + "suppressTaskName": true, + "isBuildCommand": true, + "args": [ + "Write-Host 'Invoking PSake...'; Invoke-PSake build.ps1 -taskList Build;", + "Invoke-Command { Write-Host \"Completed Build task in task runner.\" }" + ] + }, + { + "taskName": "Publish", + "suppressTaskName": true, + "args": [ + "Write-Host 'Invoking PSake...'; Invoke-PSake build.ps1 -taskList Publish;", + "Invoke-Command { Write-Host \"Completed Publish task in task runner.\" }" + ] + }, + { + "taskName": "Test", + "suppressTaskName": true, "isTestCommand": true, + "args": [ + "Write-Host 'Invoking Pester...'; Invoke-Pester -PesterOption @{IncludeVSCodeMarker=$true};", + "Invoke-Command { Write-Host \"Completed Test task in task runner.\" }" + ], "problemMatcher": [ { "owner": "powershell", diff --git a/examples/Build.ps1 b/examples/Build.ps1 new file mode 100644 index 0000000000..3f782d775b --- /dev/null +++ b/examples/Build.ps1 @@ -0,0 +1,226 @@ +############################################################################## +# PREVIEW VERSION OF PSAKE SCRIPT FOR MODULE BUILD & PUBLISH TO THE PSGALLERY +############################################################################## +# +# We are hoping to add support for publishing modules to the PowerShell gallery +# and private repositories in a future release of this extension. This is an +# early look at the approach we are considering which is to supply a +# PSake-based script that will: +# +# 1. Create a directory from which to publish your module. +# 2. Copy the appropriate module files to that directory excluding items like +# the .vscode directory, Pester tests, etc. These are configurable in Build.ps1. +# 3. Verify all existing Pester tests pass. +# 4. Publish the module to the desired repository (defaulting to the PSGallery). +# +# Requirements: PSake. If you don't have this module installed use the following +# command to install it: +# +# PS C:\> Install-Module PSake -Scope CurrentUser +# +############################################################################## +# This is a PSake script that supports the following tasks: +# clean, build, test and publish. The default task is build. +# +# The publish task uses the Publish-Module command to publish +# to either the PowerShell Gallery (the default) or you can change +# the $Repository property to the name of an alternate repository. +# +# The test task invokes Pester to run any Pester tests in your +# workspace folder. Name your test scripts .Tests.ps1 +# and Pester will find and run the tests contained in the files. +# +# You can run this build script directly using the invoke-psake +# command which will execute the build task. This task "builds" +# a temporary folder from which the module can be published. +# +# PS C:\> invoke-psake build.ps1 +# +# You can run your Pester tests (if any) by running the following command. +# +# PS C:\> invoke-psake build.ps1 -taskList test +# +# You can execute the publish task with the following command. Note that +# the publish task will run the test task first. The Pester tests must pass +# before the publish task will run. The first time you run the publish +# command, you will be prompted to enter your PowerShell Gallery NuGetApiKey. +# After entering the key, it is encrypted and stored so you will not have to +# enter it again. +# +# PS C:\> invoke-psake build.ps1 -taskList publish +# +# You can verify the stored and encrypted NuGetApiKey by running the following +# command. This will display your NuGetApiKey in plain text! +# +# PS C:\> invoke-psake build.ps1 -taskList showKey +# +# You can store a new NuGetApiKey with this command. You can leave off +# the -properties parameter and you'll be prompted for the key. +# +# PS C:\> invoke-psake build.ps1 -taskList storeKey -properties @{NuGetApiKey='test123'} +# + +############################################################################### +# Customize these properties for your module. +############################################################################### +Properties { + # The name of your module should match the basename of the PSD1 file. + $ModuleName = (Get-Item $PSScriptRoot\*.psd1)[0].BaseName + + # Path to the release notes file. Set to $null if the release notes reside in the manifest file. + $ReleaseNotesPath = "$PSScriptRoot\ReleaseNotes.md" + + # The directory used to publish the module from. If you are using Git, the + # $PublishDir should be ignored if it is under the workspace directory. + $PublishDir = "$PSScriptRoot\Release\$ModuleName" + + # The following items will not be copied to the $PublishDir. + # Add items that should not be published with the module. + $Exclude = @( + 'Release', + 'Tests', + '.git*', + '.vscode', + # The next three files are unique to this examples dir. + 'DebugTest.ps1', + 'Stop*.ps1', + 'Readme.md', + (Split-Path $PSCommandPath -Leaf) + ) + + # Name of the repository you wish to publish to. Default repo is the PSGallery. + $PublishRepository = $null + + # Your NuGet API key for the PSGallery. Leave it as $null and the first time + # you publish you will be prompted to enter your API key. The build will + # store the key encrypted in a file, so that on subsequent publishes you + # will no longer be prompted for the API key. + $NuGetApiKey = $null + $EncryptedApiKeyPath = "$env:LOCALAPPDATA\vscode-powershell\NuGetApiKey.clixml" +} + +############################################################################### +# Customize these tasks for performing operations before and/or after publish. +############################################################################### +Task PrePublish { +} + +Task PostPublish { +} + +############################################################################### +# Core task implementations - this possibly "could" ship as part of the +# vscode-powershell extension and then get dot sourced into this file. +############################################################################### +Task default -depends Build + +Task Publish -depends Test, PrePublish, PublishImpl, PostPublish { +} + +Task PublishImpl -depends Test -requiredVariables PublishDir, EncryptedApiKeyPath { + $NuGetApiKey = Get-NuGetApiKey $NuGetApiKey $EncryptedApiKeyPath + + $publishParams = @{ + Path = $PublishDir + NuGetApiKey = $NuGetApiKey + } + + if ($PublishRepository) { + $publishParams['Repository'] = $PublishRepository + } + + # Consider not using -ReleaseNotes parameter when Update-ModuleManifest has been fixed. + if ($ReleaseNotesPath) { + $publishParams['ReleaseNotes'] = @(Get-Content $ReleaseNotesPath) + } + + Publish-Module @publishParams -WhatIf +} + +Task Test -depends Build { + Import-Module Pester + Invoke-Pester $PSScriptRoot +} + +Task Build -depends Clean -requiredVariables PublishDir, Exclude, ModuleName { + Copy-Item $PSScriptRoot\* -Destination $PublishDir -Recurse -Exclude $Exclude + + # Get contents of the ReleaseNotes file and update the copied module manifest file + # with the release notes. + # DO NOT USE UNTIL UPDATE-MODULEMANIFEST IS FIXED - HORRIBLY BROKEN RIGHT NOW. + # if ($ReleaseNotesPath) { + # $releaseNotes = @(Get-Content $ReleaseNotesPath) + # Update-ModuleManifest -Path $PublishDir\${ModuleName}.psd1 -ReleaseNotes $releaseNotes + # } +} + +Task Clean -depends Init -requiredVariables PublishDir { + # Sanity check the dir we are about to "clean". If $PublishDir were to + # inadvertently get set to $null, the Remove-Item commmand removes the + # contents of \*. That's a bad day. Ask me how I know? :-( + if ($PublishDir.Contains($PSScriptRoot)) { + Remove-Item $PublishDir\* -Recurse -Force + } +} + +Task Init -requiredVariables PublishDir { + if (!(Test-Path $PublishDir)) { + $null = New-Item $PublishDir -ItemType Directory + } +} + +Task StoreKey -requiredVariables EncryptedApiKeyPath { + if (Test-Path $EncryptedApiKeyPath) { + Remove-Item $EncryptedApiKeyPath + } + + $null = Get-NuGetApiKey $NuGetApiKey $EncryptedApiKeyPath + "The NuGetApiKey has been stored in $EncryptedApiKeyPath" +} + +Task ShowKey -requiredVariables EncryptedApiKeyPath { + $NuGetApiKey = Get-NuGetApiKey $NuGetApiKey $EncryptedApiKeyPath + "The stored NuGetApiKey is: $NuGetApiKey" +} + +Task ? -description 'Lists the available tasks' { + "Available tasks:" + $psake.context.Peek().tasks.Keys | Sort +} + +############################################################################### +# Helper functions +############################################################################### +function Get-NuGetApiKey($NuGetApiKey, $EncryptedApiKeyPath) { + $storedKey = $null + if (!$NuGetApiKey) { + if (Test-Path $EncryptedApiKeyPath) { + $storedKey = Import-Clixml $EncryptedApiKeyPath | ConvertTo-SecureString + $cred = New-Object -TypeName PSCredential -ArgumentList 'kh',$storedKey + $NuGetApiKey = $cred.GetNetworkCredential().Password + Write-Verbose "Retrieved encrypted NuGetApiKey from $EncryptedApiKeyPath" + } + else { + $cred = Get-Credential -Message "Enter your NuGet API Key in the password field" -UserName "user" + $apiKeySS = $cred.Password + $NuGetApiKey = $cred.GetNetworkCredential().Password + } + } + + if (!$storedKey) { + # Store encrypted NuGet API key to use for future invocations + if (!$apiKeySS) { + $apiKeySS = ConvertTo-SecureString -String $NuGetApiKey -AsPlainText -Force + } + + $parentDir = Split-Path $EncryptedApiKeyPath -Parent + if (!(Test-Path -Path $parentDir)) { + $null = New-Item -Path $parentDir -ItemType Directory + } + + $apiKeySS | ConvertFrom-SecureString | Export-Clixml $EncryptedApiKeyPath + Write-Verbose "Stored encrypted NuGetApiKey to $EncryptedApiKeyPath" + } + + $NuGetApiKey +} diff --git a/examples/DebugTest.ps1 b/examples/DebugTest.ps1 index 68f648b1d5e746cd08444da3e53fa415c17e2e76..b5c3422cad874fdaba3becba7b4e5253fd8094e9 100644 GIT binary patch delta 307 zcmY+Ay$%6E6ot#;b@#jWg4r znS0N@-??{Y&WTGZ_I|0PC8X-+m2br*4(gFsH~(0KL?1rS5DQEh=h!h1nFmy>zn;hH zjJ+~D0UWXmDhV4Nl?|8qn2rhKmaOJ&Lln?rRo6Ra=7f9*CuhW%phTM^r?k6Rv+8h6 zsP37OzTy8Zd}4buRd3a*N@i#_e&1pL?lF0TREZ9W3OyUf8tVLqs4130Mpto)o+29! GV!aP_Y(K~V delta 82 zcmbQkK8=;_|36*^E{2IrcFaI}qN6;!0s|OMjJM|m$v`-B+b8=lWwC+;swXotOHTa7 RH~9fm3`{XdXmSX%2LRm}5rqH% diff --git a/examples/PathProcessingNoWildcards.ps1 b/examples/PathProcessingNoWildcards.ps1 index 8773db94b7..25889fd301 100644 --- a/examples/PathProcessingNoWildcards.ps1 +++ b/examples/PathProcessingNoWildcards.ps1 @@ -1,3 +1,16 @@ +<# +.SYNOPSIS + Demonstrates how to write a command that works with paths that do + not allow wildards but must exist. +.DESCRIPTION + This command does not require a LiteralPath parameter because the + Path parameter can handle paths that use wildcard characters. That's + because this command does not "resolve" the supplied path. +.EXAMPLE + C:\PS> Import-FileNoWildcard -Path ..\..\Tests\foo[1].txt -WhatIf + This example shows how the Path parameter can handle a path that happens + to use the wildcard chars "[" and "]". +#> function Import-FileNoWildcard { [CmdletBinding(SupportsShouldProcess=$true)] param( @@ -13,10 +26,10 @@ function Import-FileNoWildcard { [string[]] $Path ) - + begin { } - + process { # Modify [CmdletBinding()] to [CmdletBinding(SupportsShouldProcess=$true)] $paths = @() @@ -28,11 +41,11 @@ function Import-FileNoWildcard { $psCmdlet.WriteError($errRecord) continue } - + # Resolve any relative paths $paths += $psCmdlet.SessionState.Path.GetUnresolvedProviderPathFromPSPath($aPath) } - + foreach ($aPath in $paths) { if ($pscmdlet.ShouldProcess($aPath, 'Operation')) { # Process each path @@ -40,7 +53,7 @@ function Import-FileNoWildcard { } } } - + end { } } \ No newline at end of file diff --git a/examples/PathProcessingNonExistingPaths.ps1 b/examples/PathProcessingNonExistingPaths.ps1 index d8a06e1ecc..d11e025303 100644 --- a/examples/PathProcessingNonExistingPaths.ps1 +++ b/examples/PathProcessingNonExistingPaths.ps1 @@ -1,3 +1,18 @@ +<# +.SYNOPSIS + Demonstrates how to write a command that works with paths that do + not allow wildards and do not have to exist. +.DESCRIPTION + This command does not require a LiteralPath parameter because the + Path parameter can handle paths that use wildcard characters. That's + because this command does not "resolve" the supplied path. This command + also does not verify the path exists because the point of the command is + to create a new file at the specified path. +.EXAMPLE + C:\PS> New-File -Path xyzzy[1].txt -WhatIf + This example shows how the Path parameter can handle a path that happens + to use the wildcard chars "[" and "]" and does not exist to start with. +#> function New-File { [CmdletBinding(SupportsShouldProcess=$true)] param( @@ -13,10 +28,10 @@ function New-File { [string[]] $Path ) - + begin { } - + process { # Modify [CmdletBinding()] to [CmdletBinding(SupportsShouldProcess=$true)] $paths = @() @@ -24,7 +39,7 @@ function New-File { # Resolve any relative paths $paths += $psCmdlet.SessionState.Path.GetUnresolvedProviderPathFromPSPath($aPath) } - + foreach ($aPath in $paths) { if ($pscmdlet.ShouldProcess($aPath, 'Operation')) { # Process each path @@ -32,7 +47,7 @@ function New-File { } } } - + end { } } \ No newline at end of file diff --git a/examples/PathProcessingWildcards.ps1 b/examples/PathProcessingWildcards.ps1 index bc88d2d0bb..6ba85f9e67 100644 --- a/examples/PathProcessingWildcards.ps1 +++ b/examples/PathProcessingWildcards.ps1 @@ -1,3 +1,19 @@ +<# +.SYNOPSIS + Demonstrates how to write a command that works with paths that allow + wildards and must exist. +.DESCRIPTION + This command also demonstrates how you need to supply a LiteralPath + parameter when your Path parameter accepts wildcards. This is in order + to handle paths like foo[1].txt. If you pass this path to the Path + parameter, it will fail to find this file because "[1]" is interpreted + as a wildcard spec e.g it resolves to foo1.txt. The LiteralPath parameter + is used in this case as it does not interpret wildcard chars. +.EXAMPLE + C:\PS> Import-FileWildcard -LiteralPath ..\..\Tests\foo[1].txt -WhatIf + This example shows how to use the LiteralPath parameter with a path + that happens to use the wildcard chars "[" and "]". +#> function Import-FileWildcard { [CmdletBinding(SupportsShouldProcess=$true, DefaultParameterSetName='Path')] param( @@ -12,7 +28,7 @@ function Import-FileWildcard { [SupportsWildcards()] [string[]] $Path, - + # Specifies a path to one or more locations. Unlike the Path parameter, the value of the LiteralPath parameter is # used exactly as it is typed. No characters are interpreted as wildcards. If the path includes escape characters, # enclose it in single quotation marks. Single quotation marks tell Windows PowerShell not to interpret any @@ -27,10 +43,10 @@ function Import-FileWildcard { [string[]] $LiteralPath ) - + begin { } - + process { # Modify [CmdletBinding()] to [CmdletBinding(SupportsShouldProcess=$true, DefaultParameterSetName='Path')] $paths = @() @@ -43,7 +59,7 @@ function Import-FileWildcard { $psCmdlet.WriteError($errRecord) continue } - + # Resolve any wildcards that might be in the path $provider = $null $paths += $psCmdlet.SessionState.Path.GetResolvedProviderPathFromPSPath($aPath, [ref]$provider) @@ -58,12 +74,12 @@ function Import-FileWildcard { $psCmdlet.WriteError($errRecord) continue } - + # Resolve any relative paths $paths += $psCmdlet.SessionState.Path.GetUnresolvedProviderPathFromPSPath($aPath) } } - + foreach ($aPath in $paths) { if ($pscmdlet.ShouldProcess($aPath, 'Operation')) { # Process each path @@ -71,7 +87,7 @@ function Import-FileWildcard { } } } - + end { } } \ No newline at end of file diff --git a/examples/README.md b/examples/README.md index 3f2c4cf281..59384650cb 100644 --- a/examples/README.md +++ b/examples/README.md @@ -3,7 +3,10 @@ *NOTE: For a more comfortable reading experience, use the key combination `Ctrl+Shift+V`* This folder contains a few basic PowerShell script files that you can use -to experiment with the new PowerShell editing and debugging capabilities. +to experiment with the new PowerShell editing debugging capabilities as well +as an early preview of a workflow for publishing a module to the PowerShell +Gallery. + Here are some ideas for what you can try with these scripts: ## Language Features @@ -84,6 +87,42 @@ You can also set the parameter explicitly e.g.: `"cwd": "C:\\Users\\JSnover\\Documents\\MonadUberAlles"` +## Module Publishing Preview + +### Requirements: +* [PSake](https://github.com/psake/psake) - install PSake with the command: + + PS C:\\> `Install-Module PSake -Scope CurrentUser` + +The are two files (Build.ps1 and tasks.json) that facilitate building a directory from which +to publish a module from and then publishing from that directory. The act of creating or +building this "Release" directory can be executed with the key combination `Ctrl+Shift+B` +which is the `Build` keyboard shortcut in Visual Studio Code. + +When you execute the `Build` command, the build task from the `.vscode\tasks.json` file +is executed. This task invokes PSake on the file `Build.ps1`. This file +contains items you might want to customize such as `$PublishRepository` or the +`$ReleaseNotesPath`. It also contains two PSake tasks which you might want to +customize: `PrePublish` and `PostPublish`. If you sign your scripts, you can +use the `PrePublish` task and the script in it will get executed after the build +but before the `Publish` task is executed. + +To execute the `Publish` task, press `Ctrl+P` then type `"task publish"` and press `Enter`. + +NOTE: the `Publish` task does not actually publish to allow for experimentation. +If you wish to publish, remove the `-WhatIf` parameter on the `Publish-Module` command +in Build.ps1. + +NOTE: the very first time you execute the publish task, you will be prompted for +a NuGet API Key. This would normally be the NuGet API Key you are assigned when you +create an account of the [PowerShell Gallery](https://www.powershellgallery.com/). +However since this is just an example of how this feature could work in the future, +you can supply any string you want. You will need to enter the api key string at the +bottom of the Debug Console window. + +For more details on how this works, inspect the `.vscode\tasks.json` file and the +`Build.ps1` file. + ## Feedback We would love to hear your feedback! Please post feature requests or issue diff --git a/examples/ReleaseNotes.md b/examples/ReleaseNotes.md new file mode 100644 index 0000000000..44a2053ddc --- /dev/null +++ b/examples/ReleaseNotes.md @@ -0,0 +1,11 @@ +## What is New in SampleModule 1.0 +March 9, 2016 + +* Note: Due to a bug in `Update-ModuleManifest` you cannot put a single +quote in your release notes. + +* Initial release with support for New-File, Import-FileNoWildcard and +Import-FileWildcard commands. + +### Feedback +Please send your feedback to http://github.com/____.com/issues \ No newline at end of file diff --git a/examples/SampleModule.psd1 b/examples/SampleModule.psd1 new file mode 100644 index 0000000000000000000000000000000000000000..ba441347581c305bed4503ed88f8740def4e03c7 GIT binary patch literal 7694 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 H?;QUE%{|Y; literal 0 HcmV?d00001 diff --git a/examples/SampleModule.psm1 b/examples/SampleModule.psm1 new file mode 100644 index 0000000000..1eb7d5ec62 --- /dev/null +++ b/examples/SampleModule.psm1 @@ -0,0 +1,4 @@ + +. $PSScriptRoot\PathProcessingNonExistingPaths.ps1 +. $PSScriptRoot\PathProcessingNoWildcards.ps1 +. $PSScriptRoot\PathProcessingWildcards.ps1 diff --git a/examples/Stop-Process2.ps1 b/examples/Stop-Process2.ps1 index 9fa66141d6..4174844499 100644 --- a/examples/Stop-Process2.ps1 +++ b/examples/Stop-Process2.ps1 @@ -8,40 +8,30 @@ .EXAMPLE Another example of how to use this cmdlet #> -function Stop-Process2 -{ +function Stop-Process2 { [CmdletBinding(SupportsShouldProcess = $true)] [Alias()] [OutputType([int])] - Param - ( + param( # Param1 help description [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, Position=0)] $Name ) - - Begin - { - } - Process - { + + process { if ($PSCmdlet.ShouldProcess("")) { $processes = Get-Process -Name $Name - foreach ($process in $processes) - { + foreach ($process in $processes) { $id = $process.Id $name = $process.Name Write-Output "Killing $name ($id)" - + $process.Kill(); - + Start-Sleep -Seconds 1 } } } - End - { - } } \ No newline at end of file diff --git a/examples/StopTest.ps1 b/examples/StopTest.ps1 index 0884e47a5a..4e0291a978 100644 --- a/examples/StopTest.ps1 +++ b/examples/StopTest.ps1 @@ -1,4 +1,3 @@ - . .\Stop-Process2.ps1 notepad.exe diff --git a/examples/PathProcessing.Tests.ps1 b/examples/Tests/PathProcessing.Tests.ps1 similarity index 50% rename from examples/PathProcessing.Tests.ps1 rename to examples/Tests/PathProcessing.Tests.ps1 index 9d5cd35b58..7e751a59fe 100644 --- a/examples/PathProcessing.Tests.ps1 +++ b/examples/Tests/PathProcessing.Tests.ps1 @@ -8,91 +8,92 @@ # test task runner defined in .vscode\tasks.json. # This (empty) file is required by some of the tests. -$null = New-Item -Path 'foo[1].txt' -Force +$null = New-Item -Path "$PSScriptRoot\foo[1].txt" -Force + +Import-Module $PSScriptRoot\..\SampleModule.psd1 + +$WorkspaceRoot = $pwd -. $PSScriptRoot\PathProcessingNonExistingPaths.ps1 Describe 'Verify Path Processing for Non-existing Paths Allowed Impl' { It 'Processes non-wildcard absolute path to non-existing file via -Path param' { - New-File -Path $PSScriptRoot\ReadmeNew.md | Should Be "$PSScriptRoot\READMENew.md" + New-File -Path $WorkspaceRoot\ReadmeNew.md | Should Be "$WorkspaceRoot\READMENew.md" } It 'Processes multiple absolute paths via -Path param' { - New-File -Path $PSScriptRoot\Readme.md, $PSScriptRoot\XYZZY.ps1 | - Should Be @("$PSScriptRoot\README.md", "$PSScriptRoot\XYZZY.ps1") + New-File -Path $WorkspaceRoot\Readme.md, $WorkspaceRoot\XYZZY.ps1 | + Should Be @("$WorkspaceRoot\README.md", "$WorkspaceRoot\XYZZY.ps1") } It 'Processes relative path via -Path param' { - New-File -Path ..\examples\READMENew.md | Should Be "$PSScriptRoot\READMENew.md" + New-File -Path ..\Examples\READMENew.md | Should Be "$WorkspaceRoot\READMENew.md" } It 'Processes multiple relative path via -Path param' { - New-File -Path ..\examples\README.md, XYZZY.ps1 | - Should Be @("$PSScriptRoot\README.md", "$PSScriptRoot\XYZZY.ps1") + New-File -Path ..\Examples\README.md, XYZZY.ps1 | + Should Be @("$WorkspaceRoot\README.md", "$WorkspaceRoot\XYZZY.ps1") } It 'Should accept pipeline input to Path' { - Get-ChildItem -LiteralPath "$pwd\foo[1].txt" | New-File | Should Be "$PSScriptRoot\foo[1].txt" + Get-ChildItem -LiteralPath "$WorkspaceRoot\Tests\foo[1].txt" | New-File | Should Be "$PSScriptRoot\foo[1].txt" } } -. $PSScriptRoot\PathProcessingNoWildcards.ps1 Describe 'Verify Path Processing for NO Wildcards Allowed Impl' { It 'Processes non-wildcard absolute path via -Path param' { - Import-FileNoWildcard -Path $PSScriptRoot\Readme.md | Should Be "$PSScriptRoot\README.md" + Import-FileNoWildcard -Path $WorkspaceRoot\Readme.md | Should Be "$WorkspaceRoot\README.md" } It 'Processes multiple absolute paths via -Path param' { - Import-FileNoWildcard -Path $PSScriptRoot\Readme.md, $PSScriptRoot\PathProcessingWildcards.ps1 | - Should Be @("$PSScriptRoot\README.md", "$PSScriptRoot\PathProcessingWildcards.ps1") + Import-FileNoWildcard -Path $WorkspaceRoot\Readme.md, $WorkspaceRoot\PathProcessingWildcards.ps1 | + Should Be @("$WorkspaceRoot\README.md", "$WorkspaceRoot\PathProcessingWildcards.ps1") } It 'Processes relative path via -Path param' { - Import-FileNoWildcard -Path ..\examples\README.md | Should Be "$PSScriptRoot\README.md" + Import-FileNoWildcard -Path ..\examples\README.md | Should Be "$WorkspaceRoot\README.md" } It 'Processes multiple relative path via -Path param' { Import-FileNoWildcard -Path ..\examples\README.md, .vscode\launch.json | - Should Be @("$PSScriptRoot\README.md", "$PSScriptRoot\.vscode\launch.json") + Should Be @("$WorkspaceRoot\README.md", "$WorkspaceRoot\.vscode\launch.json") } It 'Should accept pipeline input to Path' { - Get-ChildItem -LiteralPath "$pwd\foo[1].txt" | Import-FileNoWildcard | Should Be "$PSScriptRoot\foo[1].txt" + Get-ChildItem -LiteralPath "$WorkspaceRoot\Tests\foo[1].txt" | Import-FileNoWildcard | Should Be "$PSScriptRoot\foo[1].txt" } } -. $PSScriptRoot\PathProcessingWildcards.ps1 Describe 'Verify Path Processing for Wildcards Allowed Impl' { It 'Processes non-wildcard absolute path via -Path param' { - Import-FileWildcard -Path $PSScriptRoot\Readme.md | Should Be "$PSScriptRoot\README.md" + Import-FileWildcard -Path $WorkspaceRoot\Readme.md | Should Be "$WorkspaceRoot\README.md" } It 'Processes multiple absolute paths via -Path param' { - Import-FileWildcard -Path $PSScriptRoot\Readme.md, $PSScriptRoot\PathProcessingWildcards.ps1 | - Should Be @("$PSScriptRoot\README.md", "$PSScriptRoot\PathProcessingWildcards.ps1") + Import-FileWildcard -Path $WorkspaceRoot\Readme.md, $WorkspaceRoot\PathProcessingWildcards.ps1 | + Should Be @("$WorkspaceRoot\README.md", "$WorkspaceRoot\PathProcessingWildcards.ps1") } It 'Processes wildcard absolute path via -Path param' { - Import-FileWildcard -Path $PSScriptRoot\*.md | Should Be "$PSScriptRoot\README.md" + Import-FileWildcard -Path $WorkspaceRoot\*.psd1 | Should Be "$WorkspaceRoot\SampleModule.psd1" } It 'Processes wildcard relative path via -Path param' { - Import-FileWildcard -Path *.md | Should Be "$PSScriptRoot\README.md" + Import-FileWildcard -Path *.psd1 | Should Be "$WorkspaceRoot\SampleModule.psd1" } It 'Processes relative path via -Path param' { - Import-FileWildcard -Path ..\examples\README.md | Should Be "$PSScriptRoot\README.md" + Import-FileWildcard -Path ..\examples\README.md | Should Be "$WorkspaceRoot\README.md" } It 'Processes multiple relative path via -Path param' { Import-FileWildcard -Path ..\examples\README.md, .vscode\launch.json | - Should Be @("$PSScriptRoot\README.md", "$PSScriptRoot\.vscode\launch.json") + Should Be @("$WorkspaceRoot\README.md", "$WorkspaceRoot\.vscode\launch.json") } It 'DefaultParameterSet should be Path' { - Import-FileWildcard *.md | Should Be "$PSScriptRoot\README.md" + Import-FileWildcard *.psd1 | Should Be "$WorkspaceRoot\SampleModule.psd1" } It 'Should process absolute literal paths via -LiteralPath param'{ Import-FileWildcard -LiteralPath "$PSScriptRoot\foo[1].txt" | Should Be "$PSScriptRoot\foo[1].txt" } It 'Should process relative literal paths via -LiteralPath param'{ - Import-FileWildcard -LiteralPath "..\examples\foo[1].txt" | Should Be "$PSScriptRoot\foo[1].txt" + Import-FileWildcard -LiteralPath "..\examples\Tests\foo[1].txt" | Should Be "$PSScriptRoot\foo[1].txt" } It 'Should process multiple literal paths via -LiteralPath param'{ - Import-FileWildcard -LiteralPath "..\examples\foo[1].txt", "$PSScriptRoot\README.md" | - Should Be @("$PSScriptRoot\foo[1].txt", "$PSScriptRoot\README.md") + Import-FileWildcard -LiteralPath "..\examples\Tests\foo[1].txt", "$WorkspaceRoot\README.md" | + Should Be @("$PSScriptRoot\foo[1].txt", "$WorkspaceRoot\README.md") } It 'Should accept pipeline input to LiteralPath' { - Get-ChildItem -LiteralPath "$pwd\foo[1].txt" | Import-FileWildcard | Should Be "$PSScriptRoot\foo[1].txt" + Get-ChildItem -LiteralPath "$WorkspaceRoot\Tests\foo[1].txt" | Import-FileWildcard | Should Be "$PSScriptRoot\foo[1].txt" } } diff --git a/examples/Tests/SampleModule.Tests.ps1 b/examples/Tests/SampleModule.Tests.ps1 new file mode 100644 index 0000000000..40985d6f63 --- /dev/null +++ b/examples/Tests/SampleModule.Tests.ps1 @@ -0,0 +1,9 @@ +$ModuleManifestName = 'SampleModule.psd1' +Import-Module $PSScriptRoot\..\$ModuleManifestName + +Describe 'Module Manifest Tests' { + It 'Passes Test-ModuleManifest' { + Test-ModuleManifest -Path $PSScriptRoot\..\$ModuleManifestName + $? | Should Be $true + } +} diff --git a/examples/en-US/about_SampleModule.help.txt b/examples/en-US/about_SampleModule.help.txt new file mode 100644 index 0000000000..7dc37ae5aa --- /dev/null +++ b/examples/en-US/about_SampleModule.help.txt @@ -0,0 +1,15 @@ +TOPIC + SampleModule 1.0.0 + +SHORT DESCRIPTION + You should considering providing an introduction and overview of your + module here. + +LONG DESCRIPTION + Discuss what the "primary" commands are in your module especially if + there are many commands. Discuss how to get started using this module + providing examples where appropriate. + +YOUR HEADER HERE + About topics in PowerShell are free-form text. Add headers to your + about topic as necessary. \ No newline at end of file From 1b9cae6be91e786840a2c15a7c7460dc711a2124 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Wed, 9 Mar 2016 23:06:52 -0700 Subject: [PATCH 2/4] Fixed a few typos. --- examples/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/README.md b/examples/README.md index 59384650cb..b4816312a6 100644 --- a/examples/README.md +++ b/examples/README.md @@ -111,14 +111,14 @@ To execute the `Publish` task, press `Ctrl+P` then type `"task publish"` and pre NOTE: the `Publish` task does not actually publish to allow for experimentation. If you wish to publish, remove the `-WhatIf` parameter on the `Publish-Module` command -in Build.ps1. +in Build.ps1. But make sure you've modified the module manifest (psd1) file or supplied your own +in order to give your module a unique name and guid. NOTE: the very first time you execute the publish task, you will be prompted for a NuGet API Key. This would normally be the NuGet API Key you are assigned when you -create an account of the [PowerShell Gallery](https://www.powershellgallery.com/). +register for an account on the [PowerShell Gallery](https://www.powershellgallery.com/). However since this is just an example of how this feature could work in the future, -you can supply any string you want. You will need to enter the api key string at the -bottom of the Debug Console window. +you can supply any string you want. For more details on how this works, inspect the `.vscode\tasks.json` file and the `Build.ps1` file. From 4416d3387bf28b2493c08f7a58c0832491ffa08d Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Thu, 10 Mar 2016 09:38:04 -0700 Subject: [PATCH 3/4] Tweaked NuGet API Key prompt message. Also added some output text just before calling Publish-Module to see where in the Publish task it occassionally hangs. Although now that I put this text in, it doesn't appear to hang on me now. Go figure. --- examples/.vscode/tasks.json | 12 ++++++++---- examples/Build.ps1 | 3 ++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/examples/.vscode/tasks.json b/examples/.vscode/tasks.json index 2082b04be0..071a48339c 100644 --- a/examples/.vscode/tasks.json +++ b/examples/.vscode/tasks.json @@ -49,35 +49,39 @@ { "taskName": "Clean", "suppressTaskName": true, + "showOutput": "always", "args": [ "Write-Host 'Invoking PSake...'; Invoke-PSake build.ps1 -taskList Clean;", - "Invoke-Command { Write-Host \"Completed Clean task in task runner.\" }" + "Invoke-Command { Write-Host 'Completed Clean task in task runner.' }" ] }, { "taskName": "Build", "suppressTaskName": true, "isBuildCommand": true, + "showOutput": "always", "args": [ "Write-Host 'Invoking PSake...'; Invoke-PSake build.ps1 -taskList Build;", - "Invoke-Command { Write-Host \"Completed Build task in task runner.\" }" + "Invoke-Command { Write-Host 'Completed Build task in task runner.' }" ] }, { "taskName": "Publish", "suppressTaskName": true, + "showOutput": "always", "args": [ "Write-Host 'Invoking PSake...'; Invoke-PSake build.ps1 -taskList Publish;", - "Invoke-Command { Write-Host \"Completed Publish task in task runner.\" }" + "Invoke-Command { Write-Host 'Completed Publish task in task runner.' }" ] }, { "taskName": "Test", "suppressTaskName": true, "isTestCommand": true, + "showOutput": "always", "args": [ "Write-Host 'Invoking Pester...'; Invoke-Pester -PesterOption @{IncludeVSCodeMarker=$true};", - "Invoke-Command { Write-Host \"Completed Test task in task runner.\" }" + "Invoke-Command { Write-Host 'Completed Test task in task runner.' }" ], "problemMatcher": [ { diff --git a/examples/Build.ps1 b/examples/Build.ps1 index 3f782d775b..d8aa852c04 100644 --- a/examples/Build.ps1 +++ b/examples/Build.ps1 @@ -134,6 +134,7 @@ Task PublishImpl -depends Test -requiredVariables PublishDir, EncryptedApiKeyPat $publishParams['ReleaseNotes'] = @(Get-Content $ReleaseNotesPath) } + "Calling Publish-Module..." Publish-Module @publishParams -WhatIf } @@ -201,7 +202,7 @@ function Get-NuGetApiKey($NuGetApiKey, $EncryptedApiKeyPath) { Write-Verbose "Retrieved encrypted NuGetApiKey from $EncryptedApiKeyPath" } else { - $cred = Get-Credential -Message "Enter your NuGet API Key in the password field" -UserName "user" + $cred = Get-Credential -Message "Enter your NuGet API Key in the password field (or nothing, this isn't used yet in the preview)" -UserName "user" $apiKeySS = $cred.Password $NuGetApiKey = $cred.GetNetworkCredential().Password } From 46ef534442c1308e5be23fcbbd30f7efb88fbad5 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Thu, 10 Mar 2016 09:47:29 -0700 Subject: [PATCH 4/4] Minor tweaks to the examples readme.md file. --- examples/README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/README.md b/examples/README.md index b4816312a6..9460d1fa59 100644 --- a/examples/README.md +++ b/examples/README.md @@ -13,11 +13,12 @@ Here are some ideas for what you can try with these scripts: - **Integrated syntax checks** from the PowerShell engine and **integrated rule-based analysis** using PowerShell Script Analyzer - - Try opening `DebugTest.ps1` and `StopTest.ps1` by double-clicking on their - file names. You will see red and green squiggles for rule-based checks. - You can introduce a syntax error somewhere to see the red squiggle for - that as well. To see a list of all errors and warnings, try pressing - `Ctrl+Shift+M`. + - Try opening `DebugTest.ps1` by double-clicking on its file name in the + Explorer view. You will see a green squiggle on the function name `Do-Work` + indicating that `Do` is not an approved verb. These rule-based checks use + PSScriptAnalyzer to analyze/lint your scripts. You can introduce a syntax + error somewhere to see a red squiggle for that as well. To see a list of + all errors and warnings, try pressing `Ctrl+Shift+M`. - **Go to definition `(F12)`** and **Peek definition `(Alt+F12)`** for cmdlet and variable names - Try this on the `Stop-Process2` cmdlet in `StopTest.ps1`