Comments (10)
The -CustomMessage parameter would have to be added to the config XML file so that you could translate the message into different languages and have the toolkit display the appropriate language based on the user's regional language settings.
I don't have time at the moment for new feature development, so if you want to take a crack at this, then I'll consider it for addition to the toolkit. We're also putting a hold on new feature development untill we have a stable release without new bug reports for a while so that we can start work on the v4 release.
from psappdeploytoolkit.
I'll try to come up with the necessary code for this.
from psappdeploytoolkit.
I implemented these on the Main code of the toolkit and the XML file. Here are the changes that I had to make:
Added the following parameters to the XML file:
<DeferPrompt_CountdownMessage>The {0} will automatically continue in:</DeferPrompt_CountdownMessage>
<Prompt_CustomMessage>This is a custom message to display at the Welcome Screen window.</Prompt_CustomMessage>
Added the following to the variable declaration of the Main toolkit:
[string]$configDeferPromptCountdownMessage = $xmlUIMessages.DeferPrompt_CountdownMessage
[string]$configPromptCustomMessage = $xmlUIMessages.Prompt_CustomMessage
Added the following parameters to the Function Show-InstallationWelcome:
## Specify a countdown to display before automatically proceeding with the installation when a deferal is enabled
[Parameter(Mandatory=$false)]
[ValidateNotNullorEmpty()]
[int32]$ForceCountdown = 0,
## Specify whether to display a custom message specified on the XML file
[Parameter(Mandatory=$false)]
[switch]$CustomText = $false,
Replaced part of the code in the Function Show-InstallationWelcome with the following:
## Prompt the user to close running applications and optionally defer if enabled
If (-not ($deployModeSilent) -and (-not ($silent))) {
If ($forceCloseAppsCountdown -gt 0) {
# Keep the same variable for countdown to simplify the code:
$closeAppsCountdown = $forceCloseAppsCountdown
# Change this variable to a boolean now to switch the countdown on even with deferral
[boolean]$forceCloseAppsCountdown = $true
}
ElseIf ($forceCountdown -gt 0){
# Keep the same variable for countdown to simplify the code:
$closeAppsCountdown = $forceCountdown
# Change this variable to a boolean now to switch the countdown on
[boolean]$forceCountdown = $true
}
Set-Variable -Name 'closeAppsCountdownGlobal' -Value $closeAppsCountdown -Scope 'Script'
While ((Get-RunningProcesses -ProcessObjects $processObjects -OutVariable 'runningProcesses') -or (($promptResult -ne 'Defer') -and ($promptResult -ne 'Close'))) {
[string]$runningProcessDescriptions = ($runningProcesses | Where-Object { $_.ProcessDescription } | Select-Object -ExpandProperty 'ProcessDescription' | Select-Object -Unique | Sort-Object) -join ','
# Check if we need to prompt the user to defer, to defer and close apps, or not to prompt them at all
If ($allowDefer) {
# If there is deferral and closing apps is allowed but there are no apps to be closed, break the while loop
If ($AllowDeferCloseApps -and (-not $runningProcessDescriptions)) {
Break
}
# Otherwise, as long as the user has not selected to close the apps or the processes are still running and the user has not selected to continue, prompt user to close running processes with deferral
ElseIf (($promptResult -ne 'Close') -or (($runningProcessDescriptions) -and ($promptResult -ne 'Continue'))) {
[string]$promptResult = Show-WelcomePrompt -ProcessDescriptions $runningProcessDescriptions -CloseAppsCountdown $closeAppsCountdownGlobal -ForceCloseAppsCountdown $forceCloseAppsCountdown -ForceCountdown $forceCountdown -PersistPrompt $PersistPrompt -AllowDefer -DeferTimes $deferTimes -DeferDeadline $deferDeadlineUniversal -MinimizeWindows $MinimizeWindows -CustomText $CustomText -TopMost $TopMost
}
}
# If there is no deferral and processes are running, prompt the user to close running processes with no deferral option
ElseIf (($runningProcessDescriptions) -or ($forceCountdown)) {
[string]$promptResult = Show-WelcomePrompt -ProcessDescriptions $runningProcessDescriptions -CloseAppsCountdown $closeAppsCountdownGlobal -ForceCloseAppsCountdown $forceCloseAppsCountdown -ForceCountdown $forceCountdown -PersistPrompt $PersistPrompt -MinimizeWindows $minimizeWindows -CustomText $CustomText -TopMost $TopMost
}
# If there is no deferral and no processes running, break the while loop
Added the following parameters to the Function Show-WelcomePrompt:
[Parameter(Mandatory=$false)]
[ValidateNotNullorEmpty()]
[boolean]$ForceCountdown,
[Parameter(Mandatory=$false)]
[boolean]$CustomText = $false,
Replaced part of the code in the Function Show-WelcomePrompt:
## If 'force close apps countdown' was specified, enable that feature.
If ($forceCloseAppsCountdown -eq $true) {
Write-Log -Message "Close applications countdown has [$closeAppsCountdown] seconds remaining." -Source ${CmdletName}
$showCountdown = $true
}
## If 'force countdown' was specified, enable that feature.
If ($forceCountdown -eq $true) {
Write-Log -Message "Countdown has [$closeAppsCountdown] seconds remaining." -Source ${CmdletName}
$showCountdown = $true
}
[string[]]$processDescriptions = $processDescriptions -split ','
[Windows.Forms.Application]::EnableVisualStyles()
$formWelcome = New-Object -TypeName 'System.Windows.Forms.Form'
$pictureBanner = New-Object -TypeName 'System.Windows.Forms.PictureBox'
$labelAppName = New-Object -TypeName 'System.Windows.Forms.Label'
$labelCountdown = New-Object -TypeName 'System.Windows.Forms.Label'
$labelDefer = New-Object -TypeName 'System.Windows.Forms.Label'
$listBoxCloseApps = New-Object -TypeName 'System.Windows.Forms.ListBox'
$buttonContinue = New-Object -TypeName 'System.Windows.Forms.Button'
$buttonDefer = New-Object -TypeName 'System.Windows.Forms.Button'
$buttonCloseApps = New-Object -TypeName 'System.Windows.Forms.Button'
$buttonAbort = New-Object -TypeName 'System.Windows.Forms.Button'
$formWelcomeWindowState = New-Object -TypeName 'System.Windows.Forms.FormWindowState'
$flowLayoutPanel = New-Object -TypeName 'System.Windows.Forms.FlowLayoutPanel'
$panelButtons = New-Object -TypeName 'System.Windows.Forms.Panel'
$toolTip = New-Object -TypeName 'System.Windows.Forms.ToolTip'
## Remove all event handlers from the controls
[scriptblock]$Form_Cleanup_FormClosed = {
Try {
$labelAppName.remove_Click($handler_labelAppName_Click)
$labelDefer.remove_Click($handler_labelDefer_Click)
$buttonCloseApps.remove_Click($buttonCloseApps_OnClick)
$buttonContinue.remove_Click($buttonContinue_OnClick)
$buttonDefer.remove_Click($buttonDefer_OnClick)
$buttonAbort.remove_Click($buttonAbort_OnClick)
$script:welcomeTimer.remove_Tick($timer_Tick)
$timerPersist.remove_Tick($timerPersist_Tick)
$formWelcome.remove_Load($Form_StateCorrection_Load)
$formWelcome.remove_FormClosed($Form_Cleanup_FormClosed)
}
Catch { }
}
[scriptblock]$Form_StateCorrection_Load = {
## Correct the initial state of the form to prevent the .NET maximized form issue
$formWelcome.WindowState = 'Normal'
$formWelcome.AutoSize = $true
$formWelcome.TopMost = $TopMost
$formWelcome.BringToFront()
# Get the start position of the form so we can return the form to this position if PersistPrompt is enabled
Set-Variable -Name 'formWelcomeStartPosition' -Value $formWelcome.Location -Scope 'Script'
## Initialize the countdown timer
[datetime]$currentTime = Get-Date
[datetime]$countdownTime = $startTime.AddSeconds($CloseAppsCountdown)
$script:welcomeTimer.Start()
## Set up the form
[timespan]$remainingTime = $countdownTime.Subtract($currentTime)
[string]$labelCountdownSeconds = [string]::Format('{0}:{1:d2}:{2:d2}', $remainingTime.Hours, $remainingTime.Minutes, $remainingTime.Seconds)
If ($forceCountdown -eq $true) {
If ($deploymentType -ieq 'Install') { $labelCountdown.Text = ($configDeferPromptCountdownMessage -f $configDeploymentTypeInstall) + "`n$labelCountdownSeconds" }
Else { $labelCountdown.Text = ($configDeferPromptCountdownMessage -f $configDeploymentTypeUninstall) + "`n$labelCountdownSeconds" }
}
Else { $labelCountdown.Text = "$configClosePromptCountdownMessage`n$labelCountdownSeconds" }
}
## Add the timer if it doesn't already exist - this avoids the timer being reset if the continue button is clicked
If (-not ($script:welcomeTimer)) {
$script:welcomeTimer = New-Object -TypeName 'System.Windows.Forms.Timer'
}
If ($showCountdown) {
[scriptblock]$timer_Tick = {
## Get the time information
[datetime]$currentTime = Get-Date
[datetime]$countdownTime = $startTime.AddSeconds($CloseAppsCountdown)
[timespan]$remainingTime = $countdownTime.Subtract($currentTime)
Set-Variable -Name 'closeAppsCountdownGlobal' -Value $remainingTime.TotalSeconds -Scope 'Script'
## If the countdown is complete, close the application(s) or continue
If ($countdownTime -lt $currentTime) {
If ($forceCountdown -eq $true) {
Write-Log -Message 'Countdown timer has elapsed. Force continue.' -Source ${CmdletName}
$buttonContinue.PerformClick()
}
Else {
Write-Log -Message 'Close application(s) countdown timer has elapsed. Force closing application(s).' -Source ${CmdletName}
$buttonCloseApps.PerformClick()
}
}
Else {
# Update the form
[string]$labelCountdownSeconds = [string]::Format('{0}:{1:d2}:{2:d2}', $remainingTime.Hours, $remainingTime.Minutes, $remainingTime.Seconds)
If ($forceCountdown -eq $true) {
If ($deploymentType -ieq 'Install') { $labelCountdown.Text = ($configDeferPromptCountdownMessage -f $configDeploymentTypeInstall) + "`n$labelCountdownSeconds" }
Else { $labelCountdown.Text = ($configDeferPromptCountdownMessage -f $configDeploymentTypeUninstall) + "`n$labelCountdownSeconds" }
}
Else { $labelCountdown.Text = "$configClosePromptCountdownMessage`n$labelCountdownSeconds" }
[Windows.Forms.Application]::DoEvents()
}
}
}
Else {
$script:welcomeTimer.Interval = ($configInstallationUITimeout * 1000)
[scriptblock]$timer_Tick = { $buttonAbort.PerformClick() }
}
$script:welcomeTimer.add_Tick($timer_Tick)
## Persistence Timer
If ($persistWindow) {
$timerPersist = New-Object -TypeName 'System.Windows.Forms.Timer'
$timerPersist.Interval = ($configInstallationPersistInterval * 1000)
[scriptblock]$timerPersist_Tick = { Refresh-InstallationWelcome }
$timerPersist.add_Tick($timerPersist_Tick)
$timerPersist.Start()
}
## Form
$formWelcome.Controls.Add($pictureBanner)
$formWelcome.Controls.Add($buttonAbort)
##----------------------------------------------
## Create padding object
$paddingNone = New-Object -TypeName 'System.Windows.Forms.Padding'
$paddingNone.Top = 0
$paddingNone.Bottom = 0
$paddingNone.Left = 0
$paddingNone.Right = 0
## Generic Label properties
$labelPadding = '20,0,20,0'
## Generic Button properties
$buttonWidth = 110
$buttonHeight = 23
$buttonPadding = 50
$buttonSize = New-Object -TypeName 'System.Drawing.Size'
$buttonSize.Width = $buttonWidth
$buttonSize.Height = $buttonHeight
$buttonPadding = New-Object -TypeName 'System.Windows.Forms.Padding'
$buttonPadding.Top = 0
$buttonPadding.Bottom = 5
$buttonPadding.Left = 50
$buttonPadding.Right = 0
## Picture Banner
$pictureBanner.DataBindings.DefaultDataSourceUpdateMode = 0
$pictureBanner.ImageLocation = $appDeployLogoBanner
$System_Drawing_Point = New-Object -TypeName 'System.Drawing.Point'
$System_Drawing_Point.X = 0
$System_Drawing_Point.Y = 0
$pictureBanner.Location = $System_Drawing_Point
$pictureBanner.Name = 'pictureBanner'
$System_Drawing_Size = New-Object -TypeName 'System.Drawing.Size'
$System_Drawing_Size.Height = 50
$System_Drawing_Size.Width = 450
$pictureBanner.Size = $System_Drawing_Size
$pictureBanner.SizeMode = 'CenterImage'
$pictureBanner.Margin = $paddingNone
$pictureBanner.TabIndex = 0
$pictureBanner.TabStop = $false
## Label App Name
$labelAppName.DataBindings.DefaultDataSourceUpdateMode = 0
$labelAppName.Name = 'labelAppName'
$System_Drawing_Size = New-Object -TypeName 'System.Drawing.Size'
If (-not $showCloseApps) {
$System_Drawing_Size.Height = 40
}
Else {
$System_Drawing_Size.Height = 65
}
$System_Drawing_Size.Width = 450
$labelAppName.Size = $System_Drawing_Size
$System_Drawing_Size.Height = 0
$labelAppName.MaximumSize = $System_Drawing_Size
$labelAppName.Margin = '0,15,0,15'
$labelAppName.Padding = $labelPadding
$labelAppName.TabIndex = 1
## Initial form layout: Close Applications / Allow Deferral
If ($showCloseApps) {
$labelAppNameText = $configClosePromptMessage
}
ElseIf (($showDefer) -or ($forceCountdown)) {
$labelAppNameText = "$configDeferPromptWelcomeMessage `n$installTitle"
}
If ($CustomText) {
$labelAppNameText = "$labelAppNameText `n`n$configPromptCustomMessage"
}
$labelAppName.Text = $labelAppNameText
$labelAppName.TextAlign = 'TopCenter'
$labelAppName.Anchor = 'Top'
$labelAppName.AutoSize = $true
$labelAppName.add_Click($handler_labelAppName_Click)
## Listbox Close Applications
$listBoxCloseApps.DataBindings.DefaultDataSourceUpdateMode = 0
$listBoxCloseApps.FormattingEnabled = $true
$listBoxCloseApps.HorizontalScrollbar = $true
$listBoxCloseApps.Name = 'listBoxCloseApps'
$System_Drawing_Size = New-Object -TypeName 'System.Drawing.Size'
$System_Drawing_Size.Height = 100
$System_Drawing_Size.Width = 300
$listBoxCloseApps.Size = $System_Drawing_Size
$listBoxCloseApps.Margin = '75,0,0,0'
$listBoxCloseApps.TabIndex = 3
$ProcessDescriptions | ForEach-Object { $listboxCloseApps.Items.Add($_) | Out-Null }
## Label Defer
$labelDefer.DataBindings.DefaultDataSourceUpdateMode = 0
$labelDefer.Name = 'labelDefer'
$System_Drawing_Size = New-Object -TypeName 'System.Drawing.Size'
$System_Drawing_Size.Height = 90
$System_Drawing_Size.Width = 450
$labelDefer.Size = $System_Drawing_Size
$System_Drawing_Size.Height = 0
$labelDefer.MaximumSize = $System_Drawing_Size
$labelDefer.Margin = $paddingNone
$labelDefer.Padding = $labelPadding
$labelDefer.TabIndex = 4
$deferralText = "$configDeferPromptExpiryMessage`n"
If ($deferTimes -ge 0) {
$deferralText = "$deferralText `n$configDeferPromptRemainingDeferrals $([int32]$deferTimes + 1)"
}
If ($deferDeadline) {
$deferralText = "$deferralText `n$configDeferPromptDeadline $deferDeadline"
}
If (($deferTimes -lt 0) -and (-not $DeferDeadline)) {
$deferralText = "$deferralText `n$configDeferPromptNoDeadline"
}
$deferralText = "$deferralText `n`n$configDeferPromptWarningMessage"
$labelDefer.Text = $deferralText
$labelDefer.TextAlign = 'MiddleCenter'
$labelDefer.AutoSize = $true
$labelDefer.add_Click($handler_labelDefer_Click)
## Label Countdown
$labelCountdown.DataBindings.DefaultDataSourceUpdateMode = 0
$labelCountdown.Name = 'labelCountdown'
$System_Drawing_Size = New-Object -TypeName 'System.Drawing.Size'
$System_Drawing_Size.Height = 40
$System_Drawing_Size.Width = 450
$labelCountdown.Size = $System_Drawing_Size
$System_Drawing_Size.Height = 0
$labelCountdown.MaximumSize = $System_Drawing_Size
$labelCountdown.Margin = $paddingNone
$labelCountdown.Padding = $labelPadding
$labelCountdown.TabIndex = 4
$labelCountdown.Font = 'Microsoft Sans Serif, 9pt, style=Bold'
$labelCountdown.Text = '00:00:00'
$labelCountdown.TextAlign = 'MiddleCenter'
$labelCountdown.AutoSize = $true
$labelCountdown.add_Click($handler_labelDefer_Click)
## Panel Flow Layout
$System_Drawing_Point = New-Object -TypeName 'System.Drawing.Point'
$System_Drawing_Point.X = 0
$System_Drawing_Point.Y = 50
$flowLayoutPanel.Location = $System_Drawing_Point
$flowLayoutPanel.AutoSize = $true
$flowLayoutPanel.Anchor = 'Top'
$flowLayoutPanel.FlowDirection = 'TopDown'
$flowLayoutPanel.WrapContents = $true
$flowLayoutPanel.Controls.Add($labelAppName)
If ($showCloseApps) { $flowLayoutPanel.Controls.Add($listBoxCloseApps) }
If ($showDefer) {
$flowLayoutPanel.Controls.Add($labelDefer)
}
If ($showCountdown) {
$flowLayoutPanel.Controls.Add($labelCountdown)
}
## Button Close For Me
$buttonCloseApps.DataBindings.DefaultDataSourceUpdateMode = 0
$buttonCloseApps.Location = '15,0'
$buttonCloseApps.Name = 'buttonCloseApps'
$buttonCloseApps.Size = $buttonSize
$buttonCloseApps.TabIndex = 5
$buttonCloseApps.Text = $configClosePromptButtonClose
$buttonCloseApps.DialogResult = 'Yes'
$buttonCloseApps.AutoSize = $true
$buttonCloseApps.UseVisualStyleBackColor = $true
$buttonCloseApps.add_Click($buttonCloseApps_OnClick)
## Button Defer
$buttonDefer.DataBindings.DefaultDataSourceUpdateMode = 0
If (-not $showCloseApps) {
$buttonDefer.Location = '15,0'
}
Else {
$buttonDefer.Location = '170,0'
}
$buttonDefer.Name = 'buttonDefer'
$buttonDefer.Size = $buttonSize
$buttonDefer.TabIndex = 6
$buttonDefer.Text = $configClosePromptButtonDefer
$buttonDefer.DialogResult = 'No'
$buttonDefer.AutoSize = $true
$buttonDefer.UseVisualStyleBackColor = $true
$buttonDefer.add_Click($buttonDefer_OnClick)
## Button Continue
$buttonContinue.DataBindings.DefaultDataSourceUpdateMode = 0
$buttonContinue.Location = '325,0'
$buttonContinue.Name = 'buttonContinue'
$buttonContinue.Size = $buttonSize
$buttonContinue.TabIndex = 7
$buttonContinue.Text = $configClosePromptButtonContinue
$buttonContinue.DialogResult = 'OK'
$buttonContinue.AutoSize = $true
$buttonContinue.UseVisualStyleBackColor = $true
$buttonContinue.add_Click($buttonContinue_OnClick)
If ($showCloseApps) {
# Add tooltip to Continue button
$toolTip.BackColor = [Drawing.Color]::LightGoldenrodYellow
$toolTip.IsBalloon = $false
$toolTip.InitialDelay = 100
$toolTip.ReshowDelay = 100
$toolTip.SetToolTip($buttonContinue, $configClosePromptButtonContinueTooltip)
}
from psappdeploytoolkit.
In my tests using the code above everything worked as expected. I used the following command line for testing:
Show-InstallationWelcome -AllowDefer -ForceCountdown 3600 -DeferTimes 2 -DeferDays 7 -PersistPrompt -TopMost 0 -CustomText
from psappdeploytoolkit.
This is how this code looks with deferrals left:
This is how this code looks when there are no deferrals left:
from psappdeploytoolkit.
@mmashwani I wonder if you are considering the inclusion of this feature for the next release?
from psappdeploytoolkit.
Yes, I will add this to the next release.
from psappdeploytoolkit.
@mmashwani Thank you so much!
from psappdeploytoolkit.
I have included this in the latest beta. Please test and let me know if it's working as expected. The text for one of the new XML config options still needs to be translated into different languages before we release a final version.
from psappdeploytoolkit.
I tested a few scenarios and everything is working fine, thanks a lot!
I can help with the Brazilian Portuguese translation:
<WelcomePrompt_CountdownMessage>A {0} vai continuar automaticamente em:</WelcomePrompt_CountdownMessage>
My team suggested improvements to the languages of the two texts below, it might also be valuable for the Toolkit:
<DeferPrompt_ExpiryMessage>You can choose to defer the installation until the deferral deadline:</DeferPrompt_ExpiryMessage>
<DeferPrompt_WarningMessage>Once the deadline has passed, you will no longer have the option to defer.</DeferPrompt_WarningMessage>
Another suggestion: wouldn't be better to always use {0} when we have the install or uninstall text on the XML file and replace it with the appropriate information during runtime just like the code that was included?
from psappdeploytoolkit.
Related Issues (20)
- Reference/documentation as pdf
- [Feature] Add and Remove Registry Key Values from Type MultiString without affecting existing ones
- [Bug] v3.10.1 Deploy-Application.exe triggers Defender ASR for vulnerable signed drivers HOT 1
- [Feature] Add AppDeployToolkitLogo.png in customization documentation HOT 1
- [Bug] Function Write-log does not work if log filename has Square Brackets HOT 7
- [Bug] No execute-ProcessasUser by Active Setup with *.cmd as Systemaccount HOT 1
- [Bug] Deploy-Application.exe crashing on several devices HOT 1
- [Bug] Function code examples do not work correctly with Get-Help HOT 1
- [Bug] Logs created during user context execution are not allowed to be altered by other users HOT 1
- Execution failed HOT 3
- Execute-ProcessAsUser throws terminating error when no users are logged on and ContinueOnError=$true (i.e. the default)
- Async operations (e.g. Show-InstallationPrompt) triggers rotation of a new log file when <Toolkit_LogAppend> is set to False
- Test-ServiceExists failes on Sandbox - Get-WmiObject : Provider load failure HOT 7
- [Bug] Show-InstallationWelcome -PersistPrompt not working HOT 1
- [Bug] Function Block-AppExecution not working if.. HOT 2
- [Bug] Robocopy /IM parameter not supported on older operating systems HOT 2
- [Feature] Functions Documentation on Website lacks Version Information HOT 2
- [Bug] .vscode\PSScriptAnalyzerSettings.psd1 contains a spelling error
- [Feature] Configurable prefix for LogFileName HOT 3
- [Bug] Error setting directory attributes when using Copy-File with Robocopy HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from psappdeploytoolkit.