scripts/update-script.ps1
<#
.SYNOPSIS Update a script to the latest skeleton version .DESCRIPTION skel.ps1 is improved regularly. These improvements are hard to integrate in each customer's script. That's what update-script.ps1 tries to solve. !! WARNING !! WARNING !! WARNING !! For update-script.ps1 to work flawlessly, you have to respect theese guidlines : * Add your parameters to the CmdletBinding() block * Keep the comment block ## YOUR SCRIPT BEGINS HERE ## * Keep the comment block ## YOUR SCRIPT ENDS HERE ## Everything outside the CmdletBinding block or the YOUR SCRIPT block will be lost ! !! WARNING !! WARNING !! WARNING !! In other words, what will be kept from your script : * the comment-based help (and anything before it) * the CmdletBinding() block * everything between ## YOUR SCRIPT BEGINS HERE ## and ## YOUR SCRIPT ENDS HERE ## tags Caveats : * new standard paramters added to skel.ps1 will not be merged with customer's script. .PARAMETER h display help screen. Use Get-Help instead. .PARAMETER v enable verbose mode .PARAMETER d enable debug mode .PARAMETER dev enable devel mode .PARAMETER trace .enable trace mode. With this mode on you can trace entering and leaving every single function that use the Write-EnterFunction and Write-LeaveFunction calls. Very useful while developing a new script. .PARAMETER ask ask for each action .PARAMETER quiet quiet output completely .PARAMETER log log calls to e*() functions into specified logfile. If used in conjunction with -trace, it will use PowerShell Start-Transcript to log everything, including output of commands. Useful if you can't see the output of script for whatever reason. In this case, Write-ToLog() is deactivated. .PARAMETER Skel full path to the reference to skeleton from Tiny {PowerShell} Framework .PARAMETER Script ful path to custom script to update .NOTES Author: Charles-Antoine Degennes <cadegenn@gmail.com> .LINK https://github.com/cadegenn/pwsh_fw #> [CmdletBinding()]Param( [switch]$h = $false, [switch]$v = $false, [switch]$d = $false, [switch]$dev = $false, [switch]$trace = $false, [switch]$ask = $false, [ValidateScript({ Test-Path -Path $_ -PathType container })][string]$api = $null, # if you want each invocation to overwrite logfile #[ValidateScript({New-Item $_ -ItemType file -force})][string]$log = "" # if you want each invocation to NOT overwrite logfile [ValidateScript({ New-Item $_ -ItemType file -ErrorAction:SilentlyContinue Test-Path -Path $_ -PathType leaf })][string]$log = "", [switch]$Force = $false, [Alias('Skel', 'Skeleton')] [Parameter(Mandatory = $true)][string]$SkelFilename, [Alias('Script', 'Scriptname')] [Parameter(Mandatory = $true)][string]$ScriptFilename ) $Global:BASENAME = Split-Path -Leaf $MyInvocation.MyCommand.Definition $Global:VERBOSE = $v $Global:DEBUG = $d $Global:DEVEL = $dev $Global:TRACE = $trace $Global:ASK = $ask $Global:LOG = $log $rc = Import-Module PwSh.Fw.Core -ErrorAction Stop $modules = @() if ($h) { Get-Help $MyInvocation.MyCommand.Definition Exit } # keep the order as-is please ! if ($ASK) { Set-PSDebug -Step } if ($TRACE) { # Set-PSDebug -Trace 1 $Global:DEVEL = $true } if ($DEVEL) { $Global:DEBUG = $true; } if ($DEBUG) { $DebugPreference="Continue" $Global:VERBOSE = $true } if ($VERBOSE) { $VerbosePreference="Continue" } if ($log) { if ($TRACE) { Start-Transcript -Path $log # } else { # # add -Append:$false to overwrite logfile # # Write-ToLogFile -Message "Initialize log" -Append:$false # Write-ToLogFile -Message "Initialize log" } $modules += "PwSh.Log" } # write-output "Language mode :" # $ExecutionContext.SessionState.LanguageMode # # Load Everything # everbose("Loading modules") # $modules += "PsIni" # $modules += "PwSh.ConfigFile" # $modules += "Microsoft.PowerShell.Archive" # USER MODULES HERE $ERRORFOUND = $false ForEach ($m in $modules) { $rc = Load-Module -Name $m -Force:$Force if ($rc -eq $false) { $ERRORFOUND = $true } } if ($ERRORFOUND) { efatal("At least one module could not be loaded.") } ############################# ## YOUR SCRIPT BEGINS HERE ## ############################# <# ###### ######## ### ######## ######## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ###### ## ## ## ######## ## ## ## ######### ## ## ## ## ## ## ## ## ## ## ## ###### ## ## ## ## ## ## #> etitle ("$Global:BASENAME") # get the line numbers of skeleton $PATTERN = '^\$Global:BASENAME' $SKEL_LINENO_HEAD_START = (Select-String -Path $SkelFilename -Pattern $PATTERN).LineNumber if ( ! $SKEL_LINENO_HEAD_START) { efatal "$PATTERN anchor not found in script." } $PATTERN = '^## YOUR SCRIPT BEGINS HERE ##' $SKEL_LINENO_MAIN_START = (Select-String -Path $SkelFilename -Pattern $PATTERN).LineNumber if ( ! $SKEL_LINENO_MAIN_START) { efatal "$PATTERN anchor not found in script." } $PATTERN = '^## YOUR SCRIPT ENDS HERE ##' $SKEL_LINENO_MAIN_END = (Select-String -Path $SkelFilename -Pattern $PATTERN).LineNumber if ( ! $SKEL_LINENO_MAIN_END) { efatal "$PATTERN anchor not found in script." } edevel("SKEL_LINENO_HEAD_START = $SKEL_LINENO_HEAD_START") edevel("SKEL_LINENO_MAIN_START = $SKEL_LINENO_MAIN_START") edevel("SKEL_LINENO_MAIN_END = $SKEL_LINENO_MAIN_END") # get the line numbers of customer script $PATTERN = '^\$Global:BASENAME' $SCRIPT_LINENO_HEAD_START = (Select-String -Path $ScriptFilename -Pattern $PATTERN).LineNumber if ( ! $SCRIPT_LINENO_HEAD_START) { efatal "$PATTERN anchor not found in script." } $PATTERN = '^## YOUR SCRIPT BEGINS HERE ##' $SCRIPT_LINENO_MAIN_START = (Select-String -Path $ScriptFilename -Pattern $PATTERN).LineNumber if ( ! $SCRIPT_LINENO_MAIN_START) { efatal "$PATTERN anchor not found in script." } $PATTERN = '^## YOUR SCRIPT ENDS HERE ##' $SCRIPT_LINENO_MAIN_END = (Select-String -Path $ScriptFilename -Pattern $PATTERN).LineNumber if ( ! $SCRIPT_LINENO_MAIN_END) { efatal "$PATTERN anchor not found in script." } edevel("SCRIPT_LINENO_HEAD_START = $SCRIPT_LINENO_HEAD_START") edevel("SCRIPT_LINENO_MAIN_START = $SCRIPT_LINENO_MAIN_START") edevel("SCRIPT_LINENO_MAIN_END = $SCRIPT_LINENO_MAIN_END") # cut everything together $skel = @{} $skel.head = Get-Content -Path $SkelFilename -TotalCount $($SKEL_LINENO_MAIN_START - 1) | Select-Object -Skip $($SKEL_LINENO_HEAD_START - 1) $skel.tail = Get-Content -Path $SkelFilename | Select-Object -Skip $($SKEL_LINENO_MAIN_END + 1) $Script = @{} $script.head = Get-Content -Path $ScriptFilename -TotalCount $($SCRIPT_LINENO_HEAD_START - 1) $script['body'] = Get-Content -Path $ScriptFilename -TotalCount $($SCRIPT_LINENO_MAIN_END + 1) | Select-Object -Skip $($SCRIPT_LINENO_MAIN_START - 1) $sModules = Get-Content -Path $ScriptFilename | select-string -Pattern '^\$modules \+=' $script.modules = foreach ($m in $sModules) { "{0}`n" -f $m } Clear-Content -Path $($ScriptFilename + ".new") -ErrorAction:SilentlyContinue $script.head | Add-Content -Path $($ScriptFilename + ".new") $skel.head | Add-Content -Path $($ScriptFilename + ".new") $script.body | Add-Content -Path $($ScriptFilename + ".new") $skel.tail | Add-Content -Path $($ScriptFilename + ".new") (Get-Content $($ScriptFilename + ".new")) -replace "^# USER MODULES HERE$", $("$&`n" + ($script.modules -f 'string')) | Set-Content $($ScriptFilename + ".new") if ($Force) { if (fileExist("$ScriptFilename.bak")) { Remove-Item -Path "$ScriptFilename.bak" } } Rename-Item -Path $ScriptFilename -NewName $(($ScriptFilename | Split-Path -Leaf) + ".bak") -Force:$Force Rename-Item -Path $($ScriptFilename + ".new") -NewName ($ScriptFilename | Split-Path -Leaf) -Force:$Force <# ######## ## ## ######## ## ### ## ## ## ## #### ## ## ## ###### ## ## ## ## ## ## ## #### ## ## ## ## ### ## ## ######## ## ## ######## #> ############################# ## YOUR SCRIPT ENDS HERE ## ############################# if ($log) { if ($TRACE) { Stop-Transcript } else { Write-ToLogFile -Message "------------------------------------------" } } # reinit values $Global:DebugPreference = "SilentlyContinue" Set-PSDebug -Off $Script:indent = "" |