From 275d86cb419fc6432a8e8b68f2811aa4e0330869 Mon Sep 17 00:00:00 2001 From: Mark Domansky <4317290+markdomansky@users.noreply.github.com> Date: Sun, 1 Aug 2021 11:53:39 -0500 Subject: [PATCH] new build process --- Build/Build.ps1 | 28 +- Build/Template/DSCConfig.inc.ps1 | 195 ++++ Build/Template/DSCDeploy.ps1 | 61 ++ Build/Template/StarterFiles/config.json | 15 + Build/Template/StarterFiles/overview.ps1 | 36 + Build/Template/StarterFiles/validate.ps1 | 217 ++++ Build/Template/site/content/ps.png | Bin 0 -> 3531 bytes WebJEA/ClassDiagram1.cd | 97 -- WebJEA/Global.asax.vb | 5 + WebJEA/My Project/AssemblyInfo.vb | 6 +- .../My Project/MyExtensions/MyWebExtension.vb | 6 +- WebJEA/My Project/Resources.resx | 9 +- WebJEA/My Project/Settings.Designer.vb | 2 +- WebJEA/My Project/Settings.settings | 2 +- WebJEA/NLog.config | 5 +- WebJEA/PSWebHelper.vb | 6 + WebJEA/Web.Debug.config | 2 +- WebJEA/Web.Release.config | 2 +- WebJEA/Web.config | 36 +- WebJEA/WebJEA.sln | 26 +- WebJEA/WebJEA.vbproj | 954 +++++------------- WebJEA/libman.json | 5 - WebJEA/main.css | 4 + WebJEA/packages.config | 41 +- 24 files changed, 856 insertions(+), 904 deletions(-) create mode 100644 Build/Template/DSCConfig.inc.ps1 create mode 100644 Build/Template/DSCDeploy.ps1 create mode 100644 Build/Template/StarterFiles/config.json create mode 100644 Build/Template/StarterFiles/overview.ps1 create mode 100644 Build/Template/StarterFiles/validate.ps1 create mode 100644 Build/Template/site/content/ps.png delete mode 100644 WebJEA/ClassDiagram1.cd delete mode 100644 WebJEA/libman.json diff --git a/Build/Build.ps1 b/Build/Build.ps1 index 172662b..0dc7a03 100644 --- a/Build/Build.ps1 +++ b/Build/Build.ps1 @@ -2,16 +2,17 @@ $ErrorActionPreference = "Stop" $buildpath = $PSScriptRoot $buildbin = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\amd64\msbuild.exe" -$publishtemp = "$buildpath\temp" +$publishtemp = "$buildpath\Release" $solutionpath = resolve-path "$buildpath\..\webjea" $solutionfile = "$solutionpath\webjea.sln" -$publishpath = "$solutionpath\bin" -$packagepath = "$buildpath\Package" +$publishpath = "$solutionpath\bin\app.publish" +$packagepath = "$buildpath\template" $assemblyFile = "$solutionpath\My Project\AssemblyInfo.vb" # $projpath = "C:\prj\webjea ce\WebJEA\WebJEA\WebJEA.vbproj" -$dllfile = "$publishpath\webjea.dll" +$dllfile = "$publishpath\bin\webjea.dll" # $projxml = [xml](gc $projpath -raw) -$outpath = "C:\prj\webjea ce\Release" +$outpath = resolve-path "$buildpath\..\Release" +New-Item $outpath -ItemType directory -ea 0 $buildDT = get-date $Major = 1 @@ -25,8 +26,12 @@ $assemblyinfo = gc $assemblyfile | ?{$_ -notlike '*AssemblyVersion*'} $assemblyinfo += '' -f $ver $assemblyinfo | out-file $assemblyfile -Encoding UTF8 +#clean folders folder +Get-ChildItem $publishpath -Recurse -ea 0 | Remove-Item -Recurse -Confirm:$false -Force -ea 0 +Get-ChildItem $publishtemp -Recurse -ea 0| Remove-Item -Recurse -Confirm:$false -force -ea 0 + #call build process -& $buildbin $solutionfile "/t:Restore;Rebuild" "/property:Configuration=Release" #"/v:diag" +& $buildbin $solutionfile "-m" "/p:DeployOnBuild=true;PublishProfile=FolderProfile;Configuration=Release" #"/v:diag" "/t:Restore;Rebuild" if ($LASTEXITCODE -ne 0) { Write-Warning "Build Failed"; return} $curver = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($dllfile).FileVersion @@ -36,17 +41,20 @@ $outfile = "$outpath\webjea-$curver.zip" if ((Test-Path $outfile)) { Remove-Item $outfile } Write-Host "Target File; $outfile" +write-host "Copy to temp directory" & robocopy.exe /mir $publishpath $publishtemp\site -Push-Location $publishtemp -& "$buildpath\zip.exe" -D -r -o $outfile . -Pop-Location -Push-Location $packagepath +write-host "Merge starter files" +copy-item $packagepath\* -dest $publishtemp -recurse -force + +write-host "Archive temp directory" +Push-Location $publishtemp & "$buildpath\zip.exe" -D -r -o $outfile . Pop-Location write-host -foreground cyan "Output file: $outfile" +write-output $outfile #####zip structure #dscConfig.inc.ps1 #dscDeploy.ps1 diff --git a/Build/Template/DSCConfig.inc.ps1 b/Build/Template/DSCConfig.inc.ps1 new file mode 100644 index 0000000..fd3dcd5 --- /dev/null +++ b/Build/Template/DSCConfig.inc.ps1 @@ -0,0 +1,195 @@ +$ErrorActionPreference = "Stop" +Configuration WebJEADeployment { + + Import-DscResource -ModuleName PSDesiredStateConfiguration + #Import-DSCResource -ModuleName WebAdministrationDSC + Import-DSCResource -ModuleName xWebAdministration + Import-DSCResource -ModuleName xXMLConfigFile + Import-DscResource -ModuleName cUserRightsAssignment + + Node $AllNodes.where{$_.role -eq "WebJEAServer"}.nodename { + + #Install Necessary Windows Features + $WFs = @("Web-WebServer","Web-Default-Doc","Web-Http-Errors","Web-Static-Content","Web-IP-Security","Web-Security","Web-Windows-Auth","Web-Net-Ext45","Web-Asp-Net45","NET-Framework-45-Core","NET-Framework-45-ASPNET","Web-Stat-Compression","Web-Dyn-Compression","Web-HTTP-Redirect") + foreach ($WF in $WFs) { + WindowsFeature "WF_$WF" { + Ensure = 'Present' + Name = $WF + } + } + + #build app pool + xWebAppPool "WebJEA_IISAppPool" { + Name = $node.WebAppPoolName + Ensure = 'Present' + State = 'Started' + autoStart = $true + managedPipelineMode = 'Integrated' + managedRuntimeVersion = 'v4.0' + identityType = 'SpecificUser' +####1/3 + loadUserProfile = $true #this is necessary to be able to create remote pssessions and import them + } + +####2/3 + #this is how we use the GMSA without specifying a PW we don't know. If using a regular user account, disable this and use the built-in credential support in xWebAppPool + Script ChangeAppPoolIdentity { + GetScript = { return @{ AppPoolName = "$($using:Node.WebAppPoolName)" }} + TestScript = { + import-module webadministration -verbose:$false + $pool = get-item("IIS:\AppPools\$($using:Node.WebAppPoolName)") + return $pool.processModel.userName -eq $using:Node.AppPoolUserName + } + SetScript = { + import-module webadministration -verbose:$false + + $pool = get-item("IIS:\AppPools\$($using:Node.WebAppPoolName)"); + + $pool.processModel.identityType = [String]("SpecificUser"); + $pool.processModel.userName = [String]($using:Node.AppPoolUserName) + $pool.processModel.password = [String]($using:Node.AppPoolPassword) + + $pool | Set-Item + } + DependsOn = "[xWebAppPool]WebJEA_IISAppPool" + } + + + #add webjea content + File WebJEA_WebContent { + Ensure = "Present" + SourcePath = $node.WebJEASourceFolder + "\site" + DestinationPath = $node.WebJEAIISFolder + Recurse = $true + Type = "Directory" + MatchSource = $true #always copy files to ensure accurate + Checksum = "SHA-256" + } + + #build webjea web app subdirectory + xWebApplication "WebJEA_IISWebApp" { + Website = 'Default Web Site' + Name = $node.WebJEAIISURI + WebAppPool = $node.WebAppPoolName + PhysicalPath = $node.WebJEAIISFolder + AuthenticationInfo = MSFT_xWebApplicationAuthenticationInformation { + Anonymous = $false + Basic = $false + Digest = $false + Windows = $true + } + PreloadEnabled = $true + ServiceAutoStartEnabled = $true + SslFlags = @('ssl') + + DependsOn='[WindowsFeature]WF_Web-WebServer' + } + + + + + #configure SSL + xWebsite "DefaultWeb" { + Ensure = "Present" + Name = "Default Web Site" + State = "Started" + BindingInfo = @(MSFT_xWebBindingInformation { + Protocol = 'https' + Port = '443' + CertificateStoreName = 'MY' + CertificateThumbprint = $node.CertThumbprint + HostName = $node.machinefqdn + IPAddress = '*' + SSLFlags = '1' + }#; + # MSFT_xWebBindingInformation { + # Protocol = 'https' + # Port = '443' + # CertificateStoreName = 'MY' + # CertificateThumbprint = $node.CertThumbprint + # HostName = $node.nodename + # IPAddress = '*' + # SSLFlags = '1' + # }; + #MSFT_xWebBindingInformation { + # Protocol = 'http' + # Port = '80' + # HostName = $null + # IPAddress = '*' + # } + ) + DependsOn=@('[WindowsFeature]WF_Web-WebServer','[File]WebJEA_WebContent') + } + + + #set json config location in web.config + XMLConfigFile "WebJEAConfig" { + Ensure = 'Present' + ConfigPath = "$($node.WebJEAIISFolder)\web.config" + XPath = "/configuration/applicationSettings/WebJEA.My.MySettings/setting[@name='configfile']" + isElementTextValue = $true + Name = "value" + Value = $node.WebJEAConfigPath + DependsOn=@('[File]WebJEA_WebContent','[xWebsite]DefaultWeb') + } + + #set nlog log location in nlog.config in iis site + XMLConfigFile "WebJEA_NLOGFile" { + Ensure = 'Present' + ConfigPath = "$($node.WebJEAIISFolder)\nlog.config" + XPath = "/nlog/targets/target[@name='file']/target" + isAttribute = $true + Name = "fileName" + Value = $node.WebJEA_Nlog_LogFile + DependsOn=@('[File]WebJEA_WebContent') + } + XMLConfigFile "WebJEA_NLOGUsageFile" { + Ensure = 'Present' + ConfigPath = "$($node.WebJEAIISFolder)\nlog.config" + XPath = "/nlog/targets/target[@name='fileSummary']/target" + isAttribute = $true + Name = "fileName" + Value = $node.WebJEA_Nlog_UsageFile + DependsOn=@('[File]WebJEA_WebContent') + } + + #assign permissions to scripts folder? + + #Configure Default Web Site to support SSL + +####3/3 + #add to logon as service + cUserRight WebJEA_Batch { + ensure = 'Present' + constant = 'SeServiceLogonRight' + principal = 'IIS APPPOOL\' + $node.AppPoolPoolName + dependson = @('[xWebAppPool]WebJEA_IISAppPool') + } + + #add gmsa to iusrs + Group WebJEA_IISIUSRS { + GroupName = 'IIS_IUSRS' + MembersToInclude = $node.AppPoolUserName + Ensure = 'Present' + } + + + #apppool timeout in webconfig + + #add starter scripts + File WebJEA_ScriptsContent { + Ensure = "Present" + SourcePath = $node.WebJEASourceFolder + '\StarterFiles' + DestinationPath = $node.WebJEAScriptsFolder + Recurse = $true + Type = "Directory" + MatchSource = $true #always copy files to ensure accurate + Checksum = "SHA-256" + } + + + } #/WebJEAServer + + +} + diff --git a/Build/Template/DSCDeploy.ps1 b/Build/Template/DSCDeploy.ps1 new file mode 100644 index 0000000..cdaf8d6 --- /dev/null +++ b/Build/Template/DSCDeploy.ps1 @@ -0,0 +1,61 @@ +param ([switch]$fast) +$ErrorActionPreference = "Stop" + +$MyData = @{ + AllNodes = @( + @{ + NodeName = '*' + WebAppPoolName = 'WebJEA' + AppPoolUserName = 'domain1\gmsa2$' + AppPoolPassword = "" #no credential data is actually password because we're using gMSAs + #if you use a non-msa, use another method to set the apppool identity + WebJEAIISURI = 'WebJEA' + WebJEAIISFolder = 'C:\inetpub\wwwroot\webjea' + WebJEASourceFolder = 'C:\source' + WebJEAScriptsFolder = 'C:\scripts' + WebJEAConfigPath = 'C:\scripts\config.json' #must be in webjeascriptsfolder + WebJEALogPath = 'c:\scripts' + WebJEA_Nlog_LogFile = "c:\scripts\webjea.log" + WebJEA_Nlog_UsageFile = "c:\scripts\webjea-usage.log" + }, + @{ + NodeName = 'WEB1' + Role = 'WebJEAServer' + MachineFQDN = 'web1.domain1.local' + CertThumbprint = '50495F09B2DC05DB9BB47D834623D38508A50524' + } + ) +} + + +if (-not $fast) { + #install necessary powershell modules + write-host "Configuring Package Provider" + install-packageprovider -name nuget -minimumversion 2.8.5.201 -force + write-host "Trusting PSGallery" + set-psrepository -Name psgallery -InstallationPolicy trusted + #####install-module WebAdministrationDSC + write-host "Installing DSC Modules" + install-module xwebadministration + install-module xXMLConfigFile + install-module cUserRightsAssignment +} + +#create the group MSA account +#add-kdsrootkey -effectivetime ((get-date).addhours(-10)) +#new-ADServiceAccount -name gmsa1 -dnshostname (get-addomaincontroller).hostname -principalsallowedtoretrievemanagedpassword mgmt1 +#install-adserviceaccount gmsa1 +#add-adgroupmember -identity "domain1\domain admins" -members (get-adserviceaccount gmsa1).distinguishedname +#at a later time, grant gmsa1 the permissions you want. + +#cd wsman::localhost\client +#Set-Item TrustedHosts * -confirm:$false -force +#restart-service winrm + + +write-host "Building Configuration" +. $PSScriptRoot\DSCConfig.inc.ps1 +WebJEADeployment -ConfigurationData $MyData -verbose -OutputPath .\WebJEADeployment + +write-host "Starting DSC" +Start-DscConfiguration -ComputerName $env:computername -Path .\WebJEADeployment -verbose -Wait -force diff --git a/Build/Template/StarterFiles/config.json b/Build/Template/StarterFiles/config.json new file mode 100644 index 0000000..f7ec3c1 --- /dev/null +++ b/Build/Template/StarterFiles/config.json @@ -0,0 +1,15 @@ +{ + "Title": "WebJEA Demo", + "defaultcommandid": "overview", + "basepath": "c:\\scripts", + "LogParameters": true, + "permittedgroups": [".\\Administrators"], + "commands": [{ + "id": "overview", + "displayname": "Overview", + "synopsis": "Congratulations, WebJEA is now working! We've pre-loaded a demo script that will help you verify everything is working.
Tip: You can use the synopsis property of default command to display any text you want. Including html.", + "permittedgroups": [".\\Administrators"], + "script": "validate.ps1", + "onloadscript": "overview.ps1" + }] +} \ No newline at end of file diff --git a/Build/Template/StarterFiles/overview.ps1 b/Build/Template/StarterFiles/overview.ps1 new file mode 100644 index 0000000..19e513f --- /dev/null +++ b/Build/Template/StarterFiles/overview.ps1 @@ -0,0 +1,36 @@ +$VerbosePreference = "Continue" +$DebugPreference = "Continue" + +write-host "You can also specify a script to run each time the page loads." + +write-host "WebJEA supports some basic formatting like: +Links: [[a |url|display]] -[[a|?cmdid=sample1|go to sample1]]- +CSS tags in a span: [[span |cssclasses|content]] -[[span|psvariable|this span uses a variable width font and italicised]]-. +Img: [[img |cssclasses|url]] [[img||./content/ps.png]] +Nesting: [[a |url|[[img |cssclasses|url]]]] [[a|//powershell.org|[[img||./content/ps.png]]]]" + +Write-Host "We html encode script output for safety, " + +Write-Host "Each script runs in its own instance, so load any scripts you need each time." + +write-host "We honor spaces like a
."
+write-host (Get-Process svchost | select -First 2 | out-string)
+
+Write-Host "WebJEA generates a usage log that documents all scripts that are run, with user and ip."
+write-host "You can also send messages directly to this log by prefixing a line with 'WEBJEA:'."
+write-host "The next write-host will not be shown but will appear in the logs."
+Write-Host "WEBJEA:This is an NLOG message"
+
+Write-Host "We also format Warning, Error, Verbose, and Debug messages."
+Write-Warning "This is a warning message"
+Write-Host "'natural' ps error:"
+12/0
+Write-Host "write-error:"
+Write-Error "This is an error message with a [[a|?cmdid=overview|link]] in it"
+Write-Verbose "This is a verbose message"
+Write-Debug "This is a debug message"
+write-host ""
+Write-Host "All of this is exposed in [[a|psoutput.css|psoutput.css]]."
+Write-Host $null
+write-host "PSVersion: $($PSVersionTable.psversion.tostring())"
+Write-Host (Get-Date).tostring()
diff --git a/Build/Template/StarterFiles/validate.ps1 b/Build/Template/StarterFiles/validate.ps1
new file mode 100644
index 0000000..6cc01d4
--- /dev/null
+++ b/Build/Template/StarterFiles/validate.ps1
@@ -0,0 +1,217 @@
+<#
+.SYNOPSIS
+Short 1 line description of what this script does.
+
+.DESCRIPTION
+Detailed description of the script and what it is for.  This can be longer as well.
+
+.EXAMPLE
+ScriptTemplate.ps1 -param1 "Value"
+Give an example of common usage.  Repeat EXAMPLE as desired
+
+.PARAMETER Input01Mandatory
+Short description of the parameter and how to use it.  Include PARAMETER for each parameter
+
+.PARAMETER Input02MandatoryMinLen
+Short description of the parameter and how to use it.
+
+.INPUTS
+String
+#.NET Framework object types that can be _piped_ in.  Repeat allowed inputs within single INPUTS
+
+.OUTPUTS
+String
+#.NET Framework object types that will be returned.
+
+.LINK
+URI or name of related topic. repeat LINK and URI/name as desired/needed.
+
+.NOTES
+Version:          1.0
+Author:           
+Creation Date:    
+Purpose/Change:   Initial release
+
+
+This template is CC0/1.0 Public Domain and can be found at github.com/markdomansky/powershellscripttemplate
+#note: This comment block MUST come before everything else.
+#>
+#requires -version 3
+#r#equires -runasadministrator
+#r#equires -pssnapin  -version X.x
+#r#equires -modules , #repeat as desired, replace  with @{ModuleName="X";ModuleVersion="1.0.0.0"} if you want specific versions
+#r#equires -shellid 
+##these must have the leading # to work. i.e. #requires -version 3 is active
+##for -version: specify specific version requirements: 3, 5.1, etc.
+##the other requires are pretty straightforward, just remove the extra # in requires
+
+#This PS1 script can be turned into a function by wrapping the entire script in "Function  {}"
+
+[CmdletBinding(SupportsShouldProcess=$True,ConfirmImpact='Low')]
+#SupportsShouldProcess=$true - forces acceptance of -Whatif and -Confirm
+#ConfirmImpact='Medium' (Low, Medium (default), High) will prompt for action where $pscmdlet.shouldprocess is called
+#  $pscmdlet.ShouldProcess("target",["action"]) is run.  Returns true/false, generally only want for high impact actions (i.e. restart computer)
+#TODO: better explain confirmimpact, supportsshouldprocess
+#DefaultParameterSetName="X" whatever parameterset used below
+#HelpUri="Uri" used to store help documentation elsewhere: http://msdn.microsoft.com/en-us/library/dd878343(v=vs.85).aspx
+#SupportsPaging=$true - adds First,Skip, IncludeTotalCount parameters automatically PSv3 req'd
+#PositionalBinding=$false - default true, allows parameters by position, when false, all parameters must be defined by name (-computername "X")
+
+#note: whatif, confirm, verbose, and debug are all passed through to sub-cmdlets/scripts called within the script.
+
+param
+(
+    #special variables for WebJEA
+    #[Parameter(Mandatory)] [string]$WEBJEAUsername="$($env:userdomain)\$($env:username)", #passes the domain\username to the script
+    #[Parameter(Mandatory)] [string]$WEBJEAHostname=($env:computername), #passes the client machine from asp.net, will return IP address some times
+
+#strings
+    [Parameter(Position=0, Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName,
+    HelpMessage='What computer name would you like to target?')]
+	#also random comment
+    [string]$Input01Mandatory,
+	#just a comment
+
+    [Parameter(Position=1, Mandatory=$true)]
+    [ValidateLength(3,30)]
+	<# comment block #>
+    [string]$Input02MandatoryMinLen = "ABC",
+
+    [Parameter(Position=2,mandatory=$false,HelpMessage="Help Message on MultiLine Directive")]
+	#WEBJEA-Multiline
+    [string]$Input03Str, #random comment
+
+    [Parameter(HelpMessage='What value would you like to enter?')]
+    [ValidateRange(1,100)]
+    [int32]$Input04Range,
+
+    [Parameter(Mandatory=$true,HelpMessage="Weird Help 'Message to trip up parser[]()")]
+    [ValidateScript({$_ -eq [string]"ABCD"})] #must return $true/$false
+    [string]$Input05Script="ABCD",
+
+    [Parameter()]
+    [ValidateNotNullOrEmpty()]
+	#WEBJEA-Multiline
+    [string]$Input13NotNullEmpty='x', #I think this will trip up the parser
+
+
+#numbers
+    [Parameter()]
+    [int]$NInput01,
+
+    [Parameter()]
+    [int[]]$NInput02,
+
+    [Parameter()]
+    [uint32]$NInput3,
+
+    [Parameter()]
+    [double]$NInput4,
+
+#listbox
+    [Parameter()]
+    [VALIDATESET('Input','Output','Both','A',1,2,3,"1/1/2017")]
+	[ValidateCount(1,3)]
+    [string[]]$LInput2,
+
+    [Parameter(Mandatory)]
+    [ValidateSet('Input','Output','Both')]
+    [string]$LInput1,
+
+    [Parameter()]
+    [ValidateCount(1,5)] #number of items in collection
+    [string[]]$Input08StrSetUpto5 = @('A',"B"),
+	#multiline, but taken as multiple inputs
+
+    [Parameter()]
+    [ValidateSet('Input','Output','Both')] #any set of values you want here
+    [string]$Input09ConstrainedSet,
+
+    [Parameter()]
+    [ValidateSet('Input','Output','Both','a','b','c','d',1,2)] #any set of values you want here
+    [string[]]$Input09BConstrainedSet=@('a','d'),
+
+    [Parameter(Mandatory)]
+    [ValidateSet('Input','Output','Both','a','b','c','d',1,2)] #any set of values you want here
+    [string[]]$Input09CConstrainedSet,
+
+#dates
+    [Parameter()]
+    [datetime]$DInput01DT,
+
+    [Parameter()]
+	#WEBJEA-DateTime
+    [datetime]$DInput02DT,
+
+#switches/boolean
+    [Parameter(Mandatory,HelpMessage="You must accept the terms")]
+    [switch]$Input11Switch,
+
+    [Parameter()]
+    [boolean]$Input12Bool,
+
+
+#webjea hidden parameters
+    [Parameter()]
+    [string]$WebJEAUsername, #this won't be shown to the user
+
+    [Parameter()]
+    [string]$WebJEAHostname #this won't be shown to the user
+
+
+) #/param
+
+begin {
+    #do pre script checks, etc
+
+} #/begin
+
+process {
+
+	Write-Verbose "Starting Process"
+	Write-Host (Get-Date).tostring()
+	Write-Host "Running as: $($env:username)"
+	Write-Host "PSBoundParameters"
+	$PSBoundParameters.keys | %{
+		Write-Host "[[span|psbold|$_]]"
+		$PSBoundParameters[$_] | write-host
+
+	}
+
+
+} #/process
+
+end {
+    #useful for cleanup, or to write-output whatever you want to return to the user
+} #/end
+
+###############################################################
+# Parameter Template
+###############################################################
+#    [Parameter(Position=0, Mandatory, ParameterSetName="Group1", ValueFromPipeline, ValueFromPipelineByPropertyName, HelpMessage='What computer name would you like to target?')]
+##Also available in parameter: ValueFromRemainingArgument=$true -this pushes all remaining unassigned variables into this parameter.
+##if you use parametersetname and want a parameter eligible for some but not all paramsets, you can specify the [Parameter()] property multiple times consecutively before the parameter definition ([string]$computername)
+##if you want a parameter available always, don't specify parametersetname
+##mandatory, valuefrom* can have "=$true/$false" but like a switch, it's implicit. note: I think v2 requires explicit declaration
+#    [SupportsWildcards()]
+#    [Alias('MachineName')] #Can use -MachineName in this example instead of Param1 and it will still be recognized, helpful for ValueFromPipelineByPropertyName.  Is array-based, so ('MachineName','Server') is allowed.
+#    [ValidateCount(2,5)] #number of items in collection, if you provided 1 item or 6 items in an array, it would error.  Typically used with arrays [vartype[]]
+#    [ValidateLength(3,30)] #typically for strings, if the string was 'AB', it would error
+#    [ValidatePattern("regexpattern")] #usually string, must match the regex pattern {$param -match $regex}
+#    [ValidateRange(1,100)] #typically a number, -1 or 1000 would error
+#    [ValidateScript({$_ -gt (10)})] #must return $true/$false, this would require the number to be greater than 10
+#    [ValidateSet('Input','Output','Both')] #any set of values you want here.  These are the only accepted values for this input.  Can also be effectively combined with arrays
+#    [ValidateNotNullOrEmpty()] #Common to use, Mandatory doesn't enforce content, only the existence of a parameter, this can be used to ensure the user provides something beyond $null or ""
+#    [ValidateNotNull()] #same as ValidateNotNullOrEmpty, but only prevents $null
+#    [AllowNull()] #effectively reverse of ValidateNotNullOrEmpty
+#    [AllowEmptyString()]
+#    [AllowEmptyCollection()]
+#    #WEBJEA-Multiline #WebJEA specific directive, this forces webjea to show a multiline input field
+#    #WEBJEA-DateTime #WebJEA specific directive, this forces webjea to show prompt for date AND time, not just date when using variable [datetime]
+#    [string[]]$ComputerName, #accepts multiple, typically use a foreach in process{}
+#    [string]$ComputerName, #only one
+##    common: [switch]/[boolean], [int]/[int32]/[byte]/[uint]/[uint64], [pscredential], [psobject], [float]/[double], [datetime] many others possible and most support [] within to accept multiple in an array.
+##    note: switch and boolean are not treated the same, switches are called with -paramname[:$true/false] where boolean are called -paramname $true/$false
+##    can always specify default values after the variable e.g. [string]$computername = $env:computername or (get-date) or most anything in powershell, but you can't see the other variables yet.  It can however reference variables in the parent scope.
+##DynamicParam is available, but an advanced topic not covered here.  see: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_functions_advanced_parameters?view=powershell-5.1#dynamic-parameters
+
diff --git a/Build/Template/site/content/ps.png b/Build/Template/site/content/ps.png
new file mode 100644
index 0000000000000000000000000000000000000000..1c165e77a8d3071390a4a913189c7d30175c9fed
GIT binary patch
literal 3531
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
FV1nN?^WFde

literal 0
HcmV?d00001

diff --git a/WebJEA/ClassDiagram1.cd b/WebJEA/ClassDiagram1.cd
deleted file mode 100644
index 8528a12..0000000
--- a/WebJEA/ClassDiagram1.cd
+++ /dev/null
@@ -1,97 +0,0 @@
-
-
-  
-    
-    
-      BAAAAgAAAAAAQFgAAAAAEAAAAAAAAAAAAAACABBAgAA=
-      Config.vb
-    
-  
-  
-    
-    
-      AAgEAACAgCAICEAAAAABCAEAAAAAQAIAAAgAAAIBgAA=
-      default.aspx.vb
-    
-  
-  
-    
-    
-      AAAgEAAAAAAwgQAAAAAAEAAIAAAABAAAAIACECAggAA=
-      PSCmd.vb
-    
-  
-  
-    
-    
-      
-        
-          PSEngine.vb
-        
-      
-      
-        
-          PSEngine.vb
-        
-      
-    
-    
-      CEAAAAAAAAEAAAAQAAAAAACCACAACAAgCIAAAAAgAAI=
-      PSEngine.vb
-    
-  
-  
-    
-    
-      AAAAAAAAAAAAAAAAAAEAAAAAAAABAAAAAAgAAAAAAAA=
-    
-  
-  
-    
-    
-      AAAAAAAAAAAAAYEAACgAAAQAAAJAAAAABAAAAAAAAAA=
-      PSCmdParam.vb
-    
-  
-  
-    
-    
-      AAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAQAAAAAAAAA=
-      PSCmdParamVal.vb
-    
-  
-  
-    
-    
-      AAAQAAAAAAAgAAAAAAIAAAAIAAAAAAAAAIAAAAAAAAA=
-      PSCmdParser.vb
-    
-  
-  
-    
-    
-      QAAAAAAAAAAAACAAAAAAAIgAAAAACAAIAQAAAAAAAAA=
-      UserInfo.vb
-    
-  
-  
-    
-    
-      ACABAAAAAABAAEAAAAAAAAAAAAgBgBAAAAAAAAAAAAA=
-      My Project\MyExtensions\MyWebExtension.vb
-    
-  
-  
-    
-    
-      AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAA=
-    
-  
-  
-    
-    
-      AAAAAAAAAAAAAAAAAAABEAAAAQAAAAAAAAAAAAAAAIA=
-    
-  
-  
-
\ No newline at end of file
diff --git a/WebJEA/Global.asax.vb b/WebJEA/Global.asax.vb
index e0701d6..d28c64c 100644
--- a/WebJEA/Global.asax.vb
+++ b/WebJEA/Global.asax.vb
@@ -7,6 +7,11 @@ Public Class Global_asax
 
     Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
         ' Fires when the application is started
+
+        ScriptManager.ScriptResourceMapping.AddDefinition("jquery", New ScriptResourceDefinition With {
+            .Path = "~/scripts/jquery-3.6.0.min.js",
+            .DebugPath = "~/scripts/jquery-3.6.0.js"
+        })
     End Sub
 
     Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
diff --git a/WebJEA/My Project/AssemblyInfo.vb b/WebJEA/My Project/AssemblyInfo.vb
index cc4a71e..e51df7e 100644
--- a/WebJEA/My Project/AssemblyInfo.vb	
+++ b/WebJEA/My Project/AssemblyInfo.vb	
@@ -1,4 +1,4 @@
-Imports System
+Imports System
 Imports System.Reflection
 Imports System.Runtime.InteropServices
 
@@ -29,5 +29,5 @@ Imports System.Runtime.InteropServices
 ' You can specify all the values or you can default the Build and Revision Numbers
 ' by using the '*' as shown below:
 
-' 
-
+' 
+
diff --git a/WebJEA/My Project/MyExtensions/MyWebExtension.vb b/WebJEA/My Project/MyExtensions/MyWebExtension.vb
index 78c7c19..1f6b4e2 100644
--- a/WebJEA/My Project/MyExtensions/MyWebExtension.vb	
+++ b/WebJEA/My Project/MyExtensions/MyWebExtension.vb	
@@ -7,9 +7,9 @@ Namespace My
     ''' 
      _
     Module MyWebExtension
-        Private s_Computer As New ThreadSafeObjectProvider(Of Global.Microsoft.VisualBasic.Devices.ServerComputer)
-        Private s_User As New ThreadSafeObjectProvider(Of Global.Microsoft.VisualBasic.ApplicationServices.WebUser)
-        Private s_Log As New ThreadSafeObjectProvider(Of Global.Microsoft.VisualBasic.Logging.AspLog)
+        Private ReadOnly s_Computer As New ThreadSafeObjectProvider(Of Global.Microsoft.VisualBasic.Devices.ServerComputer)
+        Private ReadOnly s_User As New ThreadSafeObjectProvider(Of Global.Microsoft.VisualBasic.ApplicationServices.WebUser)
+        Private ReadOnly s_Log As New ThreadSafeObjectProvider(Of Global.Microsoft.VisualBasic.Logging.AspLog)
         ''' 
         ''' Returns information about the host computer.
         ''' 
diff --git a/WebJEA/My Project/Resources.resx b/WebJEA/My Project/Resources.resx
index 1af7de1..5931345 100644
--- a/WebJEA/My Project/Resources.resx	
+++ b/WebJEA/My Project/Resources.resx	
@@ -46,7 +46,7 @@
     
     mimetype: application/x-microsoft.net.object.binary.base64
     value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : System.Serialization.Formatters.Binary.BinaryFormatter
             : and then encoded with base64 encoding.
     
     mimetype: application/x-microsoft.net.object.soap.base64
@@ -60,7 +60,6 @@
             : and then encoded with base64 encoding.
     -->
   
-    
     
       
         
@@ -69,10 +68,9 @@
               
                 
               
-              
+              
               
               
-              
             
           
           
@@ -87,10 +85,9 @@
                 
                 
               
-              
+              
               
               
-              
             
           
           
diff --git a/WebJEA/My Project/Settings.Designer.vb b/WebJEA/My Project/Settings.Designer.vb
index 570f4ec..8a5508a 100644
--- a/WebJEA/My Project/Settings.Designer.vb	
+++ b/WebJEA/My Project/Settings.Designer.vb	
@@ -56,7 +56,7 @@ Namespace My
         
           _
+         Global.System.Configuration.DefaultSettingValueAttribute("C:\prj\WebJEATest\config.json")>  _
         Public ReadOnly Property configfile() As String
             Get
                 Return CType(Me("configfile"),String)
diff --git a/WebJEA/My Project/Settings.settings b/WebJEA/My Project/Settings.settings
index f63b67f..290f33f 100644
--- a/WebJEA/My Project/Settings.settings	
+++ b/WebJEA/My Project/Settings.settings	
@@ -3,7 +3,7 @@
   
   
     
-      C:\prj\WebJEATest\configlocal1.json
+      C:\prj\WebJEATest\config.json
     
   
 
\ No newline at end of file
diff --git a/WebJEA/NLog.config b/WebJEA/NLog.config
index 3fe73e9..e5d6c7c 100644
--- a/WebJEA/NLog.config
+++ b/WebJEA/NLog.config
@@ -10,7 +10,6 @@
   https://github.com/nlog/NLog/wiki/Configuration-file#variables
   -->
   
-
   
     
-      
+      
     
     
-      
+      
     
     
   
diff --git a/WebJEA/PSWebHelper.vb b/WebJEA/PSWebHelper.vb
index 46d8363..03b82dc 100644
--- a/WebJEA/PSWebHelper.vb
+++ b/WebJEA/PSWebHelper.vb
@@ -534,6 +534,7 @@
             If valobj.Type = PSCmdParamVal.ValType.Mandatory And param.ParamType <> PSCmdParam.ParameterType.PSBoolean Then
                 Dim valctrl As New RequiredFieldValidator()
                 valctrl.ErrorMessage = "Required Field"
+                valctrl.CssClass = "valmsg"
                 valctrl.SetFocusOnError = True
                 valctrl.ControlToValidate = param.FieldName
                 retctrls.Add(valctrl)
@@ -544,6 +545,7 @@
                 Dim valctrl As New CustomValidator
                 valctrl.ClientValidationFunction = "validateMandatoryCheckbox"
                 valctrl.ErrorMessage = "You must check the box for " & param.Name & "."
+                valctrl.CssClass = "valmsg"
                 'valctrl.EnableClientScript = True
                 valctrl.SetFocusOnError = True
                 'you can't point a customvalidator directly at a checkbox, the checkbox can't be validated.
@@ -555,6 +557,7 @@
                 Dim valctrl As New RegularExpressionValidator()
                 valctrl.ValidationExpression = "[\S\s]{" & valobj.LowerLimit & "," & valobj.UpperLimit & "}"
                 valctrl.ErrorMessage = "Not in allowed length (" & valobj.LowerLimit & "-" & valobj.UpperLimit & ")"
+                valctrl.CssClass = "valmsg"
                 valctrl.SetFocusOnError = True
                 valctrl.ControlToValidate = param.FieldName
                 retctrls.Add(valctrl)
@@ -562,6 +565,7 @@
                 Dim valctrl As New RegularExpressionValidator()
                 valctrl.ValidationExpression = valobj.Pattern
                 valctrl.ErrorMessage = "Did not match pattern: " & valobj.Pattern
+                valctrl.CssClass = "valmsg"
                 valctrl.SetFocusOnError = True
                 valctrl.ControlToValidate = param.FieldName
                 retctrls.Add(valctrl)
@@ -570,6 +574,7 @@
                 valctrl.MinimumValue = valobj.LowerLimit
                 valctrl.MaximumValue = valobj.UpperLimit
                 valctrl.ErrorMessage = "Not in allowed range (" & valobj.LowerLimit & "-" & valobj.UpperLimit & ")"
+                valctrl.CssClass = "valmsg"
                 If param.ParamType = PSCmdParam.ParameterType.PSInt Then
                     valctrl.Type = ValidationDataType.Integer
                 ElseIf param.ParamType = PSCmdParam.ParameterType.PSFloat Then 'single/double
@@ -584,6 +589,7 @@
                 Dim valctrl As New CustomValidator
                 valctrl.ClientValidationFunction = "validateCollection"
                 valctrl.ErrorMessage = "Number of selected items not in allowed range (" & valobj.LowerLimit & "-" & valobj.UpperLimit & ")"
+                valctrl.CssClass = "valmsg"
                 valctrl.Attributes("data-min") = valobj.LowerLimit
                 valctrl.Attributes("data-max") = valobj.UpperLimit
                 'valctrl.EnableClientScript=true
diff --git a/WebJEA/Web.Debug.config b/WebJEA/Web.Debug.config
index 2e302f9..fae9cfe 100644
--- a/WebJEA/Web.Debug.config
+++ b/WebJEA/Web.Debug.config
@@ -1,6 +1,6 @@
 
 
-
+
 
 
   
+
 
 
   
 
   
@@ -14,41 +14,19 @@
 
     The following attributes can be set on the  tag.
       
-        
+        
       
   -->
   
-    
-    
-    
-    
-    
-    
+    
+    
+    
   
-  
-    
-      
-    
-    
-      
-        
-        
-      
-    
-  
   
     
       
-        C:\scripts\config.json
+        C:\prj\WebJEATest\config.json
       
     
   
-  
-    
-      
-        
-        
-      
-    
-  
 
\ No newline at end of file
diff --git a/WebJEA/WebJEA.sln b/WebJEA/WebJEA.sln
index 1c2ce9d..0b007e0 100644
--- a/WebJEA/WebJEA.sln
+++ b/WebJEA/WebJEA.sln
@@ -1,35 +1,25 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27703.2018
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31424.327
 MinimumVisualStudioVersion = 10.0.40219.1
-Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "WebJEA", "WebJEA.vbproj", "{0327F3B9-9BEA-4F00-86A5-C7355A1FC5D0}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3F2616EE-52C3-463C-960A-0DC3F50A6490}"
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "WebJEA", "WebJEA.vbproj", "{B0AA4E7A-CBF8-4807-9CAD-15316F88F758}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
-		Debug|x64 = Debug|x64
 		Release|Any CPU = Release|Any CPU
-		Release|x64 = Release|x64
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{0327F3B9-9BEA-4F00-86A5-C7355A1FC5D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{0327F3B9-9BEA-4F00-86A5-C7355A1FC5D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{0327F3B9-9BEA-4F00-86A5-C7355A1FC5D0}.Debug|x64.ActiveCfg = Debug|x64
-		{0327F3B9-9BEA-4F00-86A5-C7355A1FC5D0}.Debug|x64.Build.0 = Debug|x64
-		{0327F3B9-9BEA-4F00-86A5-C7355A1FC5D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{0327F3B9-9BEA-4F00-86A5-C7355A1FC5D0}.Release|Any CPU.Build.0 = Release|Any CPU
-		{0327F3B9-9BEA-4F00-86A5-C7355A1FC5D0}.Release|x64.ActiveCfg = Release|x64
-		{0327F3B9-9BEA-4F00-86A5-C7355A1FC5D0}.Release|x64.Build.0 = Release|x64
+		{B0AA4E7A-CBF8-4807-9CAD-15316F88F758}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B0AA4E7A-CBF8-4807-9CAD-15316F88F758}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B0AA4E7A-CBF8-4807-9CAD-15316F88F758}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B0AA4E7A-CBF8-4807-9CAD-15316F88F758}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
-		SolutionGuid = {6AC2BC8A-23E5-4208-A7BD-C7BBA12AE5E9}
-		BuildVersion_StartDate = 2000/1/1
-		BuildVersion_UseGlobalSettings = True
+		SolutionGuid = {0D880295-076E-4965-B075-3200326F1CF6}
 	EndGlobalSection
 EndGlobal
diff --git a/WebJEA/WebJEA.vbproj b/WebJEA/WebJEA.vbproj
index 747c237..6918593 100644
--- a/WebJEA/WebJEA.vbproj
+++ b/WebJEA/WebJEA.vbproj
@@ -1,7 +1,5 @@
 
-
-  
+
   
   
   
@@ -11,25 +9,24 @@
     
     
     
-    {0327F3B9-9BEA-4F00-86A5-C7355A1FC5D0}
+    {B0AA4E7A-CBF8-4807-9CAD-15316F88F758}
     {349c5851-65df-11da-9384-00065b846f21};{F184B08F-C81C-45F6-A57F-5ABD9991F28F}
     Library
     WebJEA
     WebJEA
-    v4.8
+    v4.7.2
     Custom
     true
-    
+    
+    44334
     
     
     
     
     
     
+    4.2
     
-    1.1.163.21152
-    2.8
-    
   
   
     true
@@ -39,74 +36,25 @@
     bin\
     WebJEA.xml
     42016,41999,42017,42018,42019,42032,42036,42020,42021,42022
-    AnyCPU
-    false
-    false
-    true
-    AllFilesInTheProject
-    false
-    false
-    ES2017
-    None
-    AMD
-    True
-    False
-    False
-    
-    
-    False
-    True
-    True
-    
-    
   
   
+    true
     pdbonly
     false
-    false
+    true
     true
     bin\
     WebJEA.xml
     42016,41999,42017,42018,42019,42032,42036,42020,42021,42022
-    false
-    AnyCPU
-    false
-    false
-    true
-    false
-    True
-    False
-    False
-    False
-    False
-    False
-    SettingsVersion
-    None
   
   
     
-      packages\AWSSDK.Core.3.7.0.42\lib\net45\AWSSDK.Core.dll
+      packages\AWSSDK.Core.3.7.1.3\lib\net45\AWSSDK.Core.dll
     
     
-      packages\AWSSDK.SQS.3.7.0.41\lib\net45\AWSSDK.SQS.dll
-    
-    
-      packages\Microsoft.Build.Framework.16.10.0\lib\net472\Microsoft.Build.Framework.dll
-    
-    
-      packages\Microsoft.Build.Tasks.Core.16.10.0\lib\net472\Microsoft.Build.Tasks.Core.dll
-    
-    
-      packages\Microsoft.Build.Utilities.Core.16.10.0\lib\net472\Microsoft.Build.Utilities.Core.dll
+      packages\AWSSDK.SQS.3.7.0.48\lib\net45\AWSSDK.SQS.dll
     
     
-    
-      packages\Microsoft.NET.StringTools.1.0.0\lib\net472\Microsoft.NET.StringTools.dll
-    
-    
-      packages\Microsoft.VisualStudio.Setup.Configuration.Interop.1.16.30\lib\net35\Microsoft.VisualStudio.Setup.Configuration.Interop.dll
-      True
-    
     
       packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll
     
@@ -114,85 +62,40 @@
       packages\NLog.4.7.10\lib\net45\NLog.dll
     
     
-      packages\NLog.Web.4.12.0\lib\net35\NLog.Web.dll
+      packages\NLog.Web.4.13.0\lib\net35\NLog.Web.dll
     
     
-    
-      packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
-    
-    
-      packages\System.Collections.Immutable.5.0.0\lib\net461\System.Collections.Immutable.dll
-    
-    
-      packages\System.Configuration.ConfigurationManager.4.7.0\lib\net461\System.Configuration.ConfigurationManager.dll
-    
     
     
-    
     
     
     
     
-    
     
     
       False
-      ..\..\..\..\..\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\System.Management.Automation.dll
+      ..\..\..\..\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\System.Management.Automation.dll
       False
     
-    
-      packages\System.Memory.4.5.4\lib\net461\System.Memory.dll
-    
-    
-    
-    
-    
-      packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
-    
-    
-    
-      packages\System.Resources.Extensions.4.6.0\lib\netstandard2.0\System.Resources.Extensions.dll
-    
-    
-    
-      packages\System.Runtime.CompilerServices.Unsafe.5.0.0\lib\net45\System.Runtime.CompilerServices.Unsafe.dll
-    
-    
-    
     
-    
-    
-      packages\System.Security.AccessControl.4.7.0\lib\net461\System.Security.AccessControl.dll
-    
-    
-      packages\System.Security.Permissions.4.7.0\lib\net461\System.Security.Permissions.dll
-    
-    
-      packages\System.Security.Principal.Windows.4.7.0\lib\net461\System.Security.Principal.Windows.dll
+    
+      packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll
     
     
-    
-    
-      packages\System.Threading.Tasks.Dataflow.4.9.0\lib\netstandard2.0\System.Threading.Tasks.Dataflow.dll
-    
-    
     
     
-    
+    
+    
     
     
+    
     
     
-    
-    
-    
-    
     
     
     
     
     
-    
   
   
     
@@ -202,9 +105,6 @@
     
     
     
-    
-    
-    
     
     
     
@@ -222,483 +122,228 @@
     
   
   
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
     
     
     
-    
-      Always
-    
-    
-      Always
-    
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-    
-    
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
     
       Designer
     
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
     
     
-    
     
-    
-      Designer
-    
+    
   
   
+    
+    
+      default.aspx
+    
+    
+      default.aspx
+      ASPXCodeBehind
+    
     
       error.aspx
     
@@ -713,16 +358,6 @@
     
     
     
-    
-    
-    
-    
-      default.aspx
-    
-    
-      default.aspx
-      ASPXCodeBehind
-    
     
     
       True
@@ -743,9 +378,11 @@
       Settings.settings
       True
     
-    
+    
     
     
+    
+    
     
     
     
@@ -759,7 +396,6 @@
     
   
   
-    
     
       MyApplicationCodeGenerator
       Application.Designer.vb
@@ -769,57 +405,20 @@
       My
       Settings.Designer.vb
     
-    
-    
-      PreserveNewest
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-      Always
-    
-    
-    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
     
       Web.config
     
@@ -828,14 +427,11 @@
     
   
   
-    
+    
   
   
-    
-      Always
-    
+    
   
-  
   
     10.0
     $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
@@ -852,31 +448,6 @@
   
     On
   
-  
-    true
-    true
-    true
-    bin\
-    WebJEA.xml
-    42016,41999,42017,42018,42019,42032,42036,42020,42021,42022
-    full
-    x64
-    true
-    false
-    MinimumRecommendedRules.ruleset
-  
-  
-    bin\
-    WebJEA.xml
-    true
-    42016,41999,42017,42018,42019,42032,42036,42020,42021,42022
-    pdbonly
-    x64
-    MinimumRecommendedRules.ruleset
-  
-  
-    false
-  
   
   
   
@@ -887,34 +458,23 @@
         
           True
           True
-          23811
+          49851
           /
-          http://localhost:23811/
+          https://localhost:44334/
           False
           False
-          https://web19.domain1.local
+          
+          
           False
         
       
-      
     
   
-  
-    
-    
-  
-  
-    
-      This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-    
-    
+  
-  
-  
-  
-  
+  -->
 
\ No newline at end of file
diff --git a/WebJEA/libman.json b/WebJEA/libman.json
deleted file mode 100644
index ceee271..0000000
--- a/WebJEA/libman.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "version": "1.0",
-  "defaultProvider": "cdnjs",
-  "libraries": []
-}
\ No newline at end of file
diff --git a/WebJEA/main.css b/WebJEA/main.css
index a5b5209..842c04a 100644
--- a/WebJEA/main.css
+++ b/WebJEA/main.css
@@ -121,6 +121,10 @@ body {
     font-size: 16px;
 }
 
+.valmsg {
+    color: red;
+}
+
 #imgLoader {
     display: none;
 }
diff --git a/WebJEA/packages.config b/WebJEA/packages.config
index 80600b6..a80039a 100644
--- a/WebJEA/packages.config
+++ b/WebJEA/packages.config
@@ -1,32 +1,15 @@
 
 
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
 
\ No newline at end of file