Powershell GUI for workstation restart reminder - how to postpone reminder

Hello - fairly new to Powershell and working on a solution for a small subset of our users.  We have mandatory periodic reboots of our workstations, performed at night.  We have folks in an operations monitoring area whose work can be disrupted when we kick off the reboots (via config manager).  So the idea is to give them reminders to reboot when practicable but to not force them.  They choose a postpone notification time in hours from a pulldown.  I have cobbled together code from different scripts I've found and have something that is halfway to working but am having trouble with a couple things.

First, my while statement - when I select a number value in hours to postpone and then click postpone, I want the form to hide or close until the hour interval happens and then it will bring up the form again.  I'm trying to write a null output while the time on click is less than the time plus the number of hours chosen, but I end up immediately running the script again, which I only want to do after the interval. I also tried an if/then but same results.  What it seems I really need to do is be able to sleep for the interval instead of close the script.

Second I wanted to add a description in the form and didn't know how to build it from scratch so I made a blank form in primalforms and then grabbed the label code and inserted but no matter how I adjust the x and y I can't get it to appear in the form.

Note if you run it name it timed_reboot so the variable $scriptpath works.  Thanks for any advice you can offer!

[void][System.Reflection.Assembly]::LoadWithPartialName( System.Windows.Forms)
[void][System.Reflection.Assembly]::LoadWithPartialName( Microsoft.VisualBasic)

$form = New-Object System.Windows.Forms.Form;
$form.Width = 425;
$form.Height = 150;
$form.Text = "Computer Reboot Notification";
$form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen;
$DropDownArray = @("1", "2", "3", "4")
$DDL = New-Object System.Windows.Forms.ComboBox
$DDL.Location = New-Object System.Drawing.Size(170,30)
$DDL.Size = New-Object System.Drawing.Size(80,40)

# sets path to script to current directory
$executingScriptDirectory = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
$scriptPath = Join-Path $executingScriptDirectory "timed_reboot.ps1"

$form1 = New-Object System.Windows.Forms.Form
$label1 = New-Object System.Windows.Forms.Label
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 130
$System_Drawing_Point.Y = 10
$label1.Location = $System_Drawing_Point
$label1.Name = "label1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 21
$System_Drawing_Size.Width = 272
$label1.Size = $System_Drawing_Size
$label1.TabIndex = 0
$label1.Text = "Please select the number of hours to delay notification"

ForEach ($Item in $DropDownArray) {

    $DDL.Items.Add($Item) | Out-Null

}
$DDL.SelectedIndex  = 0

$button1 = New-Object System.Windows.Forms.button;
$button1.Left = 30;
$button1.Top = 85;
$button1.Width = 100;
$button1.Text = Reboot Now;
$button1.Add_Click($button1_OnClick)
$button1_OnClick = {Restart-Computer -Force -ComputerName localhost}

$button2 = New-Object System.Windows.Forms.button;
$button2.Left = 155;
$button2.Top = 85;
$button2.Width = 100;
$button2.Text = Postpone;
$button2.Add_Click($button2_OnClick)
$button2_OnClick = {
   $Time_On_Click = (Get-Date -Format g)
   $AddHours = (Get-Date -Format g).AddHours($textBox_Sender.text)  
  
    while ($Time_On_Click -lt $AddHours)
    
    {
        
        Write-Output = $Null
        $form.close()
        
    }
        
        invoke-expression "$scriptPath"
    }
  
$button3 = New-Object System.Windows.Forms.button;
$button3.Left = 290;
$button3.Top = 85;
$button3.Width = 100;
$button3.Text = Abort Shutdown;
$button3.Add_Click($button3_OnClick)
$button3_OnClick = {$form.Close()}

$form.Controls.Add($button1);
$form.Controls.Add($button2);
$form.Controls.Add($button3);
$form.Controls.Add($DDL);
$form.Controls.Add($textLabel1)
$ret = $form.ShowDialog();
$form.Controls.Add($label1)

$form.KeyPreview = $True
$form.Add_KeyDown({if ($_.KeyCode -eq "Enter") 
    {$x=$textBox1.Text;$form.Close()}})
$form.Add_KeyDown({if ($_.KeyCode -eq "Escape") 
    {$form.Close()}})

July 21st, 2015 11:34am

$delay = 60 * 60 * 1 #hour

$form.Visible=$false
Sleep -seconds $delay
$form.Visible=$true

Free Windows Admin Tool Kit Click here and download it now
July 21st, 2015 1:14pm

What you will find with forms is that you cannot hide them.

$form.Minimize()
Sleep -seconds $delay
$form.Maximize()

Might work.

July 21st, 2015 1:15pm

this works

$buttonDelay_Click={
    $form1.WindowState='Minimized'
    Write-Host 'waiting'
    sleep -Seconds 10
    Write-Host 'resuming'
    $form1.WindowState='Normal'
}

Free Windows Admin Tool Kit Click here and download it now
July 21st, 2015 1:29pm

Here is the working version:

Add-Type -AssemblyName System.Windows.Forms $form = New-Object System.Windows.Forms.Form $form.TopMost=$true
$form.StartPosition='CenterScreen' $form.Size='425,150' $button1_OnClick={ $form.WindowState = 'Minimized' Write-Host 'waiting' sleep -Seconds 10 Write-Host 'resuming' $form.WindowState = 'Normal' } $button1 = New-Object System.Windows.Forms.button $form.Controls.Add($button1); $button1.Location='30,85' $button1.Text ='Delay' $button1.Add_Click($button1_OnClick) $form.ShowDialog()

July 21st, 2015 1:40pm

Visible-$false also works,

Free Windows Admin Tool Kit Click here and download it now
July 21st, 2015 1:43pm

Whew, thanks JRV.  Looks a lot simpler than getting dates and while statements.  I think it'll be fine minimized on their desktops like that.  I'll work on adding it into the script and will update.  Thanks again.
July 21st, 2015 2:16pm

You are welcome.  Sometimes things really are simple.  Whenever you get complicated stop and think, "What am I missing?"
Free Windows Admin Tool Kit Click here and download it now
July 21st, 2015 2:20pm

True enough!  It all works properly with one exception - now I have them entering a number of minutes into a text box and  then I have to take this number and put it into the sleep command.  When I do something like

$multiplier = 3600

sleep -seconds ($textbox_Minutes.Test) * $multiplier

I get my number of minutes 3600 times, i.e., 5555555555555 etc.

I'm trying to convert my text input from the box into an int32, assuming this will fix it, but it isn't working,

like

[string]$textbox_Minutes.toInt32()

Does this not convert it?

Thanks!

July 22nd, 2015 9:43am

sleep -seconds ($textbox_Minutes.Test * $multiplier)

Test????

Free Windows Admin Tool Kit Click here and download it now
July 22nd, 2015 10:20am

Yea, typo "test" should be text.

No still getting the same result.  I entered 2 in my text box.

PS Z:\> C:\powershell\timed_rebootFUNCTesting.ps1
waiting
Start-Sleep : Cannot bind parameter 'Seconds'. Cannot convert value 
"222222222222222222222222222222222222222222222222222222222222" to type "System.Int32". Error: "Value was either 
too large or too small for an Int32."
At C:\powershell\timed_rebootFUNCTesting.ps1:54 char:24
+         sleep -Seconds ($textBox_Minutes.Text * $multiplier)
+                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Start-Sleep], ParameterBindingException
    + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.StartSleepCommand
 
resuming

I did
[void][System.Reflection.Assembly]::LoadWithPartialName( System.Windows.Forms)
[void][System.Reflection.Assembly]::LoadWithPartialName( Microsoft.VisualBasic)

$form = New-Object System.Windows.Forms.Form;
$form.Width = 425;
$form.Height = 150;
$form.Text = "Computer Reboot Notification";
$form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen;

$textBox_Minutes = New-Object System.Windows.Forms.TextBox
$textBox_Minutes.Location = New-Object System.Drawing.Size(165,44)
$textBox_Minutes.Size = New-Object System.Drawing.Size(80,40)
$textBox_Minutes.Text = ""

$form1 = New-Object System.Windows.Forms.Form
$label1 = New-Object System.Windows.Forms.Label
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 65
$System_Drawing_Point.Y = 10
$label1.Location = $System_Drawing_Point
$label1.Name = "label1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 21
$System_Drawing_Size.Width = 325
$label1.Size = $System_Drawing_Size
$label1.TabIndex = 0
$label1.Text = "Please enter the number of minutes to postpone notification"
$multiplier = 60

$button1 = New-Object System.Windows.Forms.button;
$button1.Left = 30;
$button1.Top = 85;
$button1.Width = 100;
$button1.Text = Reboot Now;
$button1.Add_Click($button1_OnClick)
$button1_OnClick = {Restart-Computer -Force -ComputerName localhost}

$button2 = New-Object System.Windows.Forms.button;
$button2.Left = 155;
$button2.Top = 85;
$button2.Width = 100;
$button2.Text = Postpone;
$button2.Add_Click($button2_OnClick)
$button2_OnClick = {
    
    $form.WindowState = 'Minimized'
    Write-Host 'waiting'
        sleep -Seconds ($textBox_Minutes.Text * $multiplier)
    Write-Host 'resuming'
    $form.WindowState = 'Normal'
    }
  
$button3 = New-Object System.Windows.Forms.button;
$button3.Left = 290;
$button3.Top = 85;
$button3.Width = 100;
$button3.Text = Abort Shutdown;
$button3.Add_Click($button3_OnClick)
$button3_OnClick = {$form.Close()}

$form.Controls.Add($button1);
$form.Controls.Add($button2);
$form.Controls.Add($button3);
$form.Controls.Add($textBox_Minutes);
$form.Controls.Add($textLabel1)
$form.Controls.Add($label1)
$ret = $form.ShowDialog();
$form.KeyPreview = $True
$form.Add_KeyDown({if ($_.KeyCode -eq "Enter") 
    {$x=$textBox1.Text;$form.Close()}})
$form.Add_KeyDown({if ($_.KeyCode -eq "Escape") 
    {$form.Close()}})

July 22nd, 2015 11:10am

Try this at a prompt:

2 * 10

'2' * 10

10 * '2'

[int]'2' * 10

Free Windows Admin Tool Kit Click here and download it now
July 22nd, 2015 11:44am

OK thanks.  I ran through them and it makes sense.

After a few combinations I got it to work via prompt.

PS Z:\> $multiplier.GetType().FullName
System.Int32

PS Z:\>  ([int]$textBox_Minutes.Text).GetType().FullName
System.Int32

PS Z:\>  (([int]$textBox_Minutes.Text) * $multiplier)
120

PS Z:\> sleep -Seconds (([int]$textBox_Minutes.Text) * $multiplier)

PS Z:\> 

The sleep worked here.  Then I ran it in the script and got

waiting
Start-Sleep : A positional parameter cannot be found that accepts argument '*'.
At C:\powershell\timed_rebootFUNCTesting.ps1:54 char:9
+         sleep -Seconds ([int]$textBox_Minutes.Text) * [int]$multiplier
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Start-Sleep], ParameterBindingException
    + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.StartSleepCommand
 
resuming

Then I closed Powershell ISE and reopened and everything worked fine. Not sure what happened, like some previous work was held in a register or something.

Anyway I appreciate all your help, jrv.

July 22nd, 2015 2:18pm

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics