Skip to content

Instantly share code, notes, and snippets.

@Jaykul
Created November 3, 2016 22:17
Show Gist options
  • Save Jaykul/8ba1fa42111438a802983d0f36ad38da to your computer and use it in GitHub Desktop.
Save Jaykul/8ba1fa42111438a802983d0f36ad38da to your computer and use it in GitHub Desktop.
ModuleSpec dependency failure
#.Synopsis
# Generate a bunch of test modules to demonstrate ModuleSpec "cyclic dependency" bug
#.Example
# Write-ModuleSpecRepro
#
# Uses the default values to create a series of modules which will fail to import
#.Example
# Write-ModuleSpecRepro -Depth 6 -ModuleSpec First2
#
# Creates a series of modules where only two modules have specified the versions of their dependencies,
# and yet, they will fail to import.
[CmdletBinding(SupportsShouldProcess,ConfirmImpact="High")]
param(
# How many modules to create. Defaults to 5
# Note that each module depends on the previous modules
# and all modules depend on Microsoft.PowerShell.Core
$Depth = 5,
# A folder path to use to create the modules in (defaults to $Env:Temp\ModuleTest)
$TestFolder = $(Join-Path $Env:Temp "ModuleTest"),
# A name to use when creating modules (defaults to "Test" so you get "Test1", "Test2", etc)
$ModuleNameBase = "Test",
# Where to use full ModuleSpec instead of just the module name.
# TEST NOTES:
# A value of "None" allows you to specify a -Depth over 100 with no errors
# A value of "All" or "Last2" causes an error at -Depth 5
# A value of "First2" causes an error at -Depth 6
[ValidateSet("All","None","First2","Last2")]
[string]$ModuleSpec = "All"
)
# Make sure the folder exists (and remember if we created it)
$Created = $false
if(!(Test-Path $TestFolder)) {
$Created = $true
$null = mkdir $TestFolder -Force
}
$TestFolder = Resolve-Path $TestFolder
# Update PSModulePath if we need to
if($Env:PSModulePath.Split([IO.Path]::DirectorySeparatorChar) -notcontains $TestFolder) {
$Env:PSModulePath += ";$TestFolder"
}
Push-Location $TestFolder
$LastModule = @()
foreach($Level in 1..$Depth) {
$ModuleName = "${ModuleNameBase}$Level"
$ModulePath = Join-Path $ModuleName $ModuleName
# Make a module:
# 1. Make a folder
$null = mkdir $ModuleName -Force
# 2. Make a script file
Set-Content -Path "$ModulePath.psm1" -Value "function Test-$moduleName { Get-Module '$moduleName' } "
# 3. Make a manifest
if(!$LastModule) {
# The first one is simple
New-ModuleManifest "$ModulePath.psd1" -RootModule "$ModuleName.psm1"
} else {
switch($ModuleSpec) {
"All" {
New-ModuleManifest "$ModulePath.psd1" -RootModule "$ModuleName.psm1" -RequiredModules $LastModule
}
"None" {
New-ModuleManifest "$ModulePath.psd1" -RootModule "$ModuleName.psm1" -RequiredModules $LastModule.ModuleName
}
"First2" {
if($Level -in 2,3) {
New-ModuleManifest "$ModulePath.psd1" -RootModule "$ModuleName.psm1" -RequiredModules $LastModule
} else {
New-ModuleManifest "$ModulePath.psd1" -RootModule "$ModuleName.psm1" -RequiredModules $LastModule.ModuleName
}
}
"Last2" {
if($Level -in ($Depth-1),($Depth-2)) {
New-ModuleManifest "$ModulePath.psd1" -RootModule "$ModuleName.psm1" -RequiredModules $LastModule
} else {
New-ModuleManifest "$ModulePath.psd1" -RootModule "$ModuleName.psm1" -RequiredModules $LastModule.ModuleName
}
}
}
}
# Rig it so each module depends on all the previous modules
$LastModule += @{ ModuleName = $ModuleName; ModuleVersion = '1.0' }
}
Get-Module $ModuleNameBase* -List | Format-Table ModuleType, Name, Version, RequiredModules -AutoSize
try {
$null = Import-Module "${ModuleNameBase}$Depth" -PassThru
Write-Warning "Success!"
Remove-Module $ModuleNameBase*
& "Test-${ModuleNameBase}$Depth"
} catch {
Write-Warning "Failure!"
Write-Error $_
} finally {
# Cleanup
Remove-Module $ModuleNameBase*
Write-Host "Cleanup?" -ForegroundColor Cyan
if($Created) {
if($PSCmdlet.ShouldProcess("Removed the folder '$TestFolder' and it's children.",
"Should we remove the folder '$TestFolder' and all it's children?",
"Removing $TestFolder")) {
Pop-Location
Remove-Item $TestFolder -Recurse
}
} else {
if(Test-Path $ModuleNameBase*) {
foreach($folder in Get-ChildItem $ModuleNameBase* -Directory) {
if($PSCmdlet.ShouldProcess("Removed the folder '$($folder.FullName)' and it's children.",
"Should we remove the folder '$($folder.FullName)' and all it's children?",
"Removing $ModuleNameBase* folders from $pwd")) {
Remove-Item $folder -Recurse
}
}
}
Pop-Location
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment