-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathInitialize-Module.ps1
More file actions
146 lines (131 loc) · 5.82 KB
/
Copy pathInitialize-Module.ps1
File metadata and controls
146 lines (131 loc) · 5.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
<#
.SYNOPSIS
Initializes the module's environment by verifying and loading configuration and supporting script files.
.DESCRIPTION
Initializes the module's environment by verifying and loading configuration and supporting script files.
Use with PowerShell modules with complex file layouts, dependencies, and custom types.
.NOTES
Add filenames manually to $ClassFileNames, $InternalScriptFileNames, and $ExportedFunctionFileNames as appropriate.
Call the Test-Dependency function from any module file to ensure that all required types are loaded before executing dependent code.
.PARAMETER ConfigurationFileName
The name of the module configuration file. Must exist in the same location as the module's PSM1 file. Defaults to 'Configuration.psd1'.
.PARAMETER InternalScriptsFolderName
The name of the folder containing internal script files. Must exist in the same location as the module's PSM1 file. Defaults to 'Internal'.
.PARAMETER PublicScriptsFolderName
The name of the folder containing public script files. Must exist in the same location as the module's PSM1 file. Defaults to 'Public'.
.PARAMETER TypesFolderName
The name of the folder containing type definition files. Must exist in the same location as the module's PSM1 file. Defaults to 'Types'.
.PARAMETER NoConfigurationFile
Skips verifying and loading the module configuration file.
.PARAMETER NoInternalScripts
Skips verifying and loading of internal script files.
.PARAMETER NoPublicScripts
Skips verifying and loading of public script files.
.PARAMETER NoTypes
Skips verifying and loading of class definition files.
#>
[CmdletBinding()]
param(
[Parameter()][String]$ConfigurationFileName = 'Configuration.psd1',
[Parameter()][String]$InternalScriptsFolderName = 'Internal',
[Parameter()][String]$PublicScriptsFolderName = 'Public',
[Parameter()][String]$TypesFolderName = 'Types',
[Parameter()][Switch]$NoConfigurationFile,
[Parameter()][Switch]$NoInternalScripts,
[Parameter()][Switch]$NoPublicScripts,
[Parameter()][Switch]$NoTypes
)
begin
{
# Class files load in named order; consider dependencies when ordering files
# Place class files in ./Types
$ClassFileNames = @()
# Place internal script files in ./Internal
$InternalScriptFileNames = @()
# Place public script files in ./Public
# Remember to update psd1 file ExportedFunctions list when adding new public scripts
$ExportedFunctionFileNames = @()
# define the locations to look for supporting files
$RootModuleFolder = $MyInvocation.PSScriptRoot
$ConfigurationFile = Join-Path -Path $RootModuleFolder -ChildPath $ConfigurationFileName
$InternalScriptsFolder = Join-Path -Path $RootModuleFolder -ChildPath $InternalScriptsFolderName
$PublicScriptsFolder = Join-Path -Path $RootModuleFolder -ChildPath $PublicScriptsFolderName
$TypesFolder = Join-Path -Path $RootModuleFolder -ChildPath $TypesFolderName
<#
.DESCRIPTION
Tests whether the specified dependency types are available. Call from module files to ensure that all required types are loaded before executing dependent code.
.PARAMETER DependencyName
The name[s] of the dependency types to test.
#>
function Test-Dependency
{
[CmdletBinding()]
param (
[Parameter(Position = 1)][string[]]$DependencyName
)
process
{
if ($DependencyName -eq $null -or $DependencyName.Count -eq 0)
{
Write-Error -Message "Dependency name cannot be null or empty. Invoked by $($MyInvocation.ScriptName)" -ErrorAction Stop
}
foreach ($Name in $DependencyName)
{
try
{
$testtype = [Type]$Name
}
catch
{
Write-Error -Message "Type '$Name' required by '$($MyInvocation.ScriptName)' not found. Ensure that the required supporting scripts have been dot-sourced." -ErrorAction Stop
}
}
}
}
}
process
{
# check that all files exist
@(
@{ItemPath = $ConfigurationFile; ItemType = 'Leaf'; Description = 'module configuration data file'; SkipCheck = $NoConfigurationFile},
@{ItemPath = $InternalScriptsFolder; ItemType = 'Container'; Description = 'internal scripts folder'; SkipCheck = $NoInternalScripts},
@{ItemPath = $PublicScriptsFolder; ItemType = 'Container'; Description = 'public scripts folder'; SkipCheck = $NoPublicScripts},
@{ItemPath = $TypesFolder; ItemType = 'Container'; Description = 'class definitions folder'; SkipCheck = $NoTypes}
) | ForEach-Object -Process {
if (-not ($_.SkipCheck) -and -not (Test-Path -Path $_.ItemPath -PathType $_.ItemType))
{
Write-Error -Message "Item '$($_.Description)' not found at path '$($_.ItemPath)'." -ErrorAction Stop
}
}
# load the configuration
if (-not $NoConfigurationFile)
{
New-Variable -Scope Script -Name ModuleConfig -Value (New-Object -TypeName 'System.Collections.Hashtable')
$RawConfigData = Import-PowerShellDataFile -Path $ConfigurationFile
foreach ($ConfigKey in $RawConfigData.Keys)
{
$ConfigValue = $RawConfigData[$ConfigKey]
if ($ConfigValue -is [string])
{
$ConfigValue = [System.Environment]::ExpandEnvironmentVariables($ConfigValue)
}
$script:ModuleConfig[$ConfigKey] = $ConfigValue
}
}
# dot-source files in order of dependencies (classes, then internal scripts, then public scripts)
@(
@{FileGroup = $ClassFileNames; Description = 'class definition'; FileGroupPath = $TypesFolder; SkipCheck = $NoTypes},
@{FileGroup = $InternalScriptFileNames; Description = 'internal script'; FileGroupPath = $InternalScriptsFolder; SkipCheck = $NoInternalScripts},
@{FileGroup = $ExportedFunctionFileNames; Description = 'exported function'; FileGroupPath = $PublicScriptsFolder; SkipCheck = $NoPublicScripts}
) | ForEach-Object -Process {
foreach ($FileName in ($_.FileGroup))
{
$FilePath = Join-Path -Path $_.FileGroupPath -ChildPath $FileName
if (-not (Test-Path -Path $FilePath -PathType 'Leaf'))
{
Write-Error -Message "Required $($_.Description) file not found at path '$FilePath'." -ErrorAction Stop
}
. $FilePath
}
}
}