Private/Environment.ps1
using namespace System.Collections.Generic using namespace System.IO using namespace System.Management.Automation <#TODO: Test#> function GetFunctionDefinition { param( [Parameter(Mandatory=$true)][String]$CommandName ) # Using AST because -ExpandProperty Definition adds a /r/n to the beginning and end of the line # and instead of hoping all powershell versions work the same way, this is safer than manipulating # any text. #TODO: EndBlock isn't always foolproof, figure out a better way of combining body return (Get-ChildItem function:\$CommandName).ScriptBlock.Ast.Body.EndBlock.ToString() } <#TODO: Test#> function GetAliasDefinition { param( [Parameter(Mandatory=$true)][String]$CommandName ) return (Get-ChildItem alias:\$CommandName).Definition } <#FULLY TESTED#> function GetValidModuleProject { return Get-ChildItem ($ModuleProjectsFolder) | Where-Object { $files = Get-ChildItem $_.FullName -File | Select-Object -Property Name $directories = Get-ChildItem $_.FullName -Directory | Select-Object -Property Name $ModuleName = $_.BaseName; return $files -and ` ( $files -match "$ModuleName.psd1" -and ` $files -match "$ModuleName.psm1" ) -and ` $directories -and ` ( $directories -match "Functions" -and ` $directories -match "Aliases" ) } } function GetCommandEnvironmentVariables { #Todo: Replace many instances of Get-ChildItem and Get-ValidModuleProject with this to save on processing $_ValidModuleProjects = (GetValidModuleProject) $_ModuleProjects = [Dictionary[String, List[String]]]::new() $_ModuleProjectInfos = [Dictionary[String, FileSystemInfo]]::new() $_ModuleProjectCommands = [Dictionary[String, FileSystemInfo]]::new() $_ModuleProjectCommandFiles = [Dictionary[String, FileSystemInfo]]::new() $_ModuleProjectCommandDefinitions = [Dictionary[String,String]]::new() $_ModuleProjectCommandTypes = [Dictionary[String,String]]::new() foreach($_ModuleProject in $_ValidModuleProjects) { $_ModuleProjects[$_ModuleProject.Name] = [List[String]]::new() $_ModuleProjectInfos[$_ModuleProject.Name] = $_ModuleProject $_ModuleProjectFunctions = (Get-ChildItem "$($_ModuleProject.FullName)\Functions") foreach ($_Function in $_ModuleProjectFunctions) { $_FunctionName = $_Function.BaseName . $_Function.FullName $_ModuleProjects[$_ModuleProject.Name].Add($_FunctionName) $_ModuleProjectCommands[$_FunctionName] = $_ModuleProject $_ModuleProjectCommandFiles[$_FunctionName] = $_Function $_ModuleProjectCommandDefinitions[$_FunctionName] = GetFunctionDefinition -CommandName $_FunctionName $_ModuleProjectCommandTypes[$_FunctionName] = 'Function' } $_ModuleProjectAliases = (Get-ChildItem "$($_ModuleProject.FullName)\Aliases") foreach ($_Alias in $_ModuleProjectAliases) { $_AliasName = $_Alias.BaseName . $_Alias.FullName $_ModuleProjects[$_ModuleProject.Name].Add($_AliasName) $_ModuleProjectCommands[$_AliasName] = $_ModuleProject $_ModuleProjectCommandFiles[$_AliasName] = $_Alias $_ModuleProjectCommandDefinitions[$_AliasName] = GetAliasDefinition -CommandName $_AliasName $_ModuleProjectCommandTypes[$_AliasName] = 'Alias' } } return $_ModuleProjects, $_ModuleProjectInfos, $_ModuleProjectCommands, $_ModuleProjectCommandFiles, $_ModuleProjectCommandTypes, $_ModuleProjectCommandDefinitions } function GetDefinitionForCommand { param( [Parameter()][String] $CommandName ) if (!$_ModuleProjectCommandDefinitions) { if ($IsProduction) { throw 'This should be cached. If you''re seeing this, the Module would be running super slowly' } $_, $_, $_,$_,$_,$_ModuleProjectCommandDefinitions = (GetCommandEnvironmentVariables) } return $_ModuleProjectCommandDefinitions[$CommandName] } function GetFileForCommand { param( [Parameter()][String] $CommandName ) if (!$_ModuleProjectCommandFiles) { if ($IsProduction) { throw 'This should be cached. If you''re seeing this, the Module would be running super slowly' } $_, $_, $_,$_ModuleProjectCommandFiles,$_,$_ = (GetCommandEnvironmentVariables) } return $_ModuleProjectCommandFiles[$CommandName] } function GetModuleProjectTypeForCommand { param( [Parameter()][String] $CommandName ) if (!$_ModuleProjectCommandTypes) { if ($IsProduction) { throw 'This should be cached. If you''re seeing this, the Module would be running super slowly' } $_, $_, $_,$_,$_ModuleProjectCommandTypes,$_ = (GetCommandEnvironmentVariables) } return $_ModuleProjectCommandTypes[$CommandName] } function GetModuleProjectForCommand { param( [Parameter()][String] $CommandName ) if (!$_ModuleProjectCommands) { if ($IsProduction) { throw 'This should be cached. If you''re seeing this, the Module would be running super slowly' } $_, $_, $_ModuleProjectCommands,$_,$_,$_ = (GetCommandEnvironmentVariables) } return $_ModuleProjectCommands[$CommandName] } function GetModuleProjectInfo { param( [Parameter()][String] $ModuleProject ) if (!$_ModuleProjectInfos) { if ($IsProduction) { throw 'This should be cached. If you''re seeing this, the Module would be running super slowly' } $_, $_ModuleProjectInfos, $_,$_,$_,$_ = (GetCommandEnvironmentVariables) } if ($ModuleProject) { return $_ModuleProjectInfos[$ModuleProject] } return $_ModuleProjectInfos.Values } function GetCommandsInModuleProject { param( [Parameter()][String] $ModuleProject ) if (!$_ModuleProjects) { if ($IsProduction) { throw 'This should be cached. If you''re seeing this, the Module would be running super slowly' } $_ModuleProjects, $_, $_,$_,$_,$_ = (GetCommandEnvironmentVariables) } if ($ModuleProject) { return $_ModuleProjects[$ModuleProject] } $ReturnValue = @() foreach($_ModuleProject in $_ModuleProjects.Values) { $ReturnValue += $_ModuleProject } return $ReturnValue } <#FULLY TESTED - DON"T TOUCH NEEDED FOR NEW #> function Get-ModuleProjectLocation { param([Parameter(Mandatory=$true)][String]$ModuleProject) return "$ModuleProjectsFolder\$ModuleProject" } <#FULLY TESTED#> function Get-ModuleProjectFunctionsFolder { [OutputType([String])] param( [Parameter(Mandatory=$true)] [String]$ModuleProject ) $ModuleLocation = Get-ModuleProjectLocation -ModuleProject $ModuleProject return "$ModuleLocation\Functions" } <#FULLY TESTED#> function Get-ModuleProjectFunctions { [OutputType([FileInfo[]])] param( [Parameter(Mandatory=$true)] [String]$ModuleProject ) $Commands = GetCommandsInModuleProject -ModuleProject $ModuleProject foreach($CommandName in $Commands) { $CommandType = GetModuleProjectTypeForCommand -CommandName $CommandName if ($CommandType -eq 'Function') { GetFileForCommand -CommandName $CommandName } } } <#FULLY TESTED#> function Get-ModuleProjectFunctionNames { [OutputType([String[]])] param( [Parameter(Mandatory=$true)] [String]$ModuleProject ) $Functions = Get-ModuleProjectFunctions -ModuleProject $ModuleProject return $Functions.BaseName } <#FULLY TESTED#> function Get-ModuleProjectFunctionPath { param( [Parameter(Mandatory=$true)][String]$ModuleProject, [Parameter(Mandatory=$true)][String]$CommandName ) $FunctionsLocation = Get-ModuleProjectFunctionsFolder -ModuleProject $ModuleProject return "$FunctionsLocation\$CommandName.ps1" } <#FULLY TESTED#> function New-ModuleProjectFunction { param( [Parameter(Mandatory=$true)][String]$ModuleProject, [Parameter(Mandatory=$true)][String]$CommandName, [Parameter(Mandatory=$false)][String]$Text, [Switch] $Raw ) $ModuleProjectPath = Get-ModuleProjectLocation -ModuleProject $ModuleProject if (!(Test-Path ($ModuleProjectPath))) { throw [System.ArgumentException] "Module does not exist by the name '$moduleProject'" } $ModuleFunctionPath = Get-ModuleProjectFunctionPath -ModuleProject $ModuleProject -CommandName $CommandName if (Test-Path ($ModuleFunctionPath)) { throw [System.ArgumentException] "Function $CommandName already exists in $ModuleProject" } New-Item -Path $ModuleFunctionPath -ItemType File | Out-Null $functionContent = $Text; if (!$Raw) { $functionContent = @" function $CommandName { $Text } "@ } Add-Content -Path $ModuleFunctionPath -Value $functionContent | Out-Null } <#FULLY TESTED#> function Get-ModuleProjectAliasesFolder { [OutputType([String])] param( [Parameter(Mandatory=$true)] [String]$ModuleProject ) $ModuleLocation = Get-ModuleProjectLocation -ModuleProject $ModuleProject return "$ModuleLocation\Aliases" } <#FULLY TESTED#> function Get-ModuleProjectAliases { param( [Parameter(Mandatory=$true)] [String]$ModuleProject ) $Commands = GetCommandsInModuleProject -ModuleProject $ModuleProject foreach($CommandName in $Commands) { $CommandType = GetModuleProjectTypeForCommand -CommandName $CommandName if ($CommandType -eq 'Alias') { GetFileForCommand -CommandName $CommandName } } } <#FULLY TESTED#> function Get-ModuleProjectAliasNames { param( [Parameter(Mandatory=$true)] [String]$ModuleProject ) $Aliases = Get-ModuleProjectAliases -ModuleProject $ModuleProject return $Aliases.BaseName } <#FULLY TESTED#> function Get-ModuleProjectAliasPath { param( [Parameter(Mandatory=$true)][String]$ModuleProject, [Parameter(Mandatory=$true)][String]$CommandName ) $AliasesLocation = Get-ModuleProjectAliasesFolder -ModuleProject $ModuleProject return "$AliasesLocation\$CommandName.ps1" } <#FULLY TESTED#> function New-ModuleProjectAlias { [CmdletBinding(SupportsShouldProcess=$True)] param( [Parameter(Mandatory=$true)][String]$ModuleProject, [Parameter(Mandatory=$true)][String]$Alias, [Parameter(Mandatory=$true)][String]$CommandName ) $ModuleProjectPath = Get-ModuleProjectLocation -ModuleProject $ModuleProject if (!(Test-Path ($ModuleProjectPath))) { throw [System.ArgumentException] "Module does not exist by the name '$ModuleProject'" } $ModuleAliasPath = Get-ModuleProjectAliasPath -ModuleProject $ModuleProject -CommandName $Alias if (Test-Path ($ModuleAliasPath)) { throw [System.ArgumentException] "Alias $Alias already exists in $ModuleProject" } New-Item -Path $ModuleAliasPath -ItemType File | Out-Null $aliasContent = "Set-Alias $Alias $CommandName" Add-Content -Path $ModuleAliasPath -Value $aliasContent | Out-Null } <#TODO: Test#> function Remove-ModuleProjectCommand { param( [Parameter(Mandatory=$true)][String]$ModuleProject, [Parameter(Mandatory=$true)][String]$CommandName ) $Command = (GetFileForCommand -CommandName $CommandName) Remove-Item $Command.FullName } <#TODO: Test#> function Remove-ModuleProjectFolder { param( [Parameter(Mandatory=$true)][String]$ModuleProject ) $ModuleProjectLocation = Get-ModuleProjectLocation -ModuleProject $ModuleProject $Continue = Confirm-Choice -Title 'Removing Module...' -Prompt "Removing '$ModuleProject' located at '$ModuleProjectLocation'. Are you sure you wish to proceed?" if ($Continue) { Remove-Item $ModuleProjectLocation -Recurse } } <#FULLY TESTED#> function Get-ApprovedVerbs { $ApprovedVerbs = [HashSet[String]]::new(); (Get-Verb | Select-Object -Property Verb) ` | ForEach-Object {$ApprovedVerbs.Add($_.Verb)} | Out-Null; return $ApprovedVerbs; } <#TODO: Find a new place for this and Make Tests#> function Edit-ModuleManifest { [CmdletBinding(PositionalBinding=$false)] param( [String]$psd1Location, [String]$Author, [String]$CompanyName, [String]$Copyright, [Version]$ModuleVersion, [String]$Description, $Tags, [Uri]$ProjectUri, [Uri]$LicenseUri, [Uri]$IconUri, [String]$ReleaseNotes, [String]$HelpInfoUri, [String]$RootModule, $FunctionsToExport, $AliasesToExport, $NestedModules ) $psd1Content = (Get-Content $psd1Location | Out-String) $psd1 = (Invoke-Expression $psd1Content) $ManifestProperties = Get-ReducedPopulatedHashtable -InputTable $PSBoundParameters ` -Keys @( "Author", "Description", "CompanyName", "Copyright", "ModuleVersion", "HelpInfoUri", "RootModule", "FunctionsToExport", "AliasesToExport" "Tags", "ProjectUri", "LicenseUri", "IconUri", "ReleaseNotes" ) $ExistingProperties = Get-ReducedPopulatedHashTable -InputTable $psd1 ` -Keys @( "Author", "Description", "CompanyName", "Copyright", "ModuleVersion", "HelpInfoUri", "RootModule", "FunctionsToExport", "AliasesToExport" "PowerShellVersion", "CompatiblePSEditions", "CmdletsToExport", "VariablesToExport", "Guid", "ClrVersion", "DotNetFrameworkVersion", "PowerShellHostName", "PowerShellHostVersion", "RequiredModules", "TypesToProcess", "FormatsToProcess", "ScriptsToProcess", "RequiredAssemblies", "FileList", "ModuleList", "DscResourcesToExport" ) $PrivateData = Get-ReducedPopulatedHashTable -InputTable $psd1.PrivateData.PSData ` -Keys @( "Tags", "ProjectUri", "LicenseUri", "IconUri", "ReleaseNotes" ) foreach($Key in $ExistingProperties.Keys) { if (!$ManifestProperties.ContainsKey($Key)){ $ManifestProperties[$Key] = $ExistingProperties[$Key] } } foreach($Key in $PrivateData.Keys) { if (!$ManifestProperties.ContainsKey($Key)){ $ManifestProperties[$Key] = $PrivateData[$Key] } } New-ModuleManifest -Path $psd1Location @ManifestProperties } |