Created
February 17, 2019 19:04
-
-
Save nohwnd/509476b85f43b501033103d838c84789 to your computer and use it in GitHub Desktop.
Importing self-contained scripts. Demo for PSPowerHour.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Import-Script { | |
[CmdletBinding()] | |
param ( | |
[Parameter(Mandatory)] | |
[String] $Path, | |
[Hashtable] $Parameters = @{}, | |
[Object[]] $Arguments = @(), | |
[String] $EntryPoint = 'Main' | |
) | |
$sb = { | |
param ($__c, $__arguments, $__parameters) | |
Invoke-Expression " | |
function __placeholder () { | |
Write-Host ``` | |
'This is a placeholder running instead of $($__c.EntryPoint)' ``` | |
-ForegroundColor Yellow | |
}" | |
Set-Alias -Name $__c.EntryPoint -Value '__placeholder' | |
. $__c.Path @__arguments @__parameters | |
Remove-Item "alias:\$($__c.EntryPoint)" -Force | |
Remove-Item 'function:\__placeholder' -Force | |
Remove-Variable -Scope Local -Name '__c', '__arguments', '__parameters' | |
} | |
$__c = @{ | |
Path = $Path | |
EntryPoint = $EntryPoint | |
} | |
Set-ScriptBlockScope -SessionState $PSCmdlet.SessionState -ScriptBlock $sb | |
. $sb $__c $Arguments $Parameters | |
} | |
function Set-ScriptBlockScope { | |
param ( | |
[Parameter(Mandatory)] | |
[Management.Automation.SessionState] $SessionState, | |
[Parameter(Mandatory)] | |
[ScriptBlock] $ScriptBlock | |
) | |
$flags = [System.Reflection.BindingFlags]'Instance,NonPublic' | |
$SessionStateInternal = $SessionState.GetType().GetProperty('Internal', $flags).GetValue($SessionState, $null) | |
# attach the original session state to the wrapper scriptblock | |
# making it invoke in the caller session state | |
$ScriptBlock.GetType().GetProperty('SessionStateInternal', $flags).SetValue($ScriptBlock, $SessionStateInternal, $null) | |
} | |
Export-ModuleMember -Function Import-Script |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
param ( | |
[Parameter(Mandatory)] | |
$Name | |
) | |
# our entry point function that holds | |
# all the stuff that should happen when | |
# we run this script | |
function Main { | |
param ( | |
[Parameter(Mandatory)] | |
$Name | |
) | |
Get-Greeting $Name | |
} | |
# internal function that writes greeting | |
function Get-Greeting { | |
param ($Name) | |
$text = Get-GreetingText | |
$formattedGreetingText = $text -f $Name | |
Write-Host $formattedGreetingText -ForegroundColor Magenta | |
$formattedGreetingText | |
} | |
# another internal function that collaborates | |
# with Get-Greeting and that we will mock | |
# in our tests | |
function Get-GreetingText { | |
'Hello, {0}!' | |
} | |
Main -Name $Name |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Get-Module Pester, Import-Script | Remove-Module | |
Import-Module Pester -MinimumVersion 4.0 | |
Import-Module $PSScriptRoot\Import-Script.psm1 | |
function prompt () { "> " } | |
cd $PSScriptRoot | |
"Initialized, run the script step by step 🚀" | |
break | |
Import-Script -Path .\Script.ps1 -EntryPoint 'Main' -Parameters @{ Name = 'Jakub' } | |
Describe "t1.ps1" { | |
It "Can test 'Main' function" { | |
Main -Name 'PSPowerHour' | Should -Be 'Hello, PSPowerHour!' | |
} | |
It "Can test 'Get-Greeting' function" { | |
Get-Greeting -Name 'PSPowerHour' | Should -Be 'Hello, PSPowerHour!' | |
} | |
It "Can mock Get-GreetingText that is used by Get-GreetingFunction" { | |
Mock Get-GreetingText { 'I ❤ {0}!' } | |
Get-Greeting -Name 'PSPowerHour' | Should -Be 'I ❤ PSPowerHour!' | |
} | |
} | |
break | |
# mock the entrypoint function so | |
# we don't run anything from the script | |
$EntryPoint = 'Main' | |
$Path = ".\Script.ps1" | |
function placeholder { | |
Write-Host "this is a placeholder" -ForegroundColor Cyan | |
} | |
# alias to prevent main from running | |
Set-Alias $EntryPoint 'placeholder' | |
. $Path -Name 'Jakub' | |
# remove the alias, now we have all functions | |
# from the script dot-sourced in this scope | |
Remove-Item "alias:$EntryPoint" -Force | |
Main -Name "Jakub" | |
break | |
# why is this magic | |
# this is like a function call | |
# function calls make new scope | |
& { | |
# this is like dot-sourcing | |
function a () { "hello" } | |
} | |
# the function won't exist outside of the previous scriptblock, | |
# because it dies with the end of the scope | |
a |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment