<#
Standard profile for psec, the PowerShell Enhanced Controller.

Note that the functions seem to be replaced only when Powershell is restarted

This imbeds a customized powershell command structure so the the interface cab be augmented
for the users.

History:
  EC3309 - Allow flow and flows to have multiple directories

  Original EC8704
#>

<##.mod-doc
start-psec.ps1
==============

_PSEC version 0.0.9_

#### PSEC bootstrap ####

This script file contains the routines that Powershell calls upon initiation as specified by the -file parameter of the
Powershell shortcut.


Since it is the first level, functions are treated as commands by Powershell. They are
documented as _cmds_ in this documentation.

Functions in this script file that are in reality internal functions have a special flag that
triggers the dgen.ps1 routines to treat them as such.

#### PSEC Restart mechanism ####

The Powershell console task has the ability to return an integer ExitCode (with defualt of 0).
Normally this is inspected by Windows and in most  us cases for PowerShell would be ignored.

In the case where a secondary shell is started using the @@new, the return code from the secondary
console window is inspected.  If it is 777 the @@NEW is reissued.

This gives the secondary shell the ability to restart itself.  This is used primarily during development of the system modules and classes.
It gives an expwdient way to reload the runtime environment and thus work with the refreshed code after changes have been made.

The @@xx command is an easy way to trigger the 777 exit code.  Where the new code will not parse due to
compile errors typing exit 777 will accomplish the same thing.

The @@GUI routines also make use of this facility by programtically issuing the exit code 777 where necessary.  Refer to @@GuiRestart.
#>
using module .\lib\psec-v4-shr.psm1
using module .\lib\dlog.psm1

[reflection.assembly]::LoadWithPartialName("System.Windows.Forms")
[reflection.assembly]::LoadWithPartialName("System.Drawing.Icon")
Add-Type -AssemblyName PresentationCore,PresentationFramework

"starting PSEC the PowerShell Enhanced Controller using $PSCommandPath $($args.count) $($args[0..$args.count])"

set-strictmode -version 2.0

#-- global class definitions

<#.md
.desc
Global Communication Vector Table
.details
Contains a globally accessable table of important values and class pointers

Can be inspected from the command line using the see cmd. eg see $CVT
.history
In the original version of PSEC it allowed complex JOB structures to be built when entering a
particular folder. This turned out to be cumbersome and of little value.

This version anticipates a simpler CVT and the ability to add and subtract run scripts based on
entering a folder with a signature script. It is not yet implemented but the CVT remains in place in
preparation for this.
#>
class CVT { #---- properties ---- [string]$psecVer; [string]$psecStart; [string]$psecBase; [string]$iconTheme = 'cyn'; # color theme. See cc cmd [boolean]$bSecCons; # true if Running as secondary console [hashtable]$locns = @{}; [hashtable]$psec = @{}; [hashtable]$run = @{}; [hashtable]$std = @{}; [hashtable]$favs = @{}; [GlobUtil]$gutil = $null; #---- constructors ----
static [CVT] create([string]$psecVer,[string]$psecStart) { $CVT = [CVT]::new(); $CVT.psecVer = $psecVer; $CVT.psecStart = $psecStart; $CVT.psecBase = $psecStart | Split-Path -Parent; # format stabndard date hashtable $curDate = [string](get-Date).addDays(0); $curYear = "$curDate".substring(6,4); $CVT.std.curDate = "$curDate".substring(0,10); setMonth "$curDate".substring(0,2); $CVT.std.curDay = "$curDate".substring(3,2); setYear $curYear hilite "CVT created for $($CVT.psecVer) in $($CVT.psecStart)"; return $CVT; } } <# This class installs a number of useful functions. It also means we can revert to the more tranitional syntax for function calls. #> <#.md .desc Global methods stored in the g global variable .details Allows for methods to be called in the more regular syntax of a function and not a Powershell command #>
class GlobUtil { #---- properties ---- #---- constructors ---- #---- methods ----
[void]log([string]$msg) { hilite $msg } } # Note. For dgen parsing classes must be defined before this point. # --- dgen end classes -- ## ================================= functions ================================= <# ------------------------------------------------- These functions need to be defined here because they are used during startup ----------------------------------------------------#> <#.md .desc This sets a standard 4 char date seq that is sortable. It wraps every decade. .hfunc .notes #>
function ECID { $date = Get-Date $ecid = makeECID($date) [void]("ECID set to $($CVT.psec.ECID)") return $ECID } <#.md .desc This makes a standard 4 char date seq that is sortable. It wraps every decade. .hfunc .notes Returns a 4 character string as follows" * Year: 0 thru 9 * Month: 1,2,3,4,5,6,7,8,9,a,b,c * Day: 01 thru 31 #>
function makeECID($date) { # param($date) [string]$dateStr = $date.ToString("yyyyMMdd") $months = "0123456789ABC" [int]$mon = $datestr.substring(4,2) $ecid = $datestr.substring(3,1)+$months.substring($mon,1)+$datestr.substring(6,2) $CVT.psec.ECID = $ecid return $ecid } <#.md .desc return $true if property exists .hfunc .notes used in strict mode to validate property exists before using This can be used on hashtables, custom objects or class files. EC:9C10 Fails on hashTables if value is null. use $ht.containsKey($key) #>
function exists($obj,$prop) { try { if ($null -ne $obj[$prop]) {return $true} return $false } catch { return $false } return $false } <#.md .desc Converse of @@exists .hfunc #>
function notExists($obj,$prop) { if (exists $obj $prop) {return $false;} return $true; } <#.md .desc return $true if property exists and has a value other than "" or $null .hfunc .notes only works for hashtables A value of 0 returns $true unlike Javascript #>
function valExists([hashtable]$obj,$prop) { if (!(exists $obj $prop)) {return $false;} if ("$($obj[$prop])" -eq "") {return $false;} return $true; } <#.md .desc return value if exists else $null .hfunc #>
function optval($obj,$prop) { #param($obj,$prop) if (exists $obj $prop) {return $obj[$prop]} return $null } <#.md .desc return count of list or 0 if $null .hfunc #>
function count($list) { if ($list -eq $null) {return 0;} return $list.count; } <#.md .desc return $true if 2 objects are the same .hfunc .notes Uses .NET [Object]::ReferenceEquals test to see if two object references are the same object #>
function isSameObj($o1,$o2) { #param($o1,$o2) return [System.Object]::ReferenceEquals($o1,$o2); } <#.md .desc Terniary replacement. Return $val if $cond true, else $notVal .hfunc .notes To force a Condition (boolean) result sometimes the \$cond operators need to be resequenced. Thus use (\$null -eq \$arr) and not ($arr -eq \$null) (The \$arr is assumed to be boolean). Alternately it could be expressed in pure Powershell syntax. Thus: \$x = if (condition) {\$true-val} else {\$false-value} .examples \$arr = (tern (\$null -eq \$arr) \$vals \$arr); #>
function tern([boolean]$cond,$val,$notVal) { if ($cond) {return $val;} return $notVal; } <#.md .desc Sets the $CVT std.year, std.prevYear, std.nextYear .hfunc #>
function setYear([int]$curYear) { $nxtYear = ($curYear-0)+1; $prvYear = ($curYear-0)-1; $CVT.std.year = "$curYear"; $CVT.std.prevYear = "$prvYear"; $CVT.std.nextYear = "$nxtYear"; [void]("Set year $CurYear prev=$prvYear next=$nxtYear") } <#.md .desc Sets the $CVT std.curMonth, std.prevYear, std.nextYear .hfunc #>
function setMonth([int]$curMon) { $CVT.std.curMonth = "$(100+$curMon)".substring(1); $CVT.std.picMonth = "JanFebMarAprMayJunJulAugSepOctNovDec".substring(($CVT.std.curMonth - 1) * 3,3); $CVT.std.picPrevMonth = "DecJanFebMarAprMayJunJulAugSepOctNovDec".substring(($CVT.std.curMonth - 1) * 3,3); } <#.md .desc write $args[0] directly to host logger (with debug location when available) .hfunc .notes When called from a script it prefixes the message with the script location as a debugging aid. There is only 1 paramater so the more traditional hlog(\" . . . \") syntax can be used. #>
function hlog { $locn = fmtLocn $Host.UI.WriteLine("$($locn) $($args[0])") } <#.md .desc write $args[0] directly to the debug file .hfunc .notes It assumes the debug file pointer has been set up. There is only 1 paramater so the more traditional hlog(\" . . . \") syntax can be used. #>
function dlog { $locn = fmtLocn $dlog = $GLOBAL:DLOG $dlog.info("$($locn) $($args[0])") }
function flush { $dlog = $GLOBAL:DLOG $dlog.info("----- flushed -----") $dlog.flush(); }
function testd([String]$msg) { dlog($msg) } <#.md .desc writeErrorLine $args[0] directly to host logger .hfunc .notes When called from a script it prefixes the message with the script location as a debugging aid. #>
function hlogErr { $locn = fmtLocn $Host.UI.WriteErrorLine("$($locn) $($args[0])") } <#.md .desc writeWarningLine $args[0] directly to host logger .hfunc .notes When called from a script it prefixes the message with the script location as a debugging aid. #>
function hlogWarn { $locn = fmtLocn $Host.UI.WriteWarningLine("$($locn) $($args[0])") } <#.md .desc write $args[0] directly to host logger with blue on white background .hfunc .notes When called from a script it prefixes the message with the script location as a debugging aid. #>
function hNote { $locn = fmtLocn $Host.UI.WriteLine('Blue','White',"$($locn) $($args[0])") } <#.md .desc write $args[0] directly to host logger with cyan foreground color .hfunc .notes When called from a script it prefixes the message with the script location as a debugging aid. #>
function hFlag { $locn = fmtLocn $BG = $host.ui.rawui.BackgroundColor; $Host.UI.WriteLine('Cyan',$BG,"$($locn) $($args[0])") } function fmtLocn() { $csf = get-PSCallStack $scr = $csf.scriptname[2] if ($scr -ne $null) { $lix = $scr.lastIndexOf("\"); if ($lix -gt 0) {$scr = $scr.substring($lix + 1)} $scr = $scr -replace '\.(psm1|ps1)','' $pos = $csf.scriptlinenumber[2] } else { return "" } return "[$($scr)@$($pos)] " } <#.md .desc Create a runlog record for timesheet creation .hfunc .notes Used to create a runlog record and append to the file defined by ENV:RUNLOG This is used to create logging records so the timestamps can be used to determine approximate activity on a system and therefore a project. #>
function runlog($desc) { [string]$log = $ENV:RUNLOG if ($log -eq "") {return} $sys = $ENV:COMPUTERNAME $date = Get-Date [string]$dateStr = $date.ToString("yyyyMMdd hh:mm:ss") $str = "$sys $datestr $PWD $desc"; hilite -yellow "runlog:$str" add-content $log "$($str)" } $GLOBAL:CVT = [CVT]::create('PSEC.v0.9',$PSCommandPath); $reload = "reloaded" if (Test-Path alias:cd) { # This has the side-effect of being a f/t switch so we do } <#.md .desc parse the active scripts for #@ statements and create table for @@hh .hfunc .notes #>
function hhParse { if (test-path config.ps1) { ## Obsolete $file = $(Get-Item config.ps1) if ($file.LastWriteTime -gt $CVT.run.configLastWriteTime) { "config has changed $curDate $($CVT.run.configLastWriteTime)" $CVT.run.configLastWriteTime = $file.LastWriteTime installConfig($null); } } [void](hilite -yellow "hhParse.v4 $PSCommandPath") $t = @{} $text = get-content $PSCommandPath -encoding ascii [boolean]$bInCmd = $false; [boolean]$bMarkDown = $false; [string]$targ = $null; [string]$curCmd = $null; foreach ($line in $text.split("`n")) { if ($line -match "^#[@]") { $bInCmd = $true; #hilite -magenta "line: $line" # 1 23 4 if ($($line.substring(2)) -match ' *([^ ]+) (([^;]+);)?;? *(.*)') { $curCmd = $matches[1]; $t[$curCmd] = @{title=$matches[4];syntax="$($matches[1]) $($matches[3])".trim();type='cmd'} } } if ($bInCmd) { if ($line -match "^<#.md") { $bMarkDown = $true; $targ = $null; } } if ($bMarkDown) { if ($line -match "^[.]([a-z]+)$") { $targ = $matches[1] ($t[$curCmd])[$targ] = "" } else { if ($line -match "^ *#>") { $bMarkDown = $false; $targ = $null; } elseif ($targ -ne $null) { ($t[$curCmd])[$targ] += "`r`n$line" } } } else { if ($line -match '^ *function +([a-zA-Z][a-zA-Z0-9_]*) *[{]') { $func = $matches[1] if ($t[$func] -eq $null) { $t[$func] = @{title='not-defined';type='priv';syntax=""} } $bInCmd = $false; } } } foreach ($line in $text.split("`n")) { ##if ($line -match "^##[@]") {"$($line.substring(3))"} ##"$($line.toString().substring(3))" } if (test-path config.ps1) { ## Obsolete $config = $(Get-Item config.ps1) $ht = getInstalled($null); foreach($key in $ht.Keys) { $func = $ht[$key] $dyn = "run" if (exists $func invoke) { $func = $run = (& $func) $dyn = "dyn-run" $title = "?"; } elseif ("$(easyType($func))" -eq "scriptblock") { $run = (& $func) if (exists $run title) {$title = $run.title} } if ((exists $func alias) -and ($func.alias -eq $key)) {continue} if (exists $func title) {$title = $func.title} $t[$key] = @{title=$title;type=$dyn;alias=''} if (exists $func alias) { $t[$key].alias = $($func.alias) } } } return $t; }
#@ help ; Display PSEC help in default browser <#.md .desc The help command is used to display the PSEC generated help in the default browser #> function help { $browser = (& getDefaultBrowserPath) [string]$what = "$($args[0])"; if ($what -ne "") {$what="?$($what)"} [void](& $browser "$($env:PSEC_V4_DOCS_DIR)\index.html$($what)") hilite "start $browser $($env:PSEC_V4_DOCS_DIR)\index.html$($what)" }
function getDefaultBrowserPath { #Get the default Browser path New-PSDrive -Name HKCR -PSProvider registry -Root Hkey_Classes_Root | Out-Null [string]$browserPath = (Get-ItemProperty ‘HKCR:\http\shell\open\command’) #v $browserpath if ($browserpath -match '\(default\)="([^"]+)"') { return $matches[1] } else { throw "lost default browser $browserPath" } }
#@ hh [specific]; Generate this help extract <#.md .desc The @@hh is used to display the command syntax for all of the additional commands implemented in PSEC. The run commands available in the curApp are also listed. The hh specfic format displays detailed information on the specific command. Thus hh gui would display detailed help on the @@gui. #> function hh { [hashTable]$t = (& hhParse); <# if ($CVT.curApp -ne $null) { forEach($jobKey in $CVT.curApp.jobs.keys) { $job = $CVT.curApp.jobs[$jobKey] if ("$($job.name)" -eq $jobKey) { #hlog("job $jobKey $($job.getType()) $($job.name)"); $syntax = "script" $t["r:$($job.name)"] = @{title=$job.title;type='run';alias="$($job.alias)";syntax=$syntax} } } } #> if ($args.count -eq 1) { if (notExists $t $args[0]) { hilite -red "command $($args[0]) does not exist" } [hashtable]$hh = $t[$args[0]] hilite -cyan "Details for command $($args[0])" hilite "Purpose: $($hh.title)" hilite " Syntax: $($hh.syntax)" if (exists $hh desc) { hilite "`r`nDescription:`r`n============`r`n$($hh.desc)" } if (exists $hh notes) { hilite "`r`nNotes:`r`n======`r`n$($hh.notes)" } if (exists $hh example) { hilite "`r`nExample:`r`n========`r`n$($hh.example)" } return; } "====== Help for 'func' commands in $PSCommandPath and installed run commands ======" #" Type run or run-dyn for '$($CVT.std.config)' installed from $config" hilite -cyan "----Name---- --Type-- Alias -----Syntax------ --- Description ---... $($args[0])" $selType = $args[0] $t.GetEnumerator() | sort -Property name | forEach { $alias = ""; $title = ""; $syntax = ""; if (exists $_.value alias) {$alias = $_.value.alias;} if (exists $_.value title) {$title = $_.value.title;} if (exists $_.value syntax) {$syntax = $_.value.syntax;} if (($_.value.type -eq 'cmd') -or ($_.value.type -eq 'run')) { if (($selType -eq $null) -or ($selType -eq $_.value.type)) { "$($($_.name).PadRight(13)) $($($_.value.type).padRight(8)) $($alias.padRight(6)) $($syntax.padRight(17)) $($title)" } } } #$config | get-member | out-gridview }
#@ year 20yy[mm]; Change accounting year/month to 20yy[mm] <#.md .desc The year is stored in the CVT and is calculated during PSEC initiation. This allows the computed value to be changed to 20yy and nextYear and PrevYear to also be recalulated. If the optional month is provided, the current month values are also changed. .notes Many task use this value to set their parameters #> function year { $year = $args[0] if ($year -match '^20[0-9][0-9]([0-9]{2})?$') { setYear $year if ($matches[1] -ne $null) { setMonth "$($matches[1])" } } else { " INVALID year $year. must start with 20" } }
#@ cd dir; Change current directory, (reload config.ps1 Obsolete) <#.md .desc Change the current PSEC directory. If the new directory contains the file *config.ps1* it is executed and assumed to set up functions that can be accessed with the run command. .notes This intercepts and changes the standard CD behavoir. #> function cd { $("changing location to " + $args) $CVT.run.cwd = $args[0] $file = $args[0] | Split-Path -Leaf $CVT.run.cwdStart = "start-$(file).ps1" [void]("starter is $($CVT.run.cwdStart)") set-location -path $($args[0].toString()) If (Test-Path ("config.ps1")) { ## Obsolete $file = $(Get-Item config.ps1) $CVT.run.configLastWriteTime = $file.LastWriteTime "timestamp $($CVT.run.configLastWriteTime) $file" installConfig($null); } }
#@ cdd dir; Change current drive and directory, (reload config.ps1 Obsolete) <#.md .desc Change the current PSEC drive and directory. If the new directory contains the file *config.ps1* it is executed and assuned to set up functions that can be accessed with the run command. .notes This intercepts and changes the standard CDD behavoir. #> function cdd { $("changing drive and location to " + $args) set-location -path "$($args[0])" $CVT.run.cwd = $args[0] If (Test-Path ("config.ps1")) { ## Obsolete $file = $(Get-Item config.ps1) $CVT.run.configLastWriteTime = $file.LastWriteTime "timestamp $($CVT.run.configLastWriteTime) $file" installConfig($null); } }
#@ dgen [copylocn]; generate PSEC docs (developer convenience cmd) <#.md .desc This runs the generation of the PSEC docs. It is provided as a convenience to the developer as is not normally run. .notes If args[0] points to a folder the resulting documention is copied to that location. Useful for browsing from another machine. The current directory is changed by this command. #> function dgen { cdd ($CVT.psecBase) ./scr/dgen.ps1 $args[0] }
#@ gui [c] [app] args; run gui app with args. c option adds console for debug <#.md .desc Starts the GUI processing engine. If *app* is usually specified, and is a GUI application in the gui-native-forms.psm1 module. The start-gue.ps1 (a lightweight psec-start.psi replacement) is used to drive the window and by default runs in a hidden window unless the c option above is included. If no application is apecified, 'test1' is invoked to test the gui. .notes This implements the @@GuiRestart facility. Using the X in the top right corner to close the application or typing ./ will prevent restarting the application. #> function gui { $bConsole = $false; $what = "test1"; $bias = 0; if ($args.length -gt 0) { if ($args[0] -eq "c") { $bConsole = $true; $bias += 1; } } if ($args.length -gt $bias) { $what = $args[$bias]; } if ($bConsole) { [void](& invokeGui c -native $what) } else { [void](& invokeGui -native $what) } }
#@ flow [c] app [args]; run gui app with args. c option adds console for debug <#.md .desc Starts the GUI processing engine. If *app* is required and is the Workflow application in the $env:PSEC_V4_FLOWS folder. The start-gui-v4.ps1 (a lightweight start-psec-v4.ps1 replacement) is used to drive the window and by default runs in a hidden window unless the c option above is included. .notes This implements the @@link.restart facility (triggered by typing // when the window has focus). Using the X in the top right corner to close the application or typing ./ will prevent restarting the application. #> function flow { $bConsole = $false; $what = "*prev*"; $bias = 0; if ($args.length -gt 0) { if ($args[0] -eq "c") { $bConsole = $true; $bias += 1; } } if ($args.length -gt $bias) { $what = $args[$bias]; } if ($bConsole) { [void](& invokeGui c -flow $what) } else { [void](& invokeGui -flow $what) } }
function hlogReal { $Host.UI.WriteLine("$($args[0])") } <## This creates a new Powershell process that runs eith with the console or not. The start file is the psec-gui variant that starts the GUI process. This is either a native GUI app or a workflow. #>
function invokeGui { hlogReal("invokeGui"); $gui = "$PSCommandPath" -replace "start-psec","start-gui" $dlog = $GLOBAL:DLOG; $dlogGui = $($dlog.filePath) -replace "-psec-","-gui-"; $bNoConsole = $true; $ix = 0; $what = "?"; $name = "?"; while($ix -lt $args.length) { $arg = $args[$ix] if ($arg -eq "c") { $bNoConsole = $false; } elseif ($arg -eq "-native") { $what = $arg; } elseif ($arg -eq "-flow") { $what = $arg; } else { $name = $arg; } $ix += 1 } $argList = @("-noprofile","-noexit"); $showConsole = "-show"; if ($bNoConsole) { $argList += "-WindowStyle Hidden" $showConsole = "-hide"; $host.ui.writeLine("red","white","Console hidden. Expect several second configuration delay") } $argList += "-file $gui" $argList += "-dlog $dlogGui" $argList += "$showConsole" $argList += "$what $name" while($true) { hlogReal("args $argList") $process = (start-process powershell.exe -argumentlist $arglist -PassThru -Wait) hlogReal("exitCode $($process.exitCode )") if ($process.exitCode -ne 901) {break;} # used by start-gui-v4.ps1 to indicate restart } }
#@ env [arg]; list environment variables <#.md .desc Used to list environment variables from existing context. issues dir env:arg .notes The first arg can be used to shorten the list. eg env n* or env npm #> function env { dir env:$($args[0]) }
#@ cc theme or bg fg; change console color and icon <#.md .desc Used to change the console color. A single value themed color. Otherwise bg fg. Themes also change icon .notes Theme BG FG cyn darkBlue white (Default theme) pnk darkMagenta white pur darkCyan white red darkRed white org yellow black grn darkGreen white yel darkYellow white gry darkGray white blk black white #> function cc { $h = (Get-Host).UI.RawUI; if ($args.count -eq 1) { $h.foregroundColor = 'white' ; if ($args[0] -eq "cyn") {$h.backgroundColor = 'darkCyan'; $h.foregroundColor = 'white'; zapIcon("cyn");} if ($args[0] -eq "pnk") {$h.backgroundColor = 'darkMagenta'; $h.foregroundColor = 'white'; zapIcon("pnk");} if ($args[0] -eq "pur") {$h.backgroundColor = 'darkBlue'; $h.foregroundColor = 'white'; zapIcon("pur");} if ($args[0] -eq "red") {$h.backgroundColor = 'darkRed'; $h.foregroundColor = 'white'; zapIcon("red");} if ($args[0] -eq "yel") {$h.backgroundColor = 'yellow'; $h.foregroundColor = 'black'; zapIcon("org");} if ($args[0] -eq "grn") {$h.backgroundColor = 'darkGreen'; $h.foregroundColor = 'white'; zapIcon("grn");} if ($args[0] -eq "org") {$h.backgroundColor = 'darkYellow'; $h.foregroundColor = 'white'; zapIcon("yel");} if ($args[0] -eq "gry") {$h.backgroundColor = 'darkGray'; $h.foregroundColor = 'white'; zapIcon("gry");} if ($args[0] -eq "blk") {$h.backgroundColor = 'black'; $h.foregroundColor = 'white'; zapIcon("blk");} clear-host #EC0204 } if ($args.count -eq 2) { $h.backgroundColor = $args[0]; $h.foregroundColor = $args[1]; clear-host #EC0204 } }
function zapIcon($iconSel) { $cons = "gtw" # Use white > symbol in icon if ($CVT.bSecCons) { # Use red or green > symbol in icon $cons = "gtR" if ($iconSel -eq "red") {$cons = "gtG"}; } hlog("ZapIcon $iconSel $($CVT.bSecCons)") $iconName = "psec-$($iconSel)-$($cons).ico" . "$($CVT.psecBase)/scr/change-icon.ps1" $iconName $CVT.iconTheme = $iconSel; }
#@ ct title; set console title to join args <#.md .desc Used to change the console title. $args[0] thru $args[n] are joined to form title #> function ct { $h = (Get-Host).UI.RawUI; if ($args.count -gt 0) { $str = ""; forEach($s in $args) { $str += " $s" } $h.WindowTitle = $str.trim(); } }
#@ cls; clear host console and retail color <#.md .desc Used to clear host console. Windows 10 cls did not work #> function cls { clear-host }
#@ rr ;repeat run (used for Jetty) <#.md .desc Certain commands store a copy of their initiation in the appJob class. This command re-executes that command. .notes This is primarily used for the Jetty server (Google app engine) which has trouble with the r builtin command to re-execute the previous command. #> function rr { $CVT = $GLOBAL:CVT if ($CVT.curApp.runRepeat) { & run $CVT.curApp.runRepeat } else { hilite -red "nothing to repeat" } }
#@ flows ;list flows in flows directory <#.md .desc Lhis lists the flows in the configured flows directory. .notes The flows directory is located from the PSEC_V4_FLOWS env variable. #> function flows { if ("$($env:PSEC_V4_FLOWS)" -eq "") { hLogErr "env variable psec_flows needs to be configured" } else { forEach ($dirPath in ("$($env:PSEC_V4_FLOWS)".Split(';'))) { hilite -cyan "flows in dir $dirPath" forEach($flow in (get-childitem $dirPath | sort-object -Property Name)) { # sort to get a stable logical, sequence $flowCfg = "$($flow.fullName)/$($flow.name)-cfg.json" if ((& isDir "$($flow.fullName)") -and (& test-path -path "$flowCfg")) { $cfg = (get-item -path $flowCfg) $TS = ($cfg.lastWriteTime) $dateStr = (Get-Date -Date $TS -format "yyyy-MMM-dd HH:mm:ss") "$(($flow.name).padRight(16)) $dateStr" } } } } }
#@ run XXXX args; run XXXX with args defined in config.ps1 <#.md .desc run the XXXX application defined in the config.ps1 loaded by the CD or CDD command. .notes The hh command will show those that are currently active. #> function run { hilite -cyan "run $($args[0]) len=$($args.length) called" <#$curDate = (Get-Date).AddDays(0); $file = $(Get-Item $CVT.curAppconfig.ps1) if ($file.LastWriteTime -gt $CVT.run.configLastWriteTime) { "config has changed $curDate $($CVT.run.configLastWriteTime)" $CVT.run.configLastWriteTime = $file.LastWriteTime installConfig($null); } else { "config the same $curDate file $($CVT.run.configLastWriteTime)" }#> if ($($args[0]) -eq "?") { <#$("run query " + $args) forEach($key in $($($CVT.chsol.jobs).keys)) { "$key $($($CVT.chsol[$key]).title)" }#> hilite -red "$args[0] help not implemented yet" } else { $extra = @(); $i = -1; forEach($arg in $args) { $i += 1; if ($i -gt 0) { $extra += $arg } } $CVT = $GLOBAL:CVT if ($CVT.curApp -eq $null) { hilite -red "no curApp installed" return; } if (notExists $CVT.curApp.jobs $args[0]) { hilite -red "no such job $($args[0]) in $($CVT.curApp.appName)" return; } $CVT.curApp = $CVT.curApp.refresh(); [AppJob]$appJob = $CVT.curApp.jobs[$args[0]] "calling $($appJob.title)" & $appJob.script $appJob $extra #EC0125 - pass $extra } <#$pgm = $CVT[$CVT.std.config].jobs[$args[0]] if ($pgm -eq $null) { "pgm $($args[0]) not defined in config.ps1" return } elseif (!(exists $pgm invoke)) { #dynamic function #& $pgm | out-gridview $run = (& $pgm) $run.extra = $extra if (exists $run stopBefore) { & $run.stopBefore $run } if (exists $run parseExtra) { & $run.parseExtra $run } $loop = @($run.parms); if ($($run.parms).getType() -eq 'System.Object[]') {$loop = $run.parms;} if (exists $run main) {$main = $run.main} else { $main = $null} hilite -green "exec dyn function $main $($run.title) loops=$($loop.length)" forEach($runParms in $loop) { #Iterate thru parm set if $run.parms is an array $parms = @(); if ($runParms -ne $null) { forEach($key in $runParms.Keys) { if ($key.substring($key.length-1,1) -eq "=") { # property $parms += $("-def"); $parms += $($key+$($runParms[$key])) } else { $parms += $("-"+$key); if ($runParms[$key] -ne $null) {$parms += $runParms[$key]}; # else boolean } } } if (exists $run main) { . java -cp $($run.cp) $($run.main) $($parms+$($run.extra)) hilite -cyan "LastExitCode=$LastExitCode" } elseif (exists $run node) { ##[Environment]::SetEnvironmentVariable("NODE_PATH","C:\c-pgms\NPM\node_modules","User"); . C:\c-pgms\node-js\node.exe $($($run.path)+'\'+$($run.node)) $($parms+$($run.extra)) } elseif (exists $run script) { try { if ($args.count -eq 1) { . $run.script } else { . $run.script $args[1..($args.Count-1)] } } catch { $e = $_ hLogErr("$($e.exception.message)") hLogErr("$($e.ScriptStackTrace)") } } else { hilite -red "main or node or script not defined for $($args[0])" return } } if (exists $run startAfter) { & $run.startAfter $run } } else { #$("run " + $pgm.title) $parms = $pgm.parms ". java -cp $pgm.cp $pgm.class $($parms+$extra).split($sp) " }#> #} }
#@ x ; close window <#.md .desc closes the PSEC window with no restart #> function x {exit 0} # exit $lastExitCode set to 0
#@ xx ; close window, set restart flag <#.md .desc closes the PSEC window with an exit code of 777 used to signal a restart if the current window was started with the new command. .notes The command passed in with the new command will be re-executed. To change the command, use x and then new again with the revised command. Typing exit 777 will accomplish the same thing. #> function xx {exit 777} # # exit $set to 777 to indicate restart if running under new command
#@ v obj; display object in grid <#.md .desc displays the specified object in a grid. Useful to inspect the '$CVT. .notes #> function v($a1) { $a1 | out-gridview }
#@ vo obj; display object members in grid <#.md .desc displays the members of the specified object in a grid. Useful to inspect the '$CVT. .notes #> function vo($a1) { $a1 | get-member | out-gridview }
#@ objdef obj-inst [file]; display object definition to console (or file) <#.md .desc Displays obj-inst on the console where obj-inst is a new-object constructor .notes The file parameter causes the text to be written to the specified file Due to the vagueness of Powershell parameter parsing the new-object constructor needs to be wrapped in parenthesis when the file parameter is included as the second example shows. .example DirInfo: `objdef new-object system.io.directoryinfo('x')` FileInfo: `objdef (new-object system.io.fileinfo('x')) c:\temp\dirinfo.txt` #> function objdef([object]$obj,[string]$file) { if ($file -ne '') { $obj | get-member | out-string | out-file -encoding ASCII $file } else { $obj | get-member | out-string } }
#@ qbak [xxxx]; [XXXX] backup of XXXX or default <#.md .desc executes the QBAK.PS1 script to back up the configured folders. .notes * Requires winzip to be installed. * Version 2 is the enhanced version. See qbak-v2.scr script help #> function qbak() { import-module "$($CVT.psecBase)\gui\psm\gui-classes" -force import-module "$($CVT.psecBase)\gui\psm\gui-utils" -force . "$($CVT.psecBase)\scr\qbak-v2.ps1" @args }
#@ node pgm [args]; execute node pgm <#.md .desc executes the specified NodeJS script program and passes the args in as parameters. .notes Requires NodeJS to be installed. #> function node([string]$js) { "node $js args=$($args.count) $($args[0..$args.count])" $opts = $args[0..$args.count] & "$($env:NODEJS_HOME)\node.exe" $js @opts }
#@ easyType obj; display type of object <#.md .desc A developer aid to display an object type. #> function easyType($obj) { #param($obj) if ($null -eq $obj) {return "NULL";} $str = "$($obj.getType())"; $ix = $str.lastIndexOf("."); if ($ix -gt 0) {return $str.substring($ix + 1,$str.length - $ix -1)} return $str }
#@ fav dir; switch to favorite dir. no param lists favorites. <#.md .desc A system to allow symbolic references frequently used directory #> function fav($fav) { $t = $CVT.favs; if ($fav -eq $null) { $t.GetEnumerator() | sort -Property name | forEach { $dir = $_.value; $name = $_.name; "$($( $name ).PadRight(13) ) $( $dir )" } } else { if (exists $t $fav) { #hilite -yellow "$fav cd $($t[$fav])" cdd $t[$fav] } else { hilite -yellow "$fav not defined as favorite" } } }
#@ setFav name dir; set favorite and assoiated directory <#.md .desc Adds a favorite / directory pair to the favorite hashMap Typically called by the specific script run when PSEC-V4 starts. #> #> #> function setFav($name,$dir) { $t = $CVT.favs; $t[$name] = $dir; hilite -yellow "setFav $name $dir" } #========================== end of commands =====================
function prepareDir([string]$leaf) { if (test-path $leaf) { $file = $leaf | Split-Path -Leaf $dir = $leaf | Split-Path -Parent [void]("startFile $file in $dir") [void](& cdd $dir) $appDir = [AppDir]::installAppDir($dir,$file); [void]$CVT.addAppDir($appDir); } else { hilite -red "$($leaf) startFile does not exist" } return $file }
function condMakeDir([string]$path) { if (-not(Test-Path -Path $path)) { [void](New-Item -ItemType Directory -Force -Path $path) hilite -DarkYellow "Created directory $path)" } if (-not (isDir($path))) {exitFail("Directory $path not a directory. Cannot continue.")} # cannot continue }
function exitFail([string]$why) { hilite -red "$why" exit } # This is a restart of the base window so that classes can be reloaded.
function swap([string]$opt) { hlog("execute swap $opt") # we add delay so that this process closes and we avoid a duplicate file. $dlog = $GLOBAL:DLOG $argList = @("-noprofile","-noexit","-file $($CVT.psecStart)","-delay 1","-dlog $($dlog.filePath)") #$h.windowTitle = "$origTitle **busy**" dlog("restarting with swap command"); flush(""); [void](start-process powershell.exe -argumentlist $argList) exit #exit process, new window will start } #========================== Start point ===================== ## prepareEnv <# The commands we parse are those ater the -file parameter which s/b the last powershell parameter. We are able to find and parse subsequent parameters. #> $argBias = 2 $runlogStr = "?" $workDir = $env:PSEC_V4_WORK; $jamDlog = ""; if ($NULL -eq $workDir) { $workDir = "$pwd/temp"; if (-not (test-path $workDir)) { exitFail("PSEC_V4_WORK environment variable needed to define workDir or /temp created in $pwd") } } "workDir $workDir" $CVT.locns.base = $CVT.psecBase; $CVT.locns.work = $workDir; $CVT.locns.dlog = "$workDir/dlog"; condMakeDir($CVT.locns.work); condMakeDir($CVT.locns.dlog); try { $g = [GlobUtil]::new(); $CVT.gutil = $g $ECID = (& ECID) hilite -cyan "$reload ECID $ECID, use 'hh' or 'hh TYPE' to get show help" if ($args[0] -eq '-startFile') { if (test-path $args[1]) { $file = prepareDir $args[1] $CVT.run.cwd = $args[1] $CVT.run.cwdStart = $file hilite -green "installed $($CVT.run.cwdStart) in $($CVT.run.cwd) $file" } else { hilite -red "$($args[1]) startFile does not exist" } if (($args.count -ge 4) -and ($args[2] -eq '-theme')) { # note - we do not check valid arg.3 as internally used or on shortcut $CVT.iconTheme = $args[3] $argBias += 2 hilite -green "installed theme $($CVT.iconTheme)" cc $CVT.iconTheme } $runlogStr = $host.ui.RawUI.WindowTitle } elseif ($args[0] -eq '-first') { #started from new command # used by new command to create a sub-window that reloads classes "run first $args arg0 $($args[0]) arg1 $($args[1]) sub $($args[2..$args.count])" $iconTheme = 'cyn'; if (($args.count -ge 4) -and ($args[2] -eq '-theme')) { # note - we do not check validity arg.3 as internally used or on shortcut $iconTheme = $args[3] $argBias += 2 ##clear-host #EC0204 hilite -green "prepared theme $iconTheme" } <# if (test-path $args[1]) { $file = prepareDir $args[1]; $CVT.run.cwd = $args[1] $CVT.run.cwdStart = $file $CVT.bSecCons = $true $CVT.iconTheme = $iconTheme hilite -green "REINSTALLED $($CVT.run.cwdStart) in $($CVT.psecBase) $($CVT.iconTheme) $($CVT.bSecCons)" $hist = (import-csv "$($CVT.psecBase)\history.csv") $hist | add-history; $runlogStr = "PSEC Secondary: $($args[$argBias..$args.count])" $host.ui.RawUI.WindowTitle = $runlogStr ##. ./scr/pos-window 100 100 #move window to side ##. cc $CVT.iconTheme } else { hilite -red "dir\start-file expected" }#> } elseif ($args[0] -eq '-delay') { #started from new command # used by new command to create a sub-window that reloads classes "run delay $args arg0 $($args[0]) arg1 $($args[1]) sub $($args[2..$args.count])" start-sleep -seconds $($args[1]) "done with sleep" $iconTheme = 'cyn'; if (($args.count -ge 4) -and ($args[2] -eq '-dlog')) { # note - we do not check validity arg.3 as internally used or on shortcut $jamDlog = $args[3] $argBias += 2 ##clear-host #EC0204 hilite -green "jamDlog $jamDlog" } <# if (test-path $args[1]) { $file = prepareDir $args[1]; $CVT.run.cwd = $args[1] $CVT.run.cwdStart = $file $CVT.bSecCons = $true $CVT.iconTheme = $iconTheme hilite -green "REINSTALLED $($CVT.run.cwdStart) in $($CVT.psecBase) $($CVT.iconTheme) $($CVT.bSecCons)" $hist = (import-csv "$($CVT.psecBase)\history.csv") $hist | add-history; $runlogStr = "PSEC Secondary: $($args[$argBias..$args.count])" $host.ui.RawUI.WindowTitle = $runlogStr ##. ./scr/pos-window 100 100 #move window to side ##. cc $CVT.iconTheme } else { hilite -red "dir\start-file expected" }#> } else { "default start up" } } catch { $e = $_ hLogErr("$($e.exception.message)") hLogErr("$($e.ScriptStackTrace)") } #EC9B14 - always load utilities $utils = "$($CVT.psecBase)\lib\gui-utils.psm1" import-module $utils -force & utilsVersion "$utils" #$dlogMod = "$($CVT.psecBase)\lib\dlog.psm1" #import-module $dlogMod -force #& dlogVersion "$dlogMod" ##$GLOBAL:DLOG = [Dlog]::create("d:/1/test-dlog.txt"); $GLOBAL:DLOG = [DLogObj]::create($CVT.locns.dlog,$jamDLog); [string]$nowPic = (Get-Date -Format "ddd yyyy-MMM-dd HH:mm:ss") $g.log("--- installation complete --- $nowPic $($CVT.iconTheme) $argBias $($args.count) $($args[0..$args.count])") $GLOBAL:DLOG.append("PSEC-V4 window started at $nowPic"); runlog "psec-start $runlogStr" ##userNotify("starting PSEC"); if ($args.count -ge 0) { # run command hilite -green "args.extra $($args.count) bias=$argBias 0=$($args[0]) 1=$($args[1]) 2=$($args[2]) 3=$($args[3])" if ($args.count -eq 1) { # run command & $args[0] } else { # had to use splat operator here $opts = @(); forEach($opt in $args[($argBias + 1)..$args.count]) { $opts += $opt; } # EC9302: For some reason the history does not take. pressing h shows it, # retyping reinserts it. Might be something to do with typed history. ##& $args[$argBias] @opts } } else { #hilite -green "RUN $($CVT.run.cwdStart) in $($CVT.run.cwd)" #$arg1 = split-path $($CVT.run.cwd) -parent #invoke-command -nonewscope -filepath "$($CVT.run.cwd)" -argumentlist (,$arg1) #$CVT.run.cwdStart($CVT.run.cwd); }
X
PSEC - Powershell Enhanced Capability
1.2.1
  src: start-psec-v4.ps1

Copyright © 2018-2021, 2022, Rexcel System Inc.