├── .gitignore
├── .vscode
└── launch.json
├── GitVersion.yml
├── LICENSE
├── Origin
└── Publish-PSArtifactUtility.ps1
├── ThirdPartyNotices.txt
├── build
├── build.ps1
└── tasks
│ ├── BuildModule.task.ps1
│ ├── Clean.task.ps1
│ ├── CleanAll.task.ps1
│ ├── CopyModuleAssets.task.ps1
│ ├── CopyModuleBaseFiles.task.ps1
│ ├── CopyModuleSourceFiles.task.ps1
│ ├── CreatePaths.task.ps1
│ ├── ImportDependencyConfig.task.ps1
│ ├── ImportModule.task.ps1
│ ├── ImportPSModules.task.ps1
│ ├── Initialize.task.ps1
│ ├── InstallDependencies.task.ps1
│ ├── InstallDependenciesPS.task.ps1
│ ├── PublishPSModuleNuget.task.ps1
│ ├── RegisterPSRepository.task.ps1
│ ├── UpdateExportFunctionsAndAliases.task.ps1
│ └── VersionBump.task.ps1
├── config
└── dependencies.json
├── scripts
└── New-ModuleManifest.ps1
└── src
└── PSPublishHelper
├── PSPublishHelper.psd1
├── PSPublishHelper.psm1
├── private
├── Copy-PSModule.ps1
├── Format-PSModuleDependency.ps1
├── Get-AvailableRoleCapabilityName.ps1
├── Get-EscapedString.ps1
├── Get-ExportedDscResources.ps1
├── Get-NupkgFilePath.ps1
├── Get-NuspecContents.ps1
├── Get-NuspecFilePath.ps1
├── Get-PSModuleManifestData.ps1
├── Get-TemporaryPath.ps1
├── Resolve-NugetCommand.ps1
├── Resolve-PSData.ps1
├── Resolve-PSModule.ps1
├── Resolve-PSModuleDependency.ps1
├── Resolve-PSModuleInfo.ps1
├── Resolve-PSModuleTags.ps1
└── Resolve-PSModuleVersion.ps1
└── public
└── Publish-PSModuleNuget.ps1
/.gitignore:
--------------------------------------------------------------------------------
1 | bin/
2 | psmodules/
3 | tmp/
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "PowerShell",
9 | "request": "launch",
10 | "name": "PowerShell Launch Current File",
11 | "script": "${file}",
12 | "args": [],
13 | "cwd": "${file}"
14 | },
15 | {
16 | "type": "PowerShell",
17 | "request": "launch",
18 | "name": "PowerShell Launch Current File in Temporary Console",
19 | "script": "${file}",
20 | "args": [],
21 | "cwd": "${file}",
22 | "createTemporaryIntegratedConsole": true
23 | },
24 | {
25 | "type": "PowerShell",
26 | "request": "launch",
27 | "name": "PowerShell Launch Current File w/Args Prompt",
28 | "script": "${file}",
29 | "args": [
30 | "${command:SpecifyScriptArgs}"
31 | ],
32 | "cwd": "${file}"
33 | },
34 | {
35 | "type": "PowerShell",
36 | "request": "attach",
37 | "name": "PowerShell Attach to Host Process",
38 | "processId": "${command:PickPSHostProcess}",
39 | "runspaceId": 1
40 | },
41 | {
42 | "type": "PowerShell",
43 | "request": "launch",
44 | "name": "PowerShell Interactive Session",
45 | "cwd": ""
46 | }
47 | ]
48 | }
--------------------------------------------------------------------------------
/GitVersion.yml:
--------------------------------------------------------------------------------
1 | assembly-versioning-scheme: 'MajorMinorPatchTag'
2 | assembly-informational-format: '{Major}.{Minor}.{Patch}{PreReleaseTagWithDash}+Sha.{Sha}.Date.{CommitDate}'
3 | commit-message-incrementing: MergeMessageOnly
4 | mode: ContinuousDeployment
5 | branches:
6 | master:
7 | regex: master
8 | tag: beta
9 | increment: Minor
10 | mode: ContinuousDeployment
11 | feature:
12 | regex: features?[/-]
13 | increment: Minor
14 | source-branches: ['master']
15 | mode: ContinuousDeployment
16 | release:
17 | regex: releases?[/-]
18 | increment: Patch
19 | source-branches: ['master']
20 | mode: ContinuousDeployment
21 |
22 | ignore:
23 | sha: []
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2019 Mark E. Kraus
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/Origin/Publish-PSArtifactUtility.ps1:
--------------------------------------------------------------------------------
1 | function Publish-PSArtifactUtility
2 | {
3 | [CmdletBinding(PositionalBinding=$false)]
4 | Param
5 | (
6 | [Parameter(Mandatory=$true, ParameterSetName='PublishModule')]
7 | [ValidateNotNullOrEmpty()]
8 | [PSModuleInfo]
9 | $PSModuleInfo,
10 |
11 | [Parameter(Mandatory=$true, ParameterSetName='PublishScript')]
12 | [ValidateNotNullOrEmpty()]
13 | [PSCustomObject]
14 | $PSScriptInfo,
15 |
16 | [Parameter(Mandatory=$true, ParameterSetName='PublishModule')]
17 | [ValidateNotNullOrEmpty()]
18 | [string]
19 | $ManifestPath,
20 |
21 | [Parameter(Mandatory=$true)]
22 | [ValidateNotNullOrEmpty()]
23 | [string]
24 | $Destination,
25 |
26 | [Parameter(Mandatory=$true)]
27 | [ValidateNotNullOrEmpty()]
28 | [string]
29 | $Repository,
30 |
31 | [Parameter(Mandatory=$true)]
32 | [ValidateNotNullOrEmpty()]
33 | [string]
34 | $NugetApiKey,
35 |
36 | [Parameter(Mandatory=$false)]
37 | [pscredential]
38 | $Credential,
39 |
40 | [Parameter(Mandatory=$true)]
41 | [ValidateNotNullOrEmpty()]
42 | [string]
43 | $NugetPackageRoot,
44 |
45 | [Parameter(ParameterSetName='PublishModule')]
46 | [Version]
47 | $FormatVersion,
48 |
49 | [Parameter(ParameterSetName='PublishModule')]
50 | [string]
51 | $ReleaseNotes,
52 |
53 | [Parameter(ParameterSetName='PublishModule')]
54 | [string[]]
55 | $Tags,
56 |
57 | [Parameter(ParameterSetName='PublishModule')]
58 | [Uri]
59 | $LicenseUri,
60 |
61 | [Parameter(ParameterSetName='PublishModule')]
62 | [Uri]
63 | $IconUri,
64 |
65 | [Parameter(ParameterSetName='PublishModule')]
66 | [Uri]
67 | $ProjectUri
68 | )
69 |
70 | Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe
71 |
72 | $PSArtifactType = $script:PSArtifactTypeModule
73 | $Name = $null
74 | $Description = $null
75 | $Version = ""
76 | $Author = $null
77 | $CompanyName = $null
78 | $Copyright = $null
79 | $requireLicenseAcceptance = "false"
80 |
81 | if($PSModuleInfo)
82 | {
83 | $Name = $PSModuleInfo.Name
84 | $Description = $PSModuleInfo.Description
85 | $Version = $PSModuleInfo.Version
86 | $Author = $PSModuleInfo.Author
87 | $CompanyName = $PSModuleInfo.CompanyName
88 | $Copyright = $PSModuleInfo.Copyright
89 |
90 | if($PSModuleInfo.PrivateData -and
91 | ($PSModuleInfo.PrivateData.GetType().ToString() -eq "System.Collections.Hashtable") -and
92 | $PSModuleInfo.PrivateData["PSData"] -and
93 | ($PSModuleInfo.PrivateData["PSData"].GetType().ToString() -eq "System.Collections.Hashtable")
94 | )
95 | {
96 | if( -not $Tags -and $PSModuleInfo.PrivateData.PSData["Tags"])
97 | {
98 | $Tags = $PSModuleInfo.PrivateData.PSData.Tags
99 | }
100 |
101 | if( -not $ReleaseNotes -and $PSModuleInfo.PrivateData.PSData["ReleaseNotes"])
102 | {
103 | $ReleaseNotes = $PSModuleInfo.PrivateData.PSData.ReleaseNotes
104 | }
105 |
106 | if( -not $LicenseUri -and $PSModuleInfo.PrivateData.PSData["LicenseUri"])
107 | {
108 | $LicenseUri = $PSModuleInfo.PrivateData.PSData.LicenseUri
109 | }
110 |
111 | if( -not $IconUri -and $PSModuleInfo.PrivateData.PSData["IconUri"])
112 | {
113 | $IconUri = $PSModuleInfo.PrivateData.PSData.IconUri
114 | }
115 |
116 | if( -not $ProjectUri -and $PSModuleInfo.PrivateData.PSData["ProjectUri"])
117 | {
118 | $ProjectUri = $PSModuleInfo.PrivateData.PSData.ProjectUri
119 | }
120 |
121 | if ($PSModuleInfo.PrivateData.PSData["Prerelease"])
122 | {
123 | $psmoduleInfoPrereleaseString = $PSModuleInfo.PrivateData.PSData.Prerelease
124 | if ($psmoduleInfoPrereleaseString -and $psmoduleInfoPrereleaseString.StartsWith("-"))
125 | {
126 | $Version = [string]$Version + $psmoduleInfoPrereleaseString
127 | }
128 | else
129 | {
130 | $Version = [string]$Version + "-" + $psmoduleInfoPrereleaseString
131 | }
132 | }
133 |
134 | if($PSModuleInfo.PrivateData.PSData["RequireLicenseAcceptance"])
135 | {
136 | $requireLicenseAcceptance = $PSModuleInfo.PrivateData.PSData.requireLicenseAcceptance.ToString().ToLower()
137 | if($requireLicenseAcceptance -eq "true")
138 | {
139 | if($FormatVersion -and ($FormatVersion.Major -lt $script:PSGetRequireLicenseAcceptanceFormatVersion.Major))
140 | {
141 | $message = $LocalizedData.requireLicenseAcceptanceNotSupported -f($FormatVersion)
142 | ThrowError -ExceptionName "System.InvalidOperationException" `
143 | -ExceptionMessage $message `
144 | -ErrorId "requireLicenseAcceptanceNotSupported" `
145 | -CallerPSCmdlet $PSCmdlet `
146 | -ErrorCategory InvalidData
147 | }
148 |
149 | if(-not $LicenseUri)
150 | {
151 | $message = $LocalizedData.LicenseUriNotSpecified
152 | ThrowError -ExceptionName "System.InvalidOperationException" `
153 | -ExceptionMessage $message `
154 | -ErrorId "LicenseUriNotSpecified" `
155 | -CallerPSCmdlet $PSCmdlet `
156 | -ErrorCategory InvalidData
157 | }
158 |
159 | $LicenseFilePath = Join-PathUtility -Path $NugetPackageRoot -ChildPath 'License.txt' -PathType File
160 | if(-not $LicenseFilePath -or -not (Test-Path -Path $LicenseFilePath -PathType Leaf))
161 | {
162 | $message = $LocalizedData.LicenseTxtNotFound
163 | ThrowError -ExceptionName "System.InvalidOperationException" `
164 | -ExceptionMessage $message `
165 | -ErrorId "LicenseTxtNotFound" `
166 | -CallerPSCmdlet $PSCmdlet `
167 | -ErrorCategory InvalidData
168 | }
169 |
170 | if((Get-Content -LiteralPath $LicenseFilePath) -eq $null)
171 | {
172 | $message = $LocalizedData.LicenseTxtEmpty
173 | ThrowError -ExceptionName "System.InvalidOperationException" `
174 | -ExceptionMessage $message `
175 | -ErrorId "LicenseTxtEmpty" `
176 | -CallerPSCmdlet $PSCmdlet `
177 | -ErrorCategory InvalidData
178 | }
179 |
180 | #RequireLicenseAcceptance is true, License uri and license.txt exist. Bump Up the FormatVersion
181 | if(-not $FormatVersion)
182 | {
183 | $FormatVersion = $script:CurrentPSGetFormatVersion
184 | }
185 | }
186 | elseif($requireLicenseAcceptance -ne "false")
187 | {
188 | $InvalidValueForRequireLicenseAcceptance = $LocalizedData.InvalidValueBoolean -f ($requireLicenseAcceptance, "requireLicenseAcceptance")
189 | Write-Warning -Message $InvalidValueForRequireLicenseAcceptance
190 | }
191 | }
192 | }
193 | }
194 | else
195 | {
196 | $PSArtifactType = $script:PSArtifactTypeScript
197 |
198 | $Name = $PSScriptInfo.Name
199 | $Description = $PSScriptInfo.Description
200 | $Version = $PSScriptInfo.Version
201 | $Author = $PSScriptInfo.Author
202 | $CompanyName = $PSScriptInfo.CompanyName
203 | $Copyright = $PSScriptInfo.Copyright
204 |
205 | if($PSScriptInfo.'Tags')
206 | {
207 | $Tags = $PSScriptInfo.Tags
208 | }
209 |
210 | if($PSScriptInfo.'ReleaseNotes')
211 | {
212 | $ReleaseNotes = $PSScriptInfo.ReleaseNotes
213 | }
214 |
215 | if($PSScriptInfo.'LicenseUri')
216 | {
217 | $LicenseUri = $PSScriptInfo.LicenseUri
218 | }
219 |
220 | if($PSScriptInfo.'IconUri')
221 | {
222 | $IconUri = $PSScriptInfo.IconUri
223 | }
224 |
225 | if($PSScriptInfo.'ProjectUri')
226 | {
227 | $ProjectUri = $PSScriptInfo.ProjectUri
228 | }
229 | }
230 |
231 |
232 | # Add PSModule and PSGet format version tags
233 | if(-not $Tags)
234 | {
235 | $Tags = @()
236 | }
237 |
238 | if($FormatVersion)
239 | {
240 | $Tags += "$($script:PSGetFormatVersion)_$FormatVersion"
241 | }
242 |
243 | $DependentModuleDetails = @()
244 |
245 | if($PSScriptInfo)
246 | {
247 | $Tags += "PSScript"
248 |
249 | if($PSScriptInfo.DefinedCommands)
250 | {
251 | if($PSScriptInfo.DefinedFunctions)
252 | {
253 | $Tags += "$($script:Includes)_Function"
254 | $Tags += $PSScriptInfo.DefinedFunctions | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" }
255 | }
256 |
257 | if($PSScriptInfo.DefinedWorkflows)
258 | {
259 | $Tags += "$($script:Includes)_Workflow"
260 | $Tags += $PSScriptInfo.DefinedWorkflows | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Workflow)_$_" }
261 | }
262 |
263 | $Tags += $PSScriptInfo.DefinedCommands | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" }
264 | }
265 |
266 | # Populate the dependencies elements from RequiredModules and RequiredScripts
267 | #
268 | $ValidateAndGetScriptDependencies_Params = @{
269 | Repository=$Repository
270 | DependentScriptInfo=$PSScriptInfo
271 | CallerPSCmdlet=$PSCmdlet
272 | Verbose=$VerbosePreference
273 | Debug=$DebugPreference
274 | }
275 | if ($PSBoundParameters.ContainsKey('Credential'))
276 | {
277 | $ValidateAndGetScriptDependencies_Params.Add('Credential',$Credential)
278 | }
279 | $DependentModuleDetails += ValidateAndGet-ScriptDependencies @ValidateAndGetScriptDependencies_Params
280 | }
281 | else
282 | {
283 | $Tags += "PSModule"
284 |
285 | $ModuleManifestHashTable = Get-ManifestHashTable -Path $ManifestPath
286 |
287 | if($PSModuleInfo.ExportedCommands.Count)
288 | {
289 | if($PSModuleInfo.ExportedCmdlets.Count)
290 | {
291 | $Tags += "$($script:Includes)_Cmdlet"
292 | $Tags += $PSModuleInfo.ExportedCmdlets.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Cmdlet)_$_" }
293 |
294 | #if CmdletsToExport field in manifest file is "*", we suggest the user to include all those cmdlets for best practice
295 | if($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('CmdletsToExport') -and ($ModuleManifestHashTable.CmdletsToExport -eq "*"))
296 | {
297 | $WarningMessage = $LocalizedData.ShouldIncludeCmdletsToExport -f ($ManifestPath)
298 | Write-Warning -Message $WarningMessage
299 | }
300 | }
301 |
302 | if($PSModuleInfo.ExportedFunctions.Count)
303 | {
304 | $Tags += "$($script:Includes)_Function"
305 | $Tags += $PSModuleInfo.ExportedFunctions.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" }
306 |
307 | if($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('FunctionsToExport') -and ($ModuleManifestHashTable.FunctionsToExport -eq "*"))
308 | {
309 | $WarningMessage = $LocalizedData.ShouldIncludeFunctionsToExport -f ($ManifestPath)
310 | Write-Warning -Message $WarningMessage
311 | }
312 | }
313 |
314 | $Tags += $PSModuleInfo.ExportedCommands.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" }
315 | }
316 |
317 | if(!$IsCoreCLR) {
318 | $dscResourceNames = Get-ExportedDscResources -PSModuleInfo $PSModuleInfo
319 | } else {
320 | Write-Verbose 'Skipping DSC resource enumeration as it is not supported on PS Core.'
321 | Write-Verbose 'Please use Windows PowerShell to build DSC modules.'
322 | }
323 | if($dscResourceNames)
324 | {
325 | $Tags += "$($script:Includes)_DscResource"
326 |
327 | $Tags += $dscResourceNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:DscResource)_$_" }
328 |
329 | #If DscResourcesToExport is commented out or "*" is used, we will write-warning
330 | if($ModuleManifestHashTable -and
331 | ($ModuleManifestHashTable.ContainsKey("DscResourcesToExport") -and
332 | $ModuleManifestHashTable.DscResourcesToExport -eq "*") -or
333 | -not $ModuleManifestHashTable.ContainsKey("DscResourcesToExport"))
334 | {
335 | $WarningMessage = $LocalizedData.ShouldIncludeDscResourcesToExport -f ($ManifestPath)
336 | Write-Warning -Message $WarningMessage
337 | }
338 | }
339 |
340 | $RoleCapabilityNames = Get-AvailableRoleCapabilityName -PSModuleInfo $PSModuleInfo
341 | if($RoleCapabilityNames)
342 | {
343 | $Tags += "$($script:Includes)_RoleCapability"
344 |
345 | $Tags += $RoleCapabilityNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:RoleCapability)_$_" }
346 | }
347 |
348 | # Populate the module dependencies elements from RequiredModules and
349 | # NestedModules properties of the current PSModuleInfo
350 | $GetModuleDependencies_Params = @{
351 | PSModuleInfo=$PSModuleInfo
352 | Repository=$Repository
353 | CallerPSCmdlet=$PSCmdlet
354 | Verbose=$VerbosePreference
355 | Debug=$DebugPreference
356 | }
357 | if ($PSBoundParameters.ContainsKey('Credential'))
358 | {
359 | $GetModuleDependencies_Params.Add('Credential',$Credential)
360 | }
361 | $DependentModuleDetails = Get-ModuleDependencies @GetModuleDependencies_Params
362 | }
363 |
364 | $dependencies = @()
365 | ForEach($Dependency in $DependentModuleDetails)
366 | {
367 | $ModuleName = $Dependency.Name
368 | $VersionString = $null
369 |
370 | # Version format in NuSpec:
371 | # "[2.0]" --> (== 2.0) Required Version
372 | # "2.0" --> (>= 2.0) Minimum Version
373 | #
374 | # When only MaximumVersion is specified in the ModuleSpecification
375 | # (,1.0] = x <= 1.0
376 | #
377 | # When both Minimum and Maximum versions are specified in the ModuleSpecification
378 | # [1.0,2.0] = 1.0 <= x <= 2.0
379 |
380 | if($Dependency.Keys -Contains "RequiredVersion")
381 | {
382 | $VersionString = "[$($Dependency.RequiredVersion)]"
383 | }
384 | elseif($Dependency.Keys -Contains 'MinimumVersion' -and $Dependency.Keys -Contains 'MaximumVersion')
385 | {
386 | $VersionString = "[$($Dependency.MinimumVersion),$($Dependency.MaximumVersion)]"
387 | }
388 | elseif($Dependency.Keys -Contains 'MaximumVersion')
389 | {
390 | $VersionString = "(,$($Dependency.MaximumVersion)]"
391 | }
392 | elseif($Dependency.Keys -Contains 'MinimumVersion')
393 | {
394 | $VersionString = "$($Dependency.MinimumVersion)"
395 | }
396 |
397 | if ([System.string]::IsNullOrWhiteSpace($VersionString))
398 | {
399 | $dependencies += ""
400 | }
401 | else
402 | {
403 | $dependencies += ""
404 | }
405 | }
406 |
407 | # Populate the nuspec elements
408 | $nuspec = @"
409 |
410 |
411 |
412 | $(Get-EscapedString -ElementValue "$Name")
413 | $($Version)
414 | $(Get-EscapedString -ElementValue "$Author")
415 | $(Get-EscapedString -ElementValue "$CompanyName")
416 | $(Get-EscapedString -ElementValue "$Description")
417 | $(Get-EscapedString -ElementValue "$ReleaseNotes")
418 | $($requireLicenseAcceptance.ToString())
419 | $(Get-EscapedString -ElementValue "$Copyright")
420 | $(if($Tags){ Get-EscapedString -ElementValue ($Tags -join ' ')})
421 | $(if($LicenseUri){
422 | "$(Get-EscapedString -ElementValue "$LicenseUri")"
423 | })
424 | $(if($ProjectUri){
425 | "$(Get-EscapedString -ElementValue "$ProjectUri")"
426 | })
427 | $(if($IconUri){
428 | "$(Get-EscapedString -ElementValue "$IconUri")"
429 | })
430 |
431 | $dependencies
432 |
433 |
434 |
435 | "@
436 |
437 | # When packaging we must build something.
438 | # So, we are building an empty assembly called NotUsed, and discarding it.
439 | $CsprojContent = @"
440 |
441 |
442 | NotUsed
443 | Temp project used for creating nupkg file.
444 | $Name.nuspec
445 | $NugetPackageRoot
446 | netcoreapp2.0
447 |
448 |
449 | "@
450 | $NupkgPath = Microsoft.PowerShell.Management\Join-Path -Path $NugetPackageRoot -ChildPath "$Name.$Version.nupkg"
451 |
452 | $csprojBasePath = $null
453 | if($script:DotnetCommandPath) {
454 | $csprojBasePath = Microsoft.PowerShell.Management\Join-Path -Path $script:TempPath -ChildPath ([System.Guid]::NewGuid())
455 | $null = Microsoft.PowerShell.Management\New-Item -Path $csprojBasePath -ItemType Directory -Force -WhatIf:$false -Confirm:$false
456 | $NuspecPath = Microsoft.PowerShell.Management\Join-Path -Path $csprojBasePath -ChildPath "$Name.nuspec"
457 | $CsprojFilePath = Microsoft.PowerShell.Management\Join-Path -Path $csprojBasePath -ChildPath "$Name.csproj"
458 | }
459 | else {
460 | $NuspecPath = Microsoft.PowerShell.Management\Join-Path -Path $NugetPackageRoot -ChildPath "$Name.nuspec"
461 | }
462 |
463 | $tempErrorFile = $null
464 | $tempOutputFile = $null
465 |
466 | try
467 | {
468 | # Remove existing nuspec and nupkg files
469 | if($NupkgPath -and (Test-Path -Path $NupkgPath -PathType Leaf))
470 | {
471 | Microsoft.PowerShell.Management\Remove-Item $NupkgPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
472 | }
473 |
474 | if($NuspecPath -and (Test-Path -Path $NuspecPath -PathType Leaf))
475 | {
476 | Microsoft.PowerShell.Management\Remove-Item $NuspecPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
477 | }
478 |
479 | Microsoft.PowerShell.Management\Set-Content -Value $nuspec -Path $NuspecPath -Force -Confirm:$false -WhatIf:$false
480 |
481 | # Create .nupkg file
482 | if($script:DotnetCommandPath) {
483 | Microsoft.PowerShell.Management\Set-Content -Value $CsprojContent -Path $CsprojFilePath -Force -Confirm:$false -WhatIf:$false
484 |
485 | $arguments = @('pack')
486 | $arguments += $csprojBasePath
487 | $arguments += @('--output',$NugetPackageRoot)
488 | $arguments += "/p:StagingPath=$NugetPackageRoot"
489 | $output = & $script:DotnetCommandPath $arguments
490 | Write-Debug -Message "dotnet pack output: $output"
491 | }
492 | elseif($script:NuGetExePath) {
493 | $output = & $script:NuGetExePath pack $NuspecPath -OutputDirectory $NugetPackageRoot
494 | }
495 |
496 | if(-not (Test-Path -Path $NupkgPath -PathType Leaf)) {
497 | $SemanticVersionString = Get-NormalizedVersionString -Version $Version
498 | $NupkgPath = Join-PathUtility -Path $NugetPackageRoot -ChildPath "$Name.$($SemanticVersionString).nupkg" -PathType File
499 | }
500 |
501 | if($LASTEXITCODE -or -not $NupkgPath -or -not (Test-Path -Path $NupkgPath -PathType Leaf))
502 | {
503 | if($PSArtifactType -eq $script:PSArtifactTypeModule)
504 | {
505 | $message = $LocalizedData.FailedToCreateCompressedModule -f ($output)
506 | $errorId = "FailedToCreateCompressedModule"
507 | }
508 | else
509 | {
510 | $message = $LocalizedData.FailedToCreateCompressedScript -f ($output)
511 | $errorId = "FailedToCreateCompressedScript"
512 | }
513 |
514 | Write-Error -Message $message -ErrorId $errorId -Category InvalidOperation
515 | return
516 | }
517 |
518 | # Publish the .nupkg to gallery
519 | $tempErrorFile = Microsoft.PowerShell.Management\Join-Path -Path $nugetPackageRoot -ChildPath "TempPublishError.txt"
520 | $tempOutputFile = Microsoft.PowerShell.Management\Join-Path -Path $nugetPackageRoot -ChildPath "TempPublishOutput.txt"
521 |
522 | $errorMsg = $null
523 | $outputMsg = $null
524 | $StartProcess_params = @{
525 | RedirectStandardError = $tempErrorFile
526 | RedirectStandardOutput = $tempOutputFile
527 | NoNewWindow = $true
528 | Wait = $true
529 | PassThru = $true
530 | }
531 |
532 | if($script:DotnetCommandPath) {
533 | $StartProcess_params['FilePath'] = $script:DotnetCommandPath
534 |
535 | $ArgumentList = @('nuget')
536 | $ArgumentList += 'push'
537 | $ArgumentList += "`"$NupkgPath`""
538 | $ArgumentList += @('--source', "`"$($Destination.TrimEnd('\'))`"")
539 | $ArgumentList += @('--api-key', "`"$NugetApiKey`"")
540 | }
541 | elseif($script:NuGetExePath) {
542 | $StartProcess_params['FilePath'] = $script:NuGetExePath
543 |
544 | $ArgumentList = @('push')
545 | $ArgumentList += "`"$NupkgPath`""
546 | $ArgumentList += @('-source', "`"$($Destination.TrimEnd('\'))`"")
547 | $ArgumentList += @('-apikey', "`"$NugetApiKey`"")
548 | $ArgumentList += '-NonInteractive'
549 | }
550 | $StartProcess_params['ArgumentList'] = $ArgumentList
551 |
552 | if($script:IsCoreCLR -and -not $script:IsNanoServer) {
553 | $StartProcess_params['WhatIf'] = $false
554 | $StartProcess_params['Confirm'] = $false
555 | }
556 |
557 | $process = Microsoft.PowerShell.Management\Start-Process @StartProcess_params
558 |
559 | if(Test-Path -Path $tempErrorFile -PathType Leaf) {
560 | $errorMsg = Microsoft.PowerShell.Management\Get-Content -Path $tempErrorFile -Raw
561 |
562 | if($errorMsg) {
563 | Write-Verbose -Message $errorMsg
564 | }
565 | }
566 |
567 | if(Test-Path -Path $tempOutputFile -PathType Leaf) {
568 | $outputMsg = Microsoft.PowerShell.Management\Get-Content -Path $tempOutputFile -Raw
569 |
570 | if($outputMsg) {
571 | Write-Verbose -Message $outputMsg
572 | }
573 | }
574 |
575 | # The newer version of dotnet cli writes the error message into output stream instead of error stream
576 | # Get the error message from output stream when ExitCode is non zero (error).
577 | if($process -and $process.ExitCode -and -not $errorMsg -and $outputMsg) {
578 | $errorMsg = $outputMsg
579 | }
580 |
581 | if(-not $process -or $process.ExitCode)
582 | {
583 | if(($NugetApiKey -eq 'VSTS') -and
584 | ($errorMsg -match 'Cannot prompt for input in non-interactive mode.') )
585 | {
586 | $errorMsg = $LocalizedData.RegisterVSTSFeedAsNuGetPackageSource -f ($Destination, $script:VSTSAuthenticatedFeedsDocUrl)
587 | }
588 |
589 | if($PSArtifactType -eq $script:PSArtifactTypeModule)
590 | {
591 | $message = $LocalizedData.FailedToPublish -f ($Name,$errorMsg)
592 | $errorId = "FailedToPublishTheModule"
593 | }
594 | else
595 | {
596 | $message = $LocalizedData.FailedToPublishScript -f ($Name,$errorMsg)
597 | $errorId = "FailedToPublishTheScript"
598 | }
599 |
600 | Write-Error -Message $message -ErrorId $errorId -Category InvalidOperation
601 | }
602 | else
603 | {
604 | if($PSArtifactType -eq $script:PSArtifactTypeModule)
605 | {
606 | $message = $LocalizedData.PublishedSuccessfully -f ($Name, $Destination, $Name)
607 | }
608 | else
609 | {
610 | $message = $LocalizedData.PublishedScriptSuccessfully -f ($Name, $Destination, $Name)
611 | }
612 |
613 | Write-Verbose -Message $message
614 | }
615 | }
616 | finally
617 | {
618 | if($NupkgPath -and (Test-Path -Path $NupkgPath -PathType Leaf))
619 | {
620 | Microsoft.PowerShell.Management\Remove-Item $NupkgPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
621 | }
622 |
623 | if($NuspecPath -and (Test-Path -Path $NuspecPath -PathType Leaf))
624 | {
625 | Microsoft.PowerShell.Management\Remove-Item $NuspecPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
626 | }
627 |
628 | if($tempErrorFile -and (Test-Path -Path $tempErrorFile -PathType Leaf))
629 | {
630 | Microsoft.PowerShell.Management\Remove-Item $tempErrorFile -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
631 | }
632 |
633 | if($tempOutputFile -and (Test-Path -Path $tempOutputFile -PathType Leaf))
634 | {
635 | Microsoft.PowerShell.Management\Remove-Item $tempOutputFile -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
636 | }
637 |
638 | if($csprojBasePath -and (Test-Path -Path $csprojBasePath -PathType Container))
639 | {
640 | Microsoft.PowerShell.Management\Remove-Item -Path $csprojBasePath -Recurse -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
641 | }
642 | }
643 | }
644 |
--------------------------------------------------------------------------------
/ThirdPartyNotices.txt:
--------------------------------------------------------------------------------
1 | THIRD PARTY SOFTWARE NOTICES AND INFORMATION
2 |
3 | This project uses software provided by third parties, including open source software. The following copyright statements and licenses apply to various components that are distributed with various parts of the project. The project that includes this file does not necessarily use all of the third party software components referred to below.
4 |
5 | Licensee must fully agree and comply with these license terms or must not use these components. The third party license terms apply only to the respective software to which the license pertains, and the third party license terms do not apply to the Hangfire software.
6 |
7 | In the event that we accidentally failed to list a required notice, please bring it to our attention by filing an issue in our code repository.
8 |
9 | -------------------------------------------------------------------
10 |
11 | PowerShellGet
12 | https://github.com/PowerShell/PowerShellGet
13 |
14 | PowerShellGet
15 |
16 | Copyright (c) Microsoft Corporation
17 |
18 | All rights reserved.
19 |
20 | The MIT License (MIT)
21 |
22 | Permission is hereby granted, free of charge, to any person obtaining a copy
23 | of this software and associated documentation files (the "Software"), to deal
24 | in the Software without restriction, including without limitation the rights
25 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
26 | copies of the Software, and to permit persons to whom the Software is
27 | furnished to do so, subject to the following conditions:
28 |
29 | The above copyright notice and this permission notice shall be included in all
30 | copies or substantial portions of the Software.
31 |
32 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38 | SOFTWARE.
39 |
40 | -------------------------------------------------------------------
41 |
--------------------------------------------------------------------------------
/build/build.ps1:
--------------------------------------------------------------------------------
1 | [CmdletBinding()]
2 | Param(
3 | [Parameter()]
4 | [string]
5 | $ProjectRoot = (Resolve-Path (Join-path $BuildRoot '..')).Path,
6 |
7 | [Parameter()]
8 | [string]
9 | $OutputPath,
10 |
11 | [Parameter()]
12 | [string]
13 | $Phase = 'build',
14 |
15 | [Parameter()]
16 | [string]
17 | $PSGalleryApiKey,
18 |
19 | [Parameter()]
20 | [string]
21 | $PSRepositoryName = $env:PSRepositoryName,
22 |
23 | [Parameter()]
24 | [string]
25 | $PSRepositoryUrl = $env:PSRepositoryUrl,
26 |
27 | [Parameter()]
28 | [ValidateSet('','none','basic','apikey')]
29 | [string]
30 | $PSRepositoryAuthMethod = $env:PSRepositoryAuthMethod,
31 |
32 | [Parameter()]
33 | [string]
34 | $PSRepositoryUser = $env:PSRepositoryUser,
35 |
36 | [Parameter()]
37 | [string]
38 | $PSRepositoryPassword = $env:PSRepositoryPassword,
39 |
40 | [Parameter()]
41 | [string]
42 | $PSRepositoryApiKey = $env:PSRepositoryApiKey,
43 |
44 | [Parameter()]
45 | [string]
46 | $BuildVersion = $env:GitVersion_NuGetVersionV2
47 | )
48 |
49 | Set-BuildHeader {
50 | param($Path)
51 | Write-Build Green ('=' * 80)
52 | Write-Build Green (' Task {0}' -f $Path)
53 | Write-Build Green ('At {0}:{1}' -f $Task.InvocationInfo.ScriptName, $Task.InvocationInfo.ScriptLineNumber)
54 | if(($Synopsis = Get-BuildSynopsis $Task)) {
55 | Write-Build Green (' {0}' -f $Synopsis)
56 | }
57 | Write-Build Green ('-' * 80)
58 | # task location in a script
59 | Write-Build Green ' '
60 | }
61 |
62 | # Define footers similar to default but change the color to DarkGray.
63 | Set-BuildFooter {
64 | param($Path)
65 | Write-Build Green ' '
66 | Write-Build Green ('=' * 80)
67 | Write-Build DarkGray ('Done {0}, {1}' -f $Path, $Task.Elapsed)
68 | Write-Build Green ' '
69 | Write-Build Green ' '
70 | }
71 |
72 |
73 | $TasksFolder = Join-Path $PSScriptRoot 'tasks'
74 | Get-ChildItem -Path $TasksFolder -Filter "*.task.ps1" | ForEach-Object {
75 | . $_.FullName
76 | }
77 |
78 | Task . Build
--------------------------------------------------------------------------------
/build/tasks/BuildModule.task.ps1:
--------------------------------------------------------------------------------
1 | Task BuildModule {
2 | $Script:Phase = 'Build'
3 | }, Initialize, CreatePaths, InstallDependencies, CopyModuleBaseFiles, CopyModuleSourceFiles, CopyModuleAssets, UpdateExportFunctionsAndAliases, VersionBump
--------------------------------------------------------------------------------
/build/tasks/Clean.task.ps1:
--------------------------------------------------------------------------------
1 | Task Clean Initialize, {
2 | 'Removing OutputPath contents'
3 | Get-ChildItem -Path $OutputPath -Force -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -Verbose
4 | }
--------------------------------------------------------------------------------
/build/tasks/CleanAll.task.ps1:
--------------------------------------------------------------------------------
1 | Task CleanAll Initialize, {
2 | 'Cleaning all project directories'
3 | foreach($Path in $Script:ProjectDirectories) {
4 | try {
5 | 'Removing {0}...' -f $Path
6 | Remove-Item -Path $Path -Recurse -Force -ErrorAction Stop
7 | 'Removed path {0}.' -f $Path
8 | } catch [System.Management.Automation.ItemNotFoundException] {
9 | '{0} was already removed.' -f $Path
10 | } catch {
11 | Write-Error -ErrorRecord $_
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/build/tasks/CopyModuleAssets.task.ps1:
--------------------------------------------------------------------------------
1 | Task CopyModuleAssets Initialize, {
2 | if(-not (Test-Path -PathType Container -Path $ModuleSrcAssetsPath)) {
3 | 'Assets directory {0} does not exist. skipping.' -f $ModuleSrcAssetsPath
4 | return
5 | }
6 | 'Copying assets from {0} to ' -f $ModuleSrcAssetsPath, $ModuleOutputAssetsPath
7 | $Null = New-Item -Path $ModuleOutputAssetsPath -Force -ItemType Directory
8 | Get-ChildItem $ModuleSrcAssetsPath -Force | ForEach-Object {
9 | if($_.PSIsContainer) {
10 | 'Copying Directory {0}' -f $_.FullName
11 | Copy-Item -Container -Recurse -Path $_.FullName -Destination $ModuleOutputAssetsPath -Force
12 | } else {
13 | 'Copying file {0}' -f $_.FullName
14 | Copy-Item -Path $_.FullName -Destination $ModuleOutputAssetsPath -Force
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/build/tasks/CopyModuleBaseFiles.task.ps1:
--------------------------------------------------------------------------------
1 | Task CopyModuleBaseFiles Initialize, CreatePaths, {
2 | 'Copying base module files from {0} to {1}' -f $ModuleSrcPath, $ModuleOutputPath
3 | $Null = Push-Location $ModuleSrcPath
4 | Copy-Item *.psm1, *.psd1, *.ps1xml -Destination $ModuleOutputPath -Force -Verbose
5 | $Null = Pop-Location
6 | }
--------------------------------------------------------------------------------
/build/tasks/CopyModuleSourceFiles.task.ps1:
--------------------------------------------------------------------------------
1 | Task CopyModuleSourceFiles Initialize, CreatePaths, {
2 | 'Copying module source files into {0}' -f $ModuleOutputRootModuleFile
3 | $Null = Push-Location $ProjectRoot
4 |
5 | $AddContentCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Management\Add-Content', [System.Management.Automation.CommandTypes]::Cmdlet)
6 | $AddContent = {& $AddContentCmd -Path $ModuleOutputRootModuleFile -Encoding Utf8 }.GetSteppablePipeline($myInvocation.CommandOrigin)
7 | $AddContent.Begin($true)
8 |
9 | $Folders = @(
10 | $ModuleSrcEnumsPath
11 | $ModuleSrcClassesPath
12 | $ModuleSrcPrivatePath
13 | $ModuleSrcPublicPath
14 | )
15 | foreach ($Folder in $Folders) {
16 | if(-not (Test-Path -PathType Container -Path $Folder)){
17 | '{0} does not existing. skipping' -f $Folder
18 | continue
19 | }
20 | 'Copying source from {0} into {1}' -f $Folder, $ModuleOutputRootModuleFile
21 | $Params = @{
22 | Filter = '*.ps1'
23 | Path = $Folder
24 | Recurse = $true
25 | File = $true
26 | Force = $true
27 | }
28 | Get-ChildItem @Params | ForEach-Object {
29 | 'Processing {0}' -f $_.FullName
30 | $FileName = Resolve-Path -Path $_.FullName -Relative
31 | $Prefix = "#Region '{0}' 0" -f $FileName
32 | $AddContent.Process($Prefix)
33 | Get-Content $_.FullName -OutVariable Content | ForEach-Object {
34 | $AddContent.Process($_)
35 | }
36 | $Suffix = "#EndRegion '{0}' {1}" -f $FileName, $Content.Count
37 | $AddContent.Process($Suffix)
38 | }
39 | }
40 | $AddContent.End()
41 | $Null = Pop-Location
42 | }
--------------------------------------------------------------------------------
/build/tasks/CreatePaths.task.ps1:
--------------------------------------------------------------------------------
1 | Task CreatePaths Initialize, {
2 | 'Creating project directories'
3 | foreach($Path in $Script:ProjectDirectories) {
4 | New-Item -ItemType Directory -Path $Path -Force | ForEach-Object -MemberName FullName
5 | }
6 | }
--------------------------------------------------------------------------------
/build/tasks/ImportDependencyConfig.task.ps1:
--------------------------------------------------------------------------------
1 | Task ImportDependencyConfig Initialize, {
2 | 'Importing dependency configuration from {0}' -f $DependenciesFile
3 | $Script:DependencyConfig = Get-Content -Raw $DependenciesFile -ErrorAction stop | ConvertFrom-Json -ErrorAction stop
4 | }
--------------------------------------------------------------------------------
/build/tasks/ImportModule.task.ps1:
--------------------------------------------------------------------------------
1 | Task ImportModule Initialize, {
2 | 'Importing module {0}' -f $ModuleOutputManifestFile
3 | Import-Module -Force $ModuleOutputManifestFile
4 | }
5 |
--------------------------------------------------------------------------------
/build/tasks/ImportPSModules.task.ps1:
--------------------------------------------------------------------------------
1 | Task ImportPSModules Initialize, ImportDependencyConfig, {
2 | 'Importing PowerShell Modules for phase {0}' -f $Phase
3 | if(-not $DependencyConfig.PowerShell) {
4 | 'No PowerShell dependencies found. Skipping.'
5 | return
6 | }
7 |
8 | foreach($Dependency in $DependencyConfig.PowerShell){
9 | if($Dependency.Phases -notcontains $Phase) {
10 | "{0} is not required in this phase, skipping." -f $Dependency.Name
11 | continue
12 | }
13 | 'Importing module {0} version {1}' -f $Dependency.Name, $Dependency.Version
14 | Import-Module -Force -Name $Dependency.Name -RequiredVersion $Dependency.Version -scope Global
15 | }
16 | }
--------------------------------------------------------------------------------
/build/tasks/Initialize.task.ps1:
--------------------------------------------------------------------------------
1 | Task Initialize {
2 | $Script:SrcPath = Join-Path $ProjectRoot 'src'
3 | $ModuleSrc = Get-ChildItem -Path $SrcPath -Directory
4 | $Script:ModuleSrcPath = $ModuleSrc.FullName
5 | $Script:ModuleName = $ModuleSrc.Name
6 | $Script:ModuleSrcManifestFile = Join-Path $ModuleSrcPath "$ModuleName.psd1"
7 | $Script:ModuleSrcRootModuleFile = Join-Path $ModuleSrcPath "$ModuleName.psm1"
8 | $Script:ModuleSrcPublicPath = Join-Path $ModuleSrcPath 'public'
9 | $Script:ModuleSrcPrivatePath = Join-Path $ModuleSrcPath 'private'
10 | $Script:ModuleSrcClassesPath = Join-Path $ModuleSrcPath 'classes'
11 | $Script:ModuleSrcEnumsPath = Join-Path $ModuleSrcPath 'enums'
12 | $Script:ModuleSrcAssetsPath = Join-Path $ModuleSrcPath 'assets'
13 | $Script:TestPath = Join-Path $ProjectRoot 'test'
14 | $Script:TestIntegrationPath = Join-Path $TestPath 'integration'
15 | $Script:TestUnitPath = Join-Path $TestPath 'unit'
16 | $Script:LocalPSModulePath = Join-Path $ProjectRoot 'psmodules'
17 | $Script:ConfigPath = Join-Path $ProjectRoot 'config'
18 | $Script:DependenciesFile = Join-Path $ConfigPath 'dependencies.json'
19 |
20 | if($OutputPath) {
21 | 'OutputPath derived from user input'
22 | }
23 | if(-not $OutputPath -and $env:Build_ArtifactStagingDirectory) {
24 | 'OutputPath derived from Build_ArtifactStagingDirectory'
25 | $Script:OutputPath = $env:Build_ArtifactStagingDirectory
26 | }
27 | if(-not $OutputPath) {
28 | 'OutputPath derived from ProjectRoot'
29 | $Script:OutputPath = Join-Path $ProjectRoot 'bin'
30 | }
31 |
32 | $Script:ModulesOutputPath = Join-Path $OutputPath 'modules'
33 | $Script:ModuleOutputPath = Join-Path $ModulesOutputPath $ModuleName
34 | $Script:ModuleOutputAssetsPath = Join-Path $ModuleOutputPath 'assets'
35 | $Script:ModuleOutputManifestFile = Join-Path $ModuleOutputPath "$ModuleName.psd1"
36 | $Script:ModuleOutputRootModuleFile = Join-Path $ModuleOutputPath "$ModuleName.psm1"
37 |
38 | $ModulePaths = $env:PSModulePath -split [System.IO.Path]::PathSeparator
39 | if($ModulePaths -NotContains $LocalPSModulePath) {
40 | $env:PSModulePath = '{0}{1}{2}' -f @(
41 | $env:PSModulePath
42 | [System.IO.Path]::PathSeparator
43 | $LocalPSModulePath
44 | )
45 | }
46 |
47 | $Script:ProjectDirectories = @(
48 | $OutputPath
49 | $ModulesOutputPath
50 | $ModuleOutputPath
51 | $LocalPSModulePath
52 | )
53 |
54 | ' '
55 | 'ProjectRoot: {0}' -f $Script:ProjectRoot
56 | 'ModuleName: {0}' -f $Script:ModuleName
57 | 'SrcPath: {0}' -f $Script:SrcPath
58 | 'ModuleSrcPath: {0}' -f $Script:ModuleSrcPath
59 | 'ModuleSrcManifestFile: {0}' -f $Script:ModuleSrcManifestFile
60 | 'ModuleSrcRootModuleFile: {0}' -f $Script:ModuleSrcRootModuleFile
61 | 'ModuleSrcPublicPath: {0}' -f $Script:ModuleSrcPublicPath
62 | 'ModuleSrcPrivatePath: {0}' -f $Script:ModuleSrcPrivatePath
63 | 'ModuleSrcClassesPath: {0}' -f $Script:ModuleSrcClassesPath
64 | 'ModuleSrcEnumsPath: {0}' -f $Script:ModuleSrcEnumsPath
65 | 'ModuleSrcAssetsPath: {0}' -f $Script:ModuleSrcAssetsPath
66 | 'TestPath: {0}' -f $Script:TestPath
67 | 'TestIntegrationPath: {0}' -f $Script:TestIntegrationPath
68 | 'TestUnitPath: {0}' -f $Script:TestUnitPath
69 | 'OutputPath: {0}' -f $Script:OutputPath
70 | 'ModulesOutputPath: {0}' -f $Script:ModulesOutputPath
71 | 'ModuleOutputPath: {0}' -f $Script:ModuleOutputPath
72 | 'ModuleOutputAssetsPath: {0}' -f $Script:ModuleOutputAssetsPath
73 | 'ModuleOutputManifestFile: {0}' -f $Script:ModuleOutputManifestFile
74 | 'ModuleOutputRootModuleFile: {0}' -f $Script:ModuleOutputRootModuleFile
75 | 'LocalPSModulePath: {0}' -f $Script:LocalPSModulePath
76 | 'ConfigPath: {0}' -f $Script:ConfigPath
77 | 'DependenciesFile: {0}' -f $Script:DependenciesFile
78 | 'env:PSModulePath: {0}' -f $env:PSModulePath
79 | 'ProjectDirectories: {0}' -f ($Script:ProjectDirectories -join ', ')
80 | 'Phase: {0}' -f $Script:Phase
81 | 'PSGalleryApiKey present: {0}' -f (-not [string]::IsNullOrWhiteSpace($Script:PSGalleryApiKey))
82 | 'PSRepositoryName: {0}' -f $Script:PSRepositoryName
83 | 'PSRepositoryUrl: {0}' -f $Script:PSRepositoryUrl
84 | 'PSRepositoryUrl: {0}' -f $Script:PSRepositoryUrl
85 | 'PSRepositoryAuthMethod: {0}' -f $Script:PSRepositoryAuthMethod
86 | 'PSRepositoryUser: {0}' -f $Script:PSRepositoryUser
87 | 'PSRepositoryPassword present: {0}' -f (-not [string]::IsNullOrWhiteSpace($Script:PSRepositoryPassword))
88 | 'PSRepositoryApiKey present: {0}' -f (-not [string]::IsNullOrWhiteSpace($Script:PSRepositoryApiKey))
89 | 'BuildVersion: {0}' -f $Script:BuildVersion
90 | }
--------------------------------------------------------------------------------
/build/tasks/InstallDependencies.task.ps1:
--------------------------------------------------------------------------------
1 | Task InstallDependencies RegisterPSRepository, InstallDependenciesPS, ImportPSModules
--------------------------------------------------------------------------------
/build/tasks/InstallDependenciesPS.task.ps1:
--------------------------------------------------------------------------------
1 | Task InstallDependenciesPS Initialize, CreatePaths, RegisterPSRepository, ImportDependencyConfig, {
2 | 'Installing PowerShell Dependencies for phase {0}' -f $Phase
3 | if(-not $DependencyConfig.PowerShell) {
4 | 'No PowerShell dependencies found. Skipping.'
5 | return
6 | }
7 |
8 | $AvailableModules = Get-Module -ListAvailable
9 | $Params = @{
10 | Repository = 'PSGallery'
11 | Path = $LocalPSModulePath
12 | Force = $true
13 | AllowPrerelease = $true
14 | AcceptLicense = $true
15 | Verbose = $true
16 | }
17 |
18 | If($PSRepositoryName) {
19 | $Params['Repository'] = $PSRepositoryName, 'PSGallery'
20 | }
21 |
22 | if($PSRepositoryUser -and $PSRepositoryPassword) {
23 | 'PSRepositoryUser and PSRepositoryPassword present and will be used'
24 | $SecurePass = $PSRepositoryPassword | ConvertTo-SecureString -AsPlainText -Force
25 | $Params['Credential'] = [PSCredential]::new($PSRepositoryUser, $SecurePass)
26 | }
27 |
28 | foreach($Dependency in $DependencyConfig.PowerShell){
29 | if($Dependency.Phases -notcontains $Phase) {
30 | "{0} is not required in this phase, skipping." -f $Dependency.Name
31 | continue
32 | }
33 | 'Checking for existence of module {0} version {1}' -f $Dependency.Name, $Dependency.Version
34 | $Installed = $AvailableModules.Where({$_.Name -eq $Dependency.Name -and $_.Version -eq $Dependency.Version})
35 | if ($Installed) {
36 | 'module {0} version {1} already installed. Skipping.' -f $Dependency.Name, $Dependency.Version
37 | continue
38 | }
39 | Save-Module @Params -Name $Dependency.Name -RequiredVersion $Dependency.Version
40 | ' '
41 | ' '
42 | }
43 | }
--------------------------------------------------------------------------------
/build/tasks/PublishPSModuleNuget.task.ps1:
--------------------------------------------------------------------------------
1 | Task PublishPSModuleNuget Initialize, ImportModule, {
2 | $Module = Get-Module -Name $ModuleName
3 | 'Publishing Module "{0}" Nupkg' -f $Module.Name
4 | $Script:PSModuleNupkg = $Module | Publish-PSModuleNuget -OutputPath $OutputPath -Verbose -PassThru |
5 | Foreach-Object -MemberName FullName
6 | 'PSModuleNupkg: {0}' -f $Script:PSModuleNupkg
7 | }
8 |
--------------------------------------------------------------------------------
/build/tasks/RegisterPSRepository.task.ps1:
--------------------------------------------------------------------------------
1 | Task RegisterPSRepository -If {$Script:PSRepositoryName} Initialize, {
2 | 'Ensuring repository {0} at {1}' -f $PSRepositoryName, $PSRepositoryUrl
3 | $PSRepository = Get-PSRepository -Name $PSRepositoryName -ErrorAction SilentlyContinue
4 |
5 | if ($PSRepository -and $PSRepository.SourceLocation -eq $PSRepositoryUrl) {
6 | 'PSRepository {0} already exists. Skipping.' -f $PSRepositoryName
7 | return
8 | }
9 |
10 | if($PSRepository -and ($PSRepository.SourceLocation -ne $PSRepositoryUrl -or $PSRepository.InstallationPolicy -ne 'Trusted')) {
11 | 'PSRepository {0} has invalid SourceLocation {1}. expected {2}' -f @(
12 | $PSRepositoryName,
13 | $PSRepository.SourceLocation,
14 | $PSRepositoryUrl
15 | )
16 | Unregister-PSRepository -Name $PSRepositoryName -Verbose
17 | }
18 |
19 | $Params = @{
20 | Name = $PSRepositoryName
21 | SourceLocation = $PSRepositoryUrl
22 | PublishLocation = $PSRepositoryUrl
23 | InstallationPolicy = "Trusted"
24 | Verbose = $true
25 | }
26 | if($PSRepositoryUser -and $PSRepositoryPassword) {
27 | 'PSRepositoryUser and PSRepositoryPassword present and will be used for registration'
28 | $SecurePass = $PSRepositoryPassword | ConvertTo-SecureString -AsPlainText -Force
29 | $Params['Credential'] = [PSCredential]::new($PSRepositoryUser, $SecurePass)
30 | }
31 | 'Registering PSRepository {0} at {1}' -f $PSRepositoryName, $PSRepositoryUrl
32 | Register-PSRepository @Params
33 | }
--------------------------------------------------------------------------------
/build/tasks/UpdateExportFunctionsAndAliases.task.ps1:
--------------------------------------------------------------------------------
1 | Task UpdateExportFunctionsAndAliases Initialize, InstallDependencies, {
2 | "Parsing {0} for Functions and Aliases" -f $ModuleSrcPublicPath
3 | $FunctionFiles = Get-ChildItem $ModuleSrcPublicPath -Filter '*.ps1' -Recurse |
4 | Where-Object { $_.Name -notmatch '\.tests{0,1}\.ps1' }
5 | $ExportFunctions = [System.Collections.Generic.HashSet[String]]::New([System.StringComparer]::InvariantCultureIgnoreCase)
6 | $ExportAliases = [System.Collections.Generic.HashSet[String]]::New([System.StringComparer]::InvariantCultureIgnoreCase)
7 | foreach ($FunctionFile in $FunctionFiles) {
8 | "- Processing $($FunctionFile.FullName)"
9 | $AST = [System.Management.Automation.Language.Parser]::ParseFile($FunctionFile.FullName, [ref]$null, [ref]$null)
10 | $Functions = $AST.FindAll( {
11 | $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst]
12 | }, $true)
13 | foreach ($FunctionName in $Functions.Name) {
14 | ' Found Function {0}' -f $FunctionName
15 | if(-not $ExportFunctions.Add($FunctionName)) {
16 | throw "'$FunctionName' is a duplicate function."
17 | }
18 | }
19 | $Aliases = $AST.FindAll( {
20 | $args[0] -is [System.Management.Automation.Language.AttributeAst] -and
21 | $args[0].parent -is [System.Management.Automation.Language.ParamBlockAst] -and
22 | $args[0].TypeName.FullName -eq 'alias'
23 | }, $true)
24 | Foreach ($Alias in $Aliases.PositionalArguments.value) {
25 | ' Found Alias {0}' -f $Alias
26 | if(-not $ExportAliases.Add($Alias)) {
27 | throw "'$Alias' is a duplicate alias."
28 | }
29 | }
30 | }
31 |
32 | 'Updating FunctionsToExport in {0}' -f $ModuleOutputManifestFile
33 | Update-Metadata -Path $ModuleOutputManifestFile -PropertyName 'FunctionsToExport' -Value $ExportFunctions
34 | 'Updating AliasesToExport in {0}' -f $ModuleOutputManifestFile
35 | Update-Metadata -Path $ModuleOutputManifestFile -PropertyName 'AliasesToExport' -Value $ExportAliases
36 | }
--------------------------------------------------------------------------------
/build/tasks/VersionBump.task.ps1:
--------------------------------------------------------------------------------
1 | Task VersionBump Initialize, InstallDependencies, {
2 | if(-Not $BuildVersion) {
3 | 'BuildVersion not present'
4 | 'Locating GitVersion binary'
5 | $command = Get-Command -Name 'gitversion' -CommandType 'Application' |
6 | Where-Object {$_.Version -eq '4.0.0.0'} |
7 | select-object -First 1
8 | Push-Location $ProjectRoot
9 | try {
10 | 'Executing GitVersion'
11 | $GtVersion = & $command | ConvertFrom-Json -ErrorAction 'Stop'
12 | } finally {
13 | Pop-Location
14 | }
15 |
16 | $Script:BuildVersion = $GtVersion.NuGetVersionV2
17 | } else {
18 | 'BuildVersion {0} was supplied' -f $BuildVersion
19 | }
20 |
21 | $NewVersion, $PreviewVersion = $BuildVersion -split '-'
22 | $PreviewVersion = -join $PreviewVersion
23 |
24 | $Manifest = Import-PowerShellDataFile -Path $ModuleOutputManifestFile
25 | $PreviousVersion = $Manifest.ModuleVersion
26 |
27 | If (-not $Manifest.PrivateData) {
28 | 'PrivateData was not found'
29 | $Manifest['PrivateData'] = @{}
30 | }
31 |
32 | 'Updating {0} with version {1}' -f $ModuleOutputManifestFile, $NewVersion
33 | Update-Metadata -Path $ModuleOutputManifestFile -PropertyName 'ModuleVersion' -Value $NewVersion
34 |
35 | if($PreviewVersion) {
36 | 'Updating {0} with Prerelease {1}' -f $ModuleOutputManifestFile, $PreviewVersion
37 | $Manifest.PrivateData['Prerelease'] = $PreviewVersion
38 | Update-Metadata -Path $ModuleOutputManifestFile -PropertyName 'PrivateData' -Value $Manifest.PrivateData
39 | } else {
40 | 'Remove Prerelease from {0}' -f
41 | $Manifest.PrivateData.Remove('Prerelease')
42 | Update-Metadata -Path $ModuleOutputManifestFile -PropertyName 'PrivateData' -Value $Manifest.PrivateData
43 | }
44 |
45 | $NewManifest = Import-PowerShellDataFile -Path $ModuleOutputManifestFile
46 |
47 | 'OldManifestVersion: {0}' -f $PreviousVersion
48 | 'BuildVersion: {0}' -f $BuildVersion
49 | 'NewVersion: {0}' -f $NewVersion
50 | 'NewManifestVersion: {0}' -f $NewManifest.ModuleVersion
51 | 'NewManifestPrerelease: {0}' -f $NewManifest.PrivateData.Prerelease
52 | }
--------------------------------------------------------------------------------
/config/dependencies.json:
--------------------------------------------------------------------------------
1 | {
2 | "PowerShell": [
3 | {
4 | "Name": "Configuration",
5 | "Version": "1.3.1",
6 | "Phases": ["Build"]
7 | }
8 | ],
9 | "choco": [
10 | {
11 | "Name": "GitVersion.Portable",
12 | "Version": "4.0.0",
13 | "Phases": ["Build"]
14 | }
15 | ]
16 | }
--------------------------------------------------------------------------------
/scripts/New-ModuleManifest.ps1:
--------------------------------------------------------------------------------
1 | $ModuleName = 'PSPublishHelper'
2 | $ProjectRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
3 | $SrcFolder = Join-Path $ProjectRoot 'src'
4 | $ModuleSrcPath = Join-Path $SrcFolder $ModuleName
5 | $ModuleManifestFile = Join-Path $ModuleSrcPath "$ModuleName.psd1"
6 | $Params = @{
7 | Path = $ModuleManifestFile
8 | Author = "Mark E. Kraus"
9 | CompanyName = "Mark E. Kraus"
10 | Copyright = "Copyright (c) Mark E. Kraus. All rights reserved."
11 | RootModule = "$ModuleName.psm1"
12 | ModuleVersion = "0.0.1"
13 | Description = 'A module to assist with "Build Once, Deploy Many" publishing paradigms for PowerShell'
14 | Tags = "Module","Builder","Publishing","Template","CI","CD","CI/CD"
15 | ProjectUri = "https://github.com/markekraus/$ModuleName"
16 | LicenseUri = "https://github.com/markekraus/$ModuleName/blob/master/LICENSE"
17 | FunctionsToExport = @()
18 | CmdletsToExport = @()
19 | VariablesToExport = @()
20 | AliasesToExport = @()
21 | }
22 | New-ModuleManifest @Params
23 | (Get-Content -Path $ModuleManifestFile) | ForEach-Object {
24 | if($_ -match '^#[^=]*$') {return}
25 | if($_ -match '^/s*$') {return}
26 | if($_ -match '^$') {return}
27 | if($_ -notmatch '^@\{|^\}$'){
28 | " $_"
29 | } else {
30 | $_
31 | }
32 | } | Set-Content -Encoding utf8 -Path $ModuleManifestFile
--------------------------------------------------------------------------------
/src/PSPublishHelper/PSPublishHelper.psd1:
--------------------------------------------------------------------------------
1 | @{
2 | RootModule = 'PSPublishHelper.psm1'
3 | ModuleVersion = '0.0.1'
4 | # CompatiblePSEditions = @()
5 | GUID = '89d9bea3-6e06-44ef-8772-a45b644da8c0'
6 | Author = 'Mark E. Kraus'
7 | CompanyName = 'Mark E. Kraus'
8 | Copyright = 'Copyright (c) Mark E. Kraus. All rights reserved.'
9 | Description = 'A module to assist with "Build Once, Deploy Many" publishing paradigms for PowerShell'
10 | # PowerShellVersion = ''
11 | # PowerShellHostName = ''
12 | # PowerShellHostVersion = ''
13 | # DotNetFrameworkVersion = ''
14 | # CLRVersion = ''
15 | # ProcessorArchitecture = ''
16 | # RequiredModules = @()
17 | # RequiredAssemblies = @()
18 | # ScriptsToProcess = @()
19 | # TypesToProcess = @()
20 | # FormatsToProcess = @()
21 | # NestedModules = @()
22 | FunctionsToExport = @()
23 | CmdletsToExport = @()
24 | # VariablesToExport = @()
25 | AliasesToExport = @()
26 | # DscResourcesToExport = @()
27 | # ModuleList = @()
28 | # FileList = @()
29 | PrivateData = @{
30 | PSData = @{
31 | # Tags applied to this module. These help with module discovery in online galleries.
32 | Tags = 'Module', 'Builder', 'Publishing', 'Template', 'CI', 'CD', 'CI/CD'
33 | # A URL to the license for this module.
34 | LicenseUri = 'https://github.com/markekraus/PSPublishHelper/blob/master/LICENSE'
35 | # A URL to the main website for this project.
36 | ProjectUri = 'https://github.com/markekraus/PSPublishHelper'
37 | # A URL to an icon representing this module.
38 | # IconUri = ''
39 | # ReleaseNotes of this module
40 | # ReleaseNotes = ''
41 | } # End of PSData hashtable
42 | } # End of PrivateData hashtable
43 | # HelpInfoURI = ''
44 | # DefaultCommandPrefix = ''
45 | }
46 |
--------------------------------------------------------------------------------
/src/PSPublishHelper/PSPublishHelper.psm1:
--------------------------------------------------------------------------------
1 | $Script:Nuspec = @"
2 |
3 |
4 |
5 | {0}
6 | {1}
7 | {2}
8 | {3}
9 | {4}
10 | {5}
11 | {6}
12 | {7}
13 | {8}
14 | {9}
15 | {10}
16 | {11}
17 |
18 | {12}
19 |
20 |
21 |
22 | "@
--------------------------------------------------------------------------------
/src/PSPublishHelper/private/Copy-PSModule.ps1:
--------------------------------------------------------------------------------
1 | function Copy-PSModule {
2 | [CmdletBinding()]
3 | param (
4 | [Parameter(Mandatory)]
5 | [ValidateNotNull()]
6 | [PSModuleInfo]
7 | $Module,
8 |
9 | [Parameter(Mandatory)]
10 | [ValidateNotNullOrEmpty()]
11 | [string]
12 | $Path
13 | )
14 | end {
15 | $Params = @{
16 | Path = $Path
17 | Recurse = $true
18 | Force = $true
19 | ErrorAction = 'SilentlyContinue'
20 | }
21 | Microsoft.PowerShell.Management\Remove-Item @Params
22 | $Params = @{
23 | Path = $Path
24 | ItemType = 'Directory'
25 | Force = $true
26 | }
27 | $null = Microsoft.PowerShell.Management\New-Item @Params
28 | Microsoft.PowerShell.Management\Get-ChildItem $Module.ModuleBase -recurse |
29 | ForEach-Object {
30 | if ($_.PSIsContainer) {
31 | $Params = @{
32 | Force = $true
33 | Confirm = $false
34 | WhatIf = $false
35 | Recurse = $true
36 | Container = $true
37 | Destination = $Path
38 | }
39 | $_ | Microsoft.PowerShell.Management\Copy-Item @Params
40 | } else {
41 | $Params = @{
42 | Force = $true
43 | Confirm = $false
44 | WhatIf = $false
45 | Destination = $Path
46 | }
47 | $_ | Microsoft.PowerShell.Management\Copy-Item @Params
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/PSPublishHelper/private/Format-PSModuleDependency.ps1:
--------------------------------------------------------------------------------
1 | function Format-PSModuleDependency {
2 | [OutputType([string])]
3 | [CmdletBinding()]
4 | param (
5 | [Parameter(ValueFromPipeline)]
6 | [Microsoft.PowerShell.Commands.ModuleSpecification]
7 | $Dependency
8 | )
9 | process {
10 | if (-not $Dependency) {
11 | return
12 | }
13 | $Version = [string]::Empty
14 | # Version format in NuSpec:
15 | # "[2.0]" --> (== 2.0) Required Version
16 | # "2.0" --> (>= 2.0) Minimum Version
17 | #
18 | # When only MaximumVersion is specified in the ModuleSpecification
19 | # (,1.0] = x <= 1.0
20 | #
21 | # When both Minimum and Maximum versions are specified in the ModuleSpecification
22 | # [1.0,2.0] = 1.0 <= x <= 2.0
23 | if($Dependency.RequiredVersion) {
24 | $Version = "[{0}]" -f $Dependency.RequiredVersion
25 | } elseif($Dependency.Version -and $Dependency.MaximumVersion) {
26 | $Version = "[{0},{1}]" -f $Dependency.Version, $Dependency.MaximumVersion
27 | } elseif($Dependency.MaximumVersion) {
28 | $Version = "(,{0}]" -f $Dependency.MaximumVersion
29 | } elseif($Dependency.Version) {
30 | $Version = "{0}" -f $Dependency.Version
31 | }
32 |
33 | if ([System.string]::IsNullOrWhiteSpace($Version)) {
34 | "" -f $Dependency.Name
35 | } else {
36 | "" -f $Dependency.Name, $Version
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/PSPublishHelper/private/Get-AvailableRoleCapabilityName.ps1:
--------------------------------------------------------------------------------
1 | function Get-AvailableRoleCapabilityName {
2 | [CmdletBinding()]
3 | Param (
4 | [Parameter(Mandatory=$true)]
5 | [ValidateNotNullOrEmpty()]
6 | [PSModuleInfo]
7 | $Module
8 | )
9 |
10 | $RoleCapabilitiesDir = Join-Path $Module.ModuleBase 'RoleCapabilities'
11 | if(Microsoft.PowerShell.Management\Test-Path -Path $RoleCapabilitiesDir -PathType Container)
12 | {
13 | $Params = @{
14 | Path = $RoleCapabilitiesDir
15 | Filter = '*.psrc'
16 | }
17 | Microsoft.PowerShell.Management\Get-ChildItem @Params |
18 | ForEach-Object -MemberName BaseName
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/PSPublishHelper/private/Get-EscapedString.ps1:
--------------------------------------------------------------------------------
1 | function Get-EscapedString
2 | {
3 | [CmdletBinding()]
4 | [OutputType([String])]
5 | Param (
6 | [Parameter(ValueFromPipeline)]
7 | [string]
8 | $Value
9 | )
10 |
11 | process {
12 | [System.Security.SecurityElement]::Escape($Value)
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/PSPublishHelper/private/Get-ExportedDscResources.ps1:
--------------------------------------------------------------------------------
1 | function Get-ExportedDscResources {
2 | [CmdletBinding()]
3 | Param(
4 | [Parameter(Mandatory=$true)]
5 | [ValidateNotNullOrEmpty()]
6 | [PSModuleInfo]
7 | $Module
8 | )
9 |
10 | $Params = @{
11 | Name = 'Get-DscResource'
12 | Module = 'PSDesiredStateConfiguration'
13 | ErrorAction = 'Ignore'
14 | }
15 | if(-not $script:IsCoreCLR -and (Get-Command @Params)) {
16 | $OldPSModulePath = $env:PSModulePath
17 |
18 | try {
19 | $env:PSModulePath = Join-Path -Path $PSHOME -ChildPath "Modules"
20 | $ModuleBaseParent = Split-Path -Path $Module.ModuleBase -Parent
21 | $env:PSModulePath = "{0}{1}{2}" -f @(
22 | $env:PSModulePath,
23 | [System.IO.Path]::PathSeparator,
24 | $ModuleBaseParent
25 | )
26 |
27 | $Params = @{
28 | ErrorAction = 'SilentlyContinue'
29 | WarningAction = 'SilentlyContinue'
30 | }
31 | PSDesiredStateConfiguration\Get-DscResource @Params |
32 | Microsoft.PowerShell.Core\ForEach-Object {
33 | if(
34 | $_.Module -and
35 | $_.Module.Name -eq $Module.Name
36 | ){
37 | $_.Name
38 | }
39 | }
40 | } finally {
41 | $env:PSModulePath = $OldPSModulePath
42 | }
43 | } else {
44 | $dscResourcesDir = Join-Path $Module.ModuleBase "DscResources"
45 | if(Microsoft.PowerShell.Management\Test-Path $dscResourcesDir) {
46 | Microsoft.PowerShell.Management\Get-ChildItem -Path $dscResourcesDir -Directory -Name
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/PSPublishHelper/private/Get-NupkgFilePath.ps1:
--------------------------------------------------------------------------------
1 | function Get-NupkgFilePath {
2 | [CmdletBinding()]
3 | param (
4 | [Parameter(Mandatory)]
5 | [ValidateNotNull()]
6 | [PSModuleInfo]
7 | $Module,
8 |
9 | [Parameter(Mandatory)]
10 | [ValidateNotNullOrEmpty()]
11 | [string]
12 | $Path
13 | )
14 | end {
15 | $PSData = Resolve-PSData -Module $Module
16 | $Version = Resolve-PSModuleVersion -Module $Module -PSData $PSData
17 | $FileName = '{0}.{1}.nupkg' -f $Module.Name, $Version
18 | Join-Path $Path $FileName
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/PSPublishHelper/private/Get-NuspecContents.ps1:
--------------------------------------------------------------------------------
1 | function Get-NuspecContents {
2 | [OutputType([String])]
3 | [CmdletBinding()]
4 | param (
5 | [PSModuleInfo]
6 | $Module,
7 |
8 | [Hashtable]
9 | $PSData
10 | )
11 | end {
12 |
13 | $VersionText = Resolve-PSModuleVersion -Module $Module -PSData $PSData
14 |
15 | $TagsText = Resolve-PSModuleTags -Module $Module -Tags $PSData.Tags
16 |
17 | $RequireLicenseAcceptanceText = ([bool]$PSData.RequireLicenseAcceptance).ToString().ToLower()
18 |
19 | $Description = $Module.Description
20 | if ([string]::IsNullOrWhiteSpace($Description)) {
21 | $Description = $Module.Name
22 | }
23 |
24 | $ArgumentList = [System.Collections.Generic.List[string]]::new()
25 | @(
26 | $Module.Name,
27 | $VersionText,
28 | $Module.Author,
29 | $Module.CompanyName,
30 | $Description,
31 | $Module.ReleaseNotes,
32 | $RequireLicenseAcceptanceText,
33 | $Module.Copyright,
34 | $TagsText
35 | ) | Get-EscapedString | ForEach-Object {
36 | $ArgumentList.Add($_)
37 | }
38 |
39 | $LicenseUriText = if ($PSData.LicenseUri) {
40 | '{0}' -f ($PSData.LicenseUri | Get-EscapedString)
41 | }
42 | $ArgumentList.Add($LicenseUriText)
43 |
44 | $ProjectUriText = if ($PSData.ProjectUri) {
45 | '{0}' -f ($PSData.ProjectUri | Get-EscapedString)
46 | }
47 | $ArgumentList.Add($ProjectUriText)
48 |
49 | $IconUriText = if ($PSData.IconUri) {
50 | '{0}' -f ($PSData.IconUri | Get-EscapedString)
51 | }
52 | $ArgumentList.Add($IconUriText)
53 |
54 | $DependencyText = @(
55 | $Module | Resolve-PSModuleDependency -ExternalModuleDependencies $PSData.ExternalModuleDependencies | Format-PSModuleDependency
56 | ) -Join ([Environment]::NewLine)
57 | $ArgumentList.Add($DependencyText)
58 |
59 | $Script:Nuspec -f $ArgumentList.ToArray()
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/PSPublishHelper/private/Get-NuspecFilePath.ps1:
--------------------------------------------------------------------------------
1 | function Get-NuspecFilePath {
2 | [CmdletBinding()]
3 | param (
4 | [Parameter(Mandatory)]
5 | [ValidateNotNull()]
6 | [PSModuleInfo]
7 | $Module,
8 |
9 | [Parameter(Mandatory)]
10 | [ValidateNotNullOrEmpty()]
11 | [string]
12 | $Path
13 | )
14 | end {
15 | $FileName = '{0}.nuspec' -f $Module.Name
16 | Join-Path $Path $FileName
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/PSPublishHelper/private/Get-PSModuleManifestData.ps1:
--------------------------------------------------------------------------------
1 | function Get-PSModuleManifestData {
2 | [CmdletBinding()]
3 | param (
4 | [Parameter(Mandatory,ValueFromPipeline)]
5 | [ValidateNotNull()]
6 | [PSModuleInfo]
7 | $Module
8 | )
9 | process {
10 | if ($Module.Path -match '\.psd1$') {
11 | $Manifest = $Module.Path
12 | } else {
13 | $ManifestName = '{0}.psd1' -f $Module.Name
14 | $Manifest = Join-Path $Module.ModuleBase $ManifestName
15 | }
16 | Import-PowerShellDataFile -Path $Manifest
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/PSPublishHelper/private/Get-TemporaryPath.ps1:
--------------------------------------------------------------------------------
1 | function Get-TemporaryPath {
2 | [OutputType([string])]
3 | [CmdletBinding()]
4 | param (
5 | [Parameter(Mandatory,ValueFromPipeline)]
6 | [ValidateNotNull()]
7 | [PSModuleInfo]
8 | $Module
9 | )
10 | process {
11 | $Base = Join-Path ([System.IO.Path]::GetTempPath()) (Get-Random)
12 | Join-Path $Base $Module.Name
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/PSPublishHelper/private/Resolve-NugetCommand.ps1:
--------------------------------------------------------------------------------
1 | function Resolve-NugetCommand {
2 | [CmdletBinding()]
3 | param (
4 | [Parameter()]
5 | [System.Management.Automation.PSCmdlet]
6 | $Cmdlet
7 | )
8 | end {
9 | $ErrorCmdlet = $Cmdlet
10 | if (-not $Cmdlet) {
11 | $ErrorCmdlet = $PSCmdlet
12 | }
13 | $Params = @{
14 | Name = 'nuget'
15 | CommandType = 'Application'
16 | ErrorAction = 'SilentlyContinue'
17 | }
18 | $Nuget = Get-Command @Params | Select-Object -First 1
19 | if(-not $Nuget) {
20 | $ErrorRecord = [System.Management.Automation.ErrorRecord]::new(
21 | [System.Management.Automation.ItemNotFoundException]::new(
22 | "Unable to find nuget binary. Nuget is required"
23 | ),
24 | "NugetNotFound",
25 | [System.Management.Automation.ErrorCategory]::NotInstalled,
26 | $null
27 | )
28 | $ErrorCmdlet.ThrowTerminatingError($ErrorRecord)
29 | }
30 | $Nuget
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/PSPublishHelper/private/Resolve-PSData.ps1:
--------------------------------------------------------------------------------
1 | function Resolve-PSData {
2 | [OutputType([Hashtable])]
3 | [CmdletBinding()]
4 | param (
5 | [PSModuleInfo]
6 | $Module,
7 |
8 | [string]
9 | $ReleaseNotes,
10 |
11 | [string[]]
12 | $Tags,
13 |
14 | [Uri]
15 | $LicenseUri,
16 |
17 | [Uri]
18 | $IconUri,
19 |
20 | [Uri]
21 | $ProjectUri
22 | )
23 | end {
24 | $Result = @{}
25 | $PSData = @{
26 | ReleaseNotes = $ReleaseNotes
27 | Tags = $Tags
28 | LicenseUri = $LicenseUri
29 | IconUri = $IconUri
30 | ProjectUri = $ProjectUri
31 | Prerelease = $null
32 | RequireLicenseAcceptance = $null
33 | ExternalModuleDependencies = @()
34 | }
35 | foreach ($item in $PSData.GetEnumerator()) {
36 | $key = $item.key
37 | $Result[$key] = $item.value
38 | if (-not $item.value -and $key -ne 'Prerelease') {
39 | $Result[$key] = $Module.PrivateData.PSdata.$key
40 | } elseif (-not $item.value -and $key -eq 'Prerelease') {
41 | $Result[$key] = $Module.PrivateData.PSData.$key
42 | }
43 | Write-Verbose "$($key): $($Result[$key])"
44 | }
45 | $Result
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/PSPublishHelper/private/Resolve-PSModule.ps1:
--------------------------------------------------------------------------------
1 | function Resolve-PSModule {
2 | [OutputType([System.Management.Automation.PSModuleInfo])]
3 | [CmdletBinding()]
4 | param (
5 | [Parameter()]
6 | [System.Management.Automation.PSCmdlet]
7 | $Cmdlet,
8 |
9 | [Parameter()]
10 | [string]
11 | $Name,
12 |
13 | [Parameter()]
14 | [string]
15 | $RequiredVersion
16 | )
17 | end {
18 | if($Cmdlet) {
19 | $ErrorCmdlet = $Cmdlet
20 | } else {
21 | $ErrorCmdlet = $PSCmdlet
22 | }
23 |
24 | $Version, $Prerelease = $RequiredVersion -split '-', 2
25 |
26 | $Filter = {
27 | $_.Version.ToString() -eq $Version -and
28 | (
29 | $_.PrivateData.PSData.Prerelease -eq $Prerelease -or
30 | $_.PrivateData.PSData.Prerelease -eq "-$Prerelease"
31 | )
32 | }
33 |
34 | $Result = Get-Module -ListAvailable -Name $Name |
35 | Where-Object -FilterScript $Filter |
36 | Select-Object -First 1
37 |
38 | if (-not $Result) {
39 | $ErrorRecord = [System.Management.Automation.ErrorRecord]::new(
40 | [System.Management.Automation.ItemNotFoundException]::new(
41 | "Unable to find Module $Name Version $RequiredVersion"
42 | ),
43 | "ModuleNotFound",
44 | [System.Management.Automation.ErrorCategory]::InvalidArgument,
45 | $null
46 | )
47 | $ErrorCmdlet.ThrowTerminatingError($ErrorRecord)
48 | }
49 | $Result
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/PSPublishHelper/private/Resolve-PSModuleDependency.ps1:
--------------------------------------------------------------------------------
1 | function Resolve-PSModuleDependency {
2 | [OutputType([Microsoft.PowerShell.Commands.ModuleSpecification])]
3 | [CmdletBinding()]
4 | param (
5 | [Parameter(Mandatory, ValueFromPipeline)]
6 | [PSModuleInfo]
7 | $Module,
8 |
9 | [String[]]
10 | $ExternalModuleDependencies
11 | )
12 | process {
13 | # The manifest contains the actual ModuleSpec used for Version requirements
14 | $ModuleData = $Module | Get-PSModuleManifestData
15 |
16 | # A module in RequiredModules is not a dependency if it's listed in ExternalModuleDependencies
17 | $ModuleData.RequiredModules | Resolve-PSModuleInfo | Where-Object {
18 | $_.Name -notin $ExternalModuleDependencies
19 | }
20 |
21 | $NestModuleInfo = $ModuleData.NestedModules | Resolve-PSModuleInfo
22 |
23 | # A module in NestedModules become a dependency
24 | # when it is not not packaged with the module
25 | $NestedDependencies = $Module.NestedModules | Where-Object {
26 | -not $_.ModuleBase.StartsWith($Module.ModuleBase, [System.StringComparison]::OrdinalIgnoreCase) -or
27 | -not $_.Path -or
28 | -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $_.Path)
29 | } | Foreach-Object -MemberName Name
30 |
31 | $NestModuleInfo | Where-Object {$_.Name -in $NestedDependencies}
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/PSPublishHelper/private/Resolve-PSModuleInfo.ps1:
--------------------------------------------------------------------------------
1 | function Resolve-PSModuleInfo {
2 | [OutputType([Microsoft.PowerShell.Commands.ModuleSpecification])]
3 | [CmdletBinding()]
4 | param (
5 | [Parameter(ValueFromPipeline)]
6 | [PSObject]
7 | $InputObject
8 | )
9 |
10 | process {
11 | # '*' can be specified in the MaximumVersion of a ModuleSpecification to convey
12 | # that maximum possible value of that version part.
13 | # like 1.0.0.* --> 1.0.0.99999999
14 | if($InputObject.MaximumVersion){
15 | $InputObject.MaximumVersion = $InputObject.MaximumVersion -replace '\*','99999999'
16 | }
17 |
18 | [Microsoft.PowerShell.Commands.ModuleSpecification]$InputObject
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/PSPublishHelper/private/Resolve-PSModuleTags.ps1:
--------------------------------------------------------------------------------
1 | function Resolve-PSModuleTags {
2 | [CmdletBinding()]
3 | param (
4 | [PSModuleInfo]
5 | $Module,
6 |
7 | [String[]]
8 | $Tags
9 | )
10 | end {
11 | $TagsList = [System.Collections.Generic.HashSet[String]]::new()
12 | foreach($Tag in $Tags) {
13 | $null = $TagsList.Add($Tag)
14 | }
15 |
16 | $null = $TagsList.add('PSModule')
17 |
18 | foreach($Cmdlet in $Module.ExportedCmdlets.Keys) {
19 | $null = $TagsList.Add('PSIncludes_Cmdlet')
20 | $null = $TagsList.add(('PSCmdlet_{0}' -f $Cmdlet))
21 | }
22 |
23 | foreach($Func in $Module.ExportedFunctions.Keys) {
24 | $null = $TagsList.Add('PSIncludes_Function')
25 | $null = $TagsList.add(('PSFunction_{0}' -f $func))
26 | }
27 |
28 | foreach($Command in $Module.ExportedCommands.Keys) {
29 | $null = $TagsList.add(('PSCommand_{0}' -f $Command))
30 | }
31 |
32 | if(!$IsCoreCLR) {
33 | foreach ($DscResource in (Get-ExportedDscResources -Module $Module -ErrorAction SilentlyContinue)) {
34 | $null = $TagsList.Add('PSIncludes_DscResource')
35 | $null = $TagsList.add(('PSDscResource_{0}' -f $DscResource))
36 | }
37 | } else {
38 | Write-Verbose 'Skipping DSC resource enumeration as it is not supported on PS Core.'
39 | Write-Verbose 'Please use Windows PowerShell to build DSC modules.'
40 | }
41 |
42 |
43 | foreach ($Role in (Get-AvailableRoleCapabilityName -Module $Module)) {
44 | $null = $TagsList.Add('PSIncludes_RoleCapability')
45 | $null = $TagsList.add(('PSRoleCapability_{0}' -f $Role))
46 | }
47 |
48 | $TagsList -join ' '
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/PSPublishHelper/private/Resolve-PSModuleVersion.ps1:
--------------------------------------------------------------------------------
1 | function Resolve-PSModuleVersion {
2 | [OutputType([string])]
3 | [CmdletBinding()]
4 | param (
5 | [Parameter()]
6 | [PsModuleInfo]
7 | $Module,
8 |
9 | [Parameter()]
10 | [Hashtable]
11 | $PSData
12 | )
13 | end {
14 | $Version = [string]$Module.Version
15 | if($PSData.Prerelease) {
16 | $Prerelease = $PSData.Prerelease
17 | if($Prerelease.StartsWith('-')) {
18 | $version = '{0}{1}' -f $Version, $Prerelease
19 | } else {
20 | $version = '{0}-{1}' -f $Version, $Prerelease
21 | }
22 | }
23 | $Version
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/PSPublishHelper/public/Publish-PSModuleNuget.ps1:
--------------------------------------------------------------------------------
1 | function Publish-PSModuleNuget {
2 | [CmdletBinding(DefaultParameterSetName = 'NameAndVersion')]
3 | param (
4 | [Parameter(
5 | Mandatory,
6 | ParameterSetName = 'NameAndVersion'
7 | )]
8 | [ValidateNotNullOrEmpty()]
9 | [string]
10 | $Name,
11 |
12 | [Parameter(
13 | Mandatory,
14 | ParameterSetName = 'NameAndVersion'
15 | )]
16 | [ValidateNotNullOrEmpty()]
17 | [string]
18 | $RequiredVersion,
19 |
20 | [Parameter(
21 | Mandatory,
22 | ParameterSetName = 'PSModuleInfo',
23 | ValueFromPipeline
24 | )]
25 | [ValidateNotNull()]
26 | [PSModuleInfo]
27 | $InputObject,
28 |
29 | [Parameter(
30 | Mandatory,
31 | ParameterSetName = 'NameAndVersion'
32 | )]
33 | [Parameter(
34 | Mandatory,
35 | ParameterSetName = 'PSModuleInfo'
36 | )]
37 | [ValidateNotNullOrEmpty()]
38 | [ValidateScript({
39 | if(-not (Test-Path -PathType Container -Path $_)){throw}
40 | else {$true}
41 | })]
42 | [string]
43 | $OutputPath,
44 |
45 | [Parameter(Mandatory = $false, ParameterSetName = 'PSModuleInfo')]
46 | [Parameter(Mandatory = $false, ParameterSetName = 'NameAndVersion')]
47 | [string]
48 | $ReleaseNotes,
49 |
50 | [Parameter(Mandatory = $false, ParameterSetName = 'PSModuleInfo')]
51 | [Parameter(Mandatory = $false, ParameterSetName = 'NameAndVersion')]
52 | [string[]]
53 | $Tags,
54 |
55 | [Parameter(Mandatory = $false, ParameterSetName = 'PSModuleInfo')]
56 | [Parameter(Mandatory = $false, ParameterSetName = 'NameAndVersion')]
57 | [Uri]
58 | $LicenseUri,
59 |
60 | [Parameter(Mandatory = $false, ParameterSetName = 'PSModuleInfo')]
61 | [Parameter(Mandatory = $false, ParameterSetName = 'NameAndVersion')]
62 | [Uri]
63 | $IconUri,
64 |
65 | [Parameter(Mandatory = $false, ParameterSetName = 'PSModuleInfo')]
66 | [Parameter(Mandatory = $false, ParameterSetName = 'NameAndVersion')]
67 | [Uri]
68 | $ProjectUri,
69 |
70 | [Parameter(Mandatory = $false, ParameterSetName = 'PSModuleInfo')]
71 | [Parameter(Mandatory = $false, ParameterSetName = 'NameAndVersion')]
72 | [Switch]
73 | $PassThru
74 | )
75 |
76 | begin {
77 | $Nuget = Resolve-NugetCommand -Cmdlet $PSCmdlet -ErrorAction Stop
78 | Write-Verbose "Nuget found at $($Nuget.Path)"
79 | $OutputPath = Convert-Path $OutputPath -ErrorAction Stop
80 | Write-Verbose "Output Path: $OutputPath"
81 | }
82 |
83 | process {
84 | if($PSCmdlet.ParameterSetName -eq 'NameAndVersion') {
85 | $Params = @{
86 | Cmdlet = $PSCmdlet
87 | Name = $Name
88 | RequiredVersion = $RequiredVersion
89 | ErrorAction = 'stop'
90 | }
91 | $InputObject = Resolve-PSModule @Params
92 | }
93 |
94 | Write-Verbose "Using Module from $($InputObject.ModuleBase)"
95 |
96 | $Params = @{
97 | IconUri = $IconUri
98 | ReleaseNotes = $ReleaseNotes
99 | Module = $InputObject
100 | Tags = $Tags
101 | ProjectUri = $ProjectUri
102 | LicenseUri = $LicenseUri
103 | }
104 | $PSData = Resolve-PSData @Params
105 |
106 | $Params = @{
107 | Module = $InputObject
108 | PSData = $PSData
109 | ErrorAction = 'stop'
110 | }
111 | $NuspecContents = Get-NuspecContents @Params
112 |
113 | $TempPath = $InputObject | Get-TemporaryPath
114 | try {
115 | Copy-PSModule -Module $InputObject -Path $TempPath -ErrorAction Stop
116 | $NuspecPath = Get-NuspecFilePath -Module $InputObject -Path $TempPath -ErrorAction Stop
117 | $NuspecContents | Set-Content -Path $NuspecPath -Force -Confirm:$false -WhatIf:$false -ErrorAction Stop
118 | $NupkgFilePath = Get-NupkgFilePath -Module $InputObject -Path $OutputPath -ErrorAction Stop
119 | Push-Location -StackName PSPublishHelperNugetPack -Path $TempPath -ErrorAction Stop
120 | $Output = & $Nuget pack $NuspecPath -OutputDirectory $OutputPath -BasePath $TempPath -Verbosity detailed -NonInteractive -NoDefaultExcludes
121 | Write-Verbose "Nuget Pack Output:"
122 | foreach($Line in $Output) {
123 | if($Line -notmatch 'NU5110|NU5111'){
124 | Write-Verbose $Line
125 | }
126 | }
127 | }
128 | finally {
129 | Pop-Location -StackName PSPublishHelperNugetPack
130 | $Params = @{
131 | Path = Split-path -Parent $TempPath
132 | Recurse = $true
133 | Force = $true
134 | ErrorAction = 'SilentlyContinue'
135 | }
136 | Microsoft.PowerShell.Management\Remove-Item @Params
137 | }
138 |
139 | if($PassThru) {
140 | Get-item -Path $NupkgFilePath -ErrorAction SilentlyContinue
141 | }
142 | }
143 | }
144 |
--------------------------------------------------------------------------------