Powershell timer : no action is launched - c

I want my timer to consult a file (consigne.csv) and display the "consigne" column according to the date I defined.
The data of this file would be regularly modified, hence the choice of the timer.
The form opens with the correct information but the information is not updated.
Thanks for your help.
Script :
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
[System.Windows.Forms.Application]::EnableVisualStyles();
################ TIMER ##################################
$Timer = new-object System.Windows.forms.timer
$Timer.Interval = 1000
#Action.
$Timer.Add_Tick({
#Interval after boot.
$Timer.Interval = (5000)
#Command
$global:today = get-date -format "dd/MM/yy"
$global:DesktopPath = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::Desktop)
$global:TxtConsigne= (import-csv "$DesktopPath\consigne.csv" -encoding UTF8 -delimiter ";")
$global:Message = ($TxtConsigne | where-object {$_.EXPIRATION -ge $today})
})
################ Form #####################################
#Form
$Form = New-Object System.Windows.Forms.Form
$Form.Location = New-Object System.Drawing.Point 0,570
$Form.Size = New-Object System.Drawing.Size(1920,260)
# Consigne
$Consigne = New-Object system.windows.Forms.Label
$Consigne.Location = New-Object System.Drawing.Point 210,20
$Consigne.Size = New-Object System.Drawing.Size(1500,220)
$Form.Controls.Add($Consigne)
################################################################################################################
# $DesktopPath = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::Desktop)
# $TxtConsigne= (import-csv "$DesktopPath\consigne.csv" -encoding UTF8 -delimiter ";")
# $Message = ($TxtConsigne | where-object {$_.EXPIRATION -ge $today})
$Timer.Start()
if ($Message){
$Message | FOREACH{
$Mess += "- " + $_.Consigne + "`n"
$Consigne.Text = $Mess
}
$Mess=$null
#Affichage de la fenêtre uniquement si consigne à passer
[void]$Form.ShowDialog()
}
$Timer.Stop()
and content of consigne.csv
DATE;EXPIRATION;CONSIGNE; 12/09/20;15/09/20;Message 4;
11/09/20;11/09/20;Message 3; 10/09/20;11/09/20;Message 2;
10/09/20;10/09/20;Message 1;

You don't need all those $global:xxx variables in the Timer event handler; just one for the path to the CSV file would be enough. Also, it could do with a lesser scope: $script:xxx.
Then, you are comparing a date as formatted string in format dd/MM/yy which does not compare like you think, since the day comes earlier than the month. (it is a non-sortable date format).
Always try to compare datetime objects to other datetime objects.
Try:
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
[System.Windows.Forms.Application]::EnableVisualStyles();
# the path to the csv file used in the timer event handler.
$csvPath = Join-Path -Path ([Environment]::GetFolderPath("Desktop")) -ChildPath 'consigne.csv'
################ Form #####################################
#Form
$Form = New-Object System.Windows.Forms.Form
$Form.Location = New-Object System.Drawing.Point 0,570
$Form.Size = New-Object System.Drawing.Size(1920,260)
# Consigne
$Consigne = New-Object System.Windows.Forms.Label
$Consigne.Location = New-Object System.Drawing.Point 210,20
$Consigne.Size = New-Object System.Drawing.Size(1500,200)
$Form.Controls.Add($Consigne)
################ TIMER ##################################
$Timer = New-Object System.Windows.forms.timer
$Timer.Enabled = $false # disabled at first
$Timer.Interval = 50 # initial timer interval
# Timer Action.
$Timer.Add_Tick({
$this.Interval = 5000 # inside the event handler, you can refer to the control with `$this`
$Consigne.Text = [string]::Empty # clear the label
# read the CSV file, get the items with an EXPIRATION date greater
# or equal to today and write the CONSIGNE messages to the label
(Import-Csv -Path $script:csvPath -Encoding UTF8 -Delimiter ";") |
Where-Object { [datetime]::ParseExact($_.EXPIRATION, 'dd/MM/yy', $null) -ge (Get-Date).Date } |
ForEach-Object {$Consigne.Text += "- {0}`r`n" -f $_.CONSIGNE }
})
# start the timer as soon as the form is shown
$Form.Add_Shown({$Timer.Enabled = $true; $Timer.Start()})
[void]$Form.ShowDialog()
# clean up the Timer and Form objects
$Timer.Dispose()
$Form.Dispose()

Related

Monitor a folder using Powershell and check it against a SQL table and send an email out if file doesn't exists in the last 6 hours

I am using powershell to check a folder and when a file gets added to the folder, it queries a sql table and if there hasn't been a file added in the last 6 hours then it will send an email to several people letting them know that the file was copied/uploaded to that folder.
I can send the email when a file gets added, but when I added the code to check the SQL table, it stopped working. Can someone help me figure out the rest of this script?
[code]
# make sure you adjust this to point to the folder you want to monitor
$PathToMonitor = "U:\temp\test"
explorer $PathToMonitor
$FileSystemWatcher = New-Object System.IO.FileSystemWatcher
$FileSystemWatcher.Path = $PathToMonitor
$FileSystemWatcher.IncludeSubdirectories = $true
# make sure the watcher emits events
$FileSystemWatcher.EnableRaisingEvents = $true
# define the code that should execute when a file change is detected
$Action = {
$details = $event.SourceEventArgs
$Name = $details.Name
$FullPath = $details.FullPath
$OldFullPath = $details.OldFullPath
$OldName = $details.OldName
$ChangeType = $details.ChangeType
$Timestamp = $event.TimeGenerated
$JustPath = Path.GetDirectoryName($FullPath)
# SQL Work ---------------------------------------------------------------------
$Server = 'SQL01'
$Database = 'FTP_Upload'
$Connection = New-Object System.Data.SQLClient.SQLConnection
$Connection.ConnectionString = "server='$Server';database='$Database';trusted_connection=true;"
$Connection.Open()
$Command = New-Object System.Data.SQLClient.SQLCommand
$Command.Connection = $Connection
$text = "{0} was {1} at {2}" -f $FullPath, $ChangeType, $Timestamp
$sql = "IF Not Exists (Select 1 From Transmit Where DateDiff(IsNull(TimeGenerated, '01/01/2020 01:00:00 PM'), '$Timestamp') < 6 ) AND PathOnly = '$JustPath' )
BEGIN
Insert Transmit(FullPath, PathOnly, TimeGenerated)
Values('$FullPath', '$JustPath', '$Timestamp')
END "
Write-Host ""
Write-Host $text -ForegroundColor Green
Write-Host $sql
# you can also execute code based on change type here
switch ($ChangeType)
{
'Created' {
# Check SQL to see if there has been a file ftp'd in the last 6 hours ------
$Command.CommandText = $sql
$Command.ExecuteReader()
$Connection.Close()
# Send Email ---------------------------------
$EmailFrom = “email1#domain1.com”
$EmailTo = “email2#domain2.com, email3#domain3.com”
$Subject = “FTP Notification”
$Body = $text
$SMTPServer = “smtp.office365.com”
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587)
$SMTPClient.EnableSsl = $true
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential(“email1#domain1.com”, “password”);
$SMTPClient.Send($EmailFrom, $EmailTo, $Subject, $Body)
Start-Sleep -Seconds 5
$SMTPClient.Dispose()
# this executes only when a file was renamed
$text = "File {0} was Created" -f $FullPath
Write-Host $text -ForegroundColor Yellow
}
default { Write-Host $_ -ForegroundColor Red -BackgroundColor White }
}
}
# add event handlers
$handlers = . {
Register-ObjectEvent -InputObject $FileSystemWatcher -EventName Changed -Action $Action -SourceIdentifier FSChange
Register-ObjectEvent -InputObject $FileSystemWatcher -EventName Created -Action $Action -SourceIdentifier FSCreate
Register-ObjectEvent -InputObject $FileSystemWatcher -EventName Deleted -Action $Action -SourceIdentifier FSDelete
Register-ObjectEvent -InputObject $FileSystemWatcher -EventName Renamed -Action $Action -SourceIdentifier FSRename
}
Write-Host "Watching for changes to $PathToMonitor"
try
{
do
{
Wait-Event -Timeout 1
Write-Host "." -NoNewline
} while ($true)
}
finally
{
# this gets executed when user presses CTRL+C
# remove the event handlers
Unregister-Event -SourceIdentifier FSChange
Unregister-Event -SourceIdentifier FSCreate
Unregister-Event -SourceIdentifier FSDelete
Unregister-Event -SourceIdentifier FSRename
# remove background jobs
$handlers | Remove-Job
# remove filesystemwatcher
$FileSystemWatcher.EnableRaisingEvents = $false
$FileSystemWatcher.Dispose()
"Event Handler disabled."
}
[/code]

Run Multiple Script Instances

I work in an operations center with 10 screens on each computer. The main computer shows a lot of telemetry data and dashboards, graphs, animations, and a lot of other useful information via Chrome in a browser window. This is tedious to set up every time you reboot the computer, so I was very happy to find this original project: Chrome-Kiosk from https://alextomin.wordpress.com/2015/04/10/kiosk-mode-in-windows-chrome-on-multiple-displays/
It works very well as an auto starter in our operations center, so I am happy with that aspect of its functionality. But then I got to thinking: wouldn't it be useful if I could somehow temporarily display a webpage on the board, and have it close after a set time period so that the whole office can monitor an important event.
What I came up with is quite cool so far, and the people at work think that it is very useful, BUT, it needs more features. These are simple but I am stuck, I have been trying to figure this out for a while now. Below is the code that I am using.
Things that I can't get to work:
Kill Timer: I can get this to work by adding start-wait in front of the kill function that I have created, but that makes the looper.ps1 script sit and wait while the launcher.ps1 completes. How can I get the script to run without making the looper script stop until the other script finishes?
How can I track each new instance of Chrome that gets opened? Using the system ID does not seem to work, the best I can do is get-process and sort by chrome and the newest instance, which means that I can kill chrome instances that are younger than the timer value, but I am struggling to get this to work.
Any advice here would be appreciated.
SERVER SCRIPTS
I have put these into a folder called c:\scripts\ICVT
looper.ps1 - This will run constantly
Set-Location -Path C:\scripts\ICVT
while ($true) {
.\file_checker.ps1;
}
file_checker.ps1 - This is the script that looper runs. file_checker scans the folder for web.txt and mon.txt . Both must be present for the rest of the script to execute.
#Checks folder for web.txt and mon.txt . Both must be present for the rest of the script to execute
Set-Location -Path C:\scripts\ICVT
$a = Test-Path web.txt
$b = Test-Path mon.txt
if (($a -and $b -eq $True)) {
.\launcher.ps1
} else {
Write-Host "Scanning For Files"
}
Start-Sleep -Seconds 5
launcher.ps1 - This is just a modified version of the original script
$chromePath = 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe'
$chromeArguments = '--new-window'
$web = (Get-Content -Path web.txt)
$mon = (Get-Content -Path mon.txt)
$timer = (Get-Content -Path $timer.txt)
# if Window not moved (especially on machine start) - try increasing the
# delay.
$ChromeStartDelay = 5
Set-Location $PSScriptRoot
. .\HelperFunctions.ps1
Chrome-Kiosk $web -MonitorNum $mon
#Delete parameters after use
Start-Sleep -Seconds 5
del web.txt
del mon.txt
del timer.txt
Here is the GUI that creates the web.txt, timer.txt and mon.txt files over the network
Set-Location -Path \\networkpc\folder
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
# Hide PowerShell Console
Add-Type -Name Window -Namespace Console -MemberDefinition '
[DllImport("Kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
'
$consolePtr = [Console.Window]::GetConsoleWindow()
[Console.Window]::ShowWindow($consolePtr, 0)
function button ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) {
$Form = New-Object "system.Windows.Forms.Form";
$Form.ClientSize = '653,436'
$Form.text = "Display Board URL Tool"
$Form.TopMost = $false
$form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen;
$iconBytes = [Convert]::FromBase64String($iconBase64)
$stream = New-Object IO.MemoryStream($iconBytes, 0, $iconBytes.Length)
$stream.Write($iconBytes, 0, $iconBytes.Length);
$iconImage = [System.Drawing.Image]::FromStream($stream, $true)
$Form.Icon = [System.Drawing.Icon]::FromHandle((New-Object System.Drawing.Bitmap -Argument $stream).GetHIcon())
$Button1 = New-Object "system.Windows.Forms.Button";
$Button1.text = "Screen 1"
$Button1.width = 132
$Button1.height = 77
$Button1.location = New-Object "System.Drawing.Point"(8,14);
$Button1.Font = 'Microsoft Sans Serif,10'
$Button2 = New-Object "system.Windows.Forms.Button";
$Button2.text = "Screen 2"
$Button2.width = 132
$Button2.height = 77
$Button2.location = New-Object "System.Drawing.Point"(165,14);
$Button2.Font = 'Microsoft Sans Serif,10'
$Button3 = New-Object "system.Windows.Forms.Button";
$Button3.text = "Screen 3"
$Button3.width = 132
$Button3.height = 77
$Button3.location = New-Object "System.Drawing.Point"(326,14);
$Button3.Font = 'Microsoft Sans Serif,10'
$Button4 = New-Object "system.Windows.Forms.Button";
$Button4.text = "Screen 4"
$Button4.width = 132
$Button4.height = 77
$Button4.location = New-Object "System.Drawing.Point"(483,15);
$Button4.Font = 'Microsoft Sans Serif,10'
$WinForm1 = New-Object "system.Windows.Forms.Form";
$WinForm1.ClientSize = '653,400'
$WinForm1.text = "Form"
$WinForm1.TopMost = $false
$Button5 = New-Object "system.Windows.Forms.Button";
$Button5.text = "Screen 5"
$Button5.width = 132
$Button5.height = 77
$Button5.location = New-Object "System.Drawing.Point"(8,117);
$Button5.Font = 'Microsoft Sans Serif,10'
$Button6 = New-Object "system.Windows.Forms.Button";
$Button6.text = "Screen 6"
$Button6.width = 132
$Button6.height = 77
$Button6.location = New-Object "System.Drawing.Point"(165,119);
$Button6.Font = 'Microsoft Sans Serif,10'
$Button7 = New-Object "system.Windows.Forms.Button";
$Button7.text = "Screen 7"
$Button7.width = 132
$Button7.height = 77
$Button7.location = New-Object "System.Drawing.Point"(326,119);
$Button7.Font = 'Microsoft Sans Serif,10'
$Button8 = New-Object "system.Windows.Forms.Button";
$Button8.text = "Screen 8"
$Button8.width = 132
$Button8.height = 77
$Button8.location = New-Object "System.Drawing.Point"(483,119);
$Button8.Font = 'Microsoft Sans Serif,10'
$Button9 = New-Object "system.Windows.Forms.Button";
$Button9.text = "Screen 9"
$Button9.width = 132
$Button9.height = 77
$Button9.location = New-Object "System.Drawing.Point"(9,220);
$Button9.Font = 'Microsoft Sans Serif,10'
$Button10 = New-Object "system.Windows.Forms.Button";
$Button10.text = "Screen 10"
$Button10.width = 132
$Button10.height = 77
$Button10.location = New-Object "System.Drawing.Point"(165,220);
$Button10.Font = 'Microsoft Sans Serif,10'
$Button11 = New-Object "system.Windows.Forms.Button";
$Button11.text = "Screen 11"
$Button11.width = 132
$Button11.height = 77
$Button11.location = New-Object "System.Drawing.Point"(326,220);
$Button11.Font = 'Microsoft Sans Serif,10'
$TextBox1 = New-Object "system.Windows.Forms.TextBox";
$TextBox1.multiline = $false
$TextBox1.width = 400
$TextBox1.height = 20
$TextBox1.location = New-Object "System.Drawing.Point"(220,314);
$TextBox1.Font = 'Microsoft Sans Serif,10'
$TextBox2 = New-Object "system.Windows.Forms.TextBox";
$TextBox2.multiline = $false
$TextBox2.width = 50
$TextBox2.height = 20
$TextBox2.location = New-Object "System.Drawing.Point"(220,348);
$TextBox2.Font = 'Microsoft Sans Serif,10'
$Label1 = New-Object "system.Windows.Forms.Label";
$Label1.text = "Display Time (Minutes)"
$Label1.AutoSize = $true
$Label1.width = 25
$Label1.height = 10
$Label1.location = New-Object "System.Drawing.Point"(15,348);
$Label1.Font = 'Microsoft Sans Serif,10'
$Label2 = New-Object "system.Windows.Forms.Label";
$Label2.text = "URL for Timed Monitoring"
$Label2.AutoSize = $true
$Label2.width = 25
$Label2.height = 10
$Label2.location = New-Object "System.Drawing.Point"(15,314);
$Label2.Font = 'Microsoft Sans Serif,10'
$Button12 = New-Object "system.Windows.Forms.Button";
$Button12.text = "Kill Current Screen"
$Button12.width = 132
$Button12.height = 77
$Button12.location = New-Object "System.Drawing.Point"(483,220);
$Button12.Font = 'Microsoft Sans Serif,10'
$Button12.ForeColor = "#d0021b"
$Form.controls.AddRange(#($Button1,$Button2,$Button3,$Button4,$Button5,$Button6,$Button7,$Button8,$Button9,$Button10,$Button11,$TextBox1,$TextBox2,$Label1,$Label2,$Button12))
############# This is when you have to close the form after getting values
$eventHandler1 = [System.EventHandler]{
$textBox1.Text;
$textBox2.Text;
############# Create mon.txt per button
$text = '1'
$text | Set-Content 'mon.txt'
$form.Close();};
$eventHandler2 = [System.EventHandler]{
$textBox1.Text;
$textBox2.Text;
############# Create mon.txt per button
$text = '2'
$text | Set-Content 'mon.txt'
$form.Close();};
$eventHandler3 = [System.EventHandler]{
$textBox1.Text;
$textBox2.Text;
############# Create mon.txt per button
$text = '3'
$text | Set-Content 'mon.txt'
$form.Close();};
$eventHandler4 = [System.EventHandler]{
$textBox1.Text;
$textBox2.Text;
############# Create mon.txt per button
$text = '4'
$text | Set-Content 'mon.txt'
$form.Close();};
$eventHandler5 = [System.EventHandler]{
$textBox1.Text;
$textBox2.Text;
############# Create mon.txt per button
$text = '5'
$text | Set-Content 'mon.txt'
$form.Close();};
$eventHandler6 = [System.EventHandler]{
$textBox1.Text;
$textBox2.Text;
############# Create mon.txt per button
$text = '6'
$text | Set-Content 'mon.txt'
$form.Close();};
$eventHandler7 = [System.EventHandler]{
$textBox1.Text;
$textBox2.Text;
############# Create mon.txt per button
$text = '7'
$text | Set-Content 'mon.txt'
$form.Close();};
$eventHandler8 = [System.EventHandler]{
$textBox1.Text;
$textBox2.Text;
############# Create mon.txt per button
$text = '8'
$text | Set-Content 'mon.txt'
$form.Close();};
$eventHandler9 = [System.EventHandler]{
$textBox1.Text;
$textBox2.Text;
############# Create mon.txt per button
$text = '9'
$text | Set-Content 'mon.txt'
$form.Close();};
$eventHandler10 = [System.EventHandler]{
$textBox1.Text;
$textBox2.Text;
############# Create mon.txt per button
$text = '10'
$text | Set-Content 'mon.txt'
$form.Close();};
$eventHandler11 = [System.EventHandler]{
$textBox1.Text;
$textBox2.Text;
############# Create mon.txt per button
$text = '11'
$text | Set-Content 'mon.txt'
$form.Close();};
$eventHandler12 = [System.EventHandler]{
$textBox1.Text;
$textBox2.Text;
############# Kill the last Screen that was launched
$text = '1'
$text | Set-Content 'mon.txt'
$form.Close();};
$button1.Add_Click($eventHandler1) ;
$button2.Add_Click($eventHandler2) ;
$button3.Add_Click($eventHandler3) ;
$button4.Add_Click($eventHandler4) ;
$button5.Add_Click($eventHandler5) ;
$button6.Add_Click($eventHandler6) ;
$button7.Add_Click($eventHandler7) ;
$button8.Add_Click($eventHandler8) ;
$button9.Add_Click($eventHandler9) ;
$button10.Add_Click($eventHandler10) ;
$button11.Add_Click($eventHandler11) ;
$button12.Add_Click($eventHandler12) ;
#############Add controls to all the above objects defined
$form.Controls.Add($button1);
$form.Controls.Add($button2);
$form.Controls.Add($button3);
$form.Controls.Add($button4);
$form.Controls.Add($button5);
$form.Controls.Add($button6);
$form.Controls.Add($button7);
$form.Controls.Add($button8);
$form.Controls.Add($button9);
$form.Controls.Add($button10);
$form.Controls.Add($button11);
$form.Controls.Add($textLabel1);
$form.Controls.Add($textLabel2);
$form.Controls.Add($textBox1);
$form.Controls.Add($textBox2);
$ret = $form.ShowDialog();
#################return values
return $textBox1.Text, $textBox2.Text
}
#Creates the 3 txt files for web, mon and timer
$return = button "Monitoring Screen Selector" "Enter URL" "Enter Screen # from 1 to 11"
if ($return[0] -ne "") {
$return[0] > web.txt
}
if ($return[0] -eq "") {
exit
}
if ($return[1] -ne "") {
$return[1] > timer.txt
}
if ($return[1] -eq "") {
exit
}
#multiply by 60 to get minutes
if (Test-Path timer.txt) {
if ((Get-Item timer.txt).Length -gt 0kb) {
$result = Get-Content timer.txt
60 * $result > timer.txt
}
}
In order to do a lot of that functionality, you first need to get a Process Id for the Chrome window. In order to do that we need to make a few changes to the Chrome-Kiosk function to return that information. First I change the Start-Process to include the -PassThru parameter. That way I get a process object that I can get the PID from. Another edit to Get-Process to use the Id instead of "chrome", and finally we Write-Output the $Process object.
function Chrome-Kiosk($Url, $MonitorNum)
{
Write-Output "starting chrome $Url , monitor: $MonitorNum"
$Process = Start-Process $chromePath "$chromeArguments $Url" -PassThru
Start-Sleep -Seconds $ChromeStartDelay
$window = (Get-Process -Id $Process.Id | where MainWindowHandle -ne ([IntPtr]::Zero) | select -First 1).MainWindowHandle
$WinAPI::ShowWindow($window, [Tomin.Tools.KioskMode.Enums.ShowWindowCommands]::Restore)
$Helpers::MoveToMonitor($window, $MonitorNum)
$Helpers::SendKey($window, '{F11}')
Start-Sleep -Seconds $ChromeStartDelay
Write-Output $Process
}
The rest of the work is to modify the launcher script to have a kill timer. Essentially we pull the .txt deletion portion back into your file_checker.PS1 script so that we can launch the launcher.ps1 as a new self contained PowerShell process.
file_checker.PS1
#Checks folder for web.txt and mon.txt . Both must be present for the rest of the script to execute
Set-Location -Path C:\scripts\ICVT
$a = Test-Path web.txt
$b = Test-Path mon.txt
IF (($a -and $b -eq $True)) {
. .\launcher.ps1
#Delete parameters after use
del web.txt
del mon.txt
del timer.txt
}
else {
Write-Host "Scanning For Files"
}
Start-Sleep -Seconds 5
By using the modified Chrome-Kiosk function, where it returns the Process object of the Chrome window, we can now have the launcher script launch, sleep, and then kill only the Chrome window that we launched:
launcher.ps1
$chromePath = 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe'
$chromeArguments = '--new-window'
$web = (Get-Content -Path web.txt)
$mon = (Get-Content -Path mon.txt)
$timer = (Get-Content -Path $timer.txt)
# if Window not moved (especially on machine start) - try increasing the
# delay.
$ChromeStartDelay = 5
Set-Location $PSScriptRoot
. .\HelperFunctions.ps1
$Process = Chrome-Kiosk $web -MonitorNum $mon
#Wait some period of time
Start-Sleep -Seconds 60
#Kill the process
Stop-Process $Process

How to limit number of lines in a TextBox and split the lines to strings?

How can I achieve that the input of the TextBox with multilines is only possible to a specific number of lines e.g. 10 lines only.
Further I want to get the input of each line and write each line to a separate variable to work later with this variables. It would be nice if the user gets a messagebox with warning that only 10 lines are possible.
Any help would be appreciated
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
#Assembly PresentationFramework wird geladen
Add-Type -AssemblyName PresentationFramework
$form = New-Object System.Windows.Forms.Form
$form.StartPosition = 'CenterScreen' #Formstartposition Zentrum
$form.Size = New-Object System.Drawing.Size(500,400)
$textBox = New-Object System.Windows.Forms.TextBox
$textBox.DataBindings.DefaultDataSourceUpdateMode = 0
$textBox.Location = New-Object System.Drawing.Point((110),(90))
$textBox.Size = New-Object System.Drawing.Size(288,150)
$textBox.TabIndex = 0
$textBox.Multiline =$true
$form.Controls.Add($textBox)
$form.ShowDialog() | Out-Null
1.Get Line count on the event of TextChanged.
2.Turn the iList into a ArrayList.
3.Get the difference from max line to current line count.
4.Remove the range from the ArrayList.
5.Set the content of the Textbox to the Arraylist
6.Set the curser to end of textbox.
$TextboxMaxLines = 10
$textBox.Add_TextChanged({
If($textBox.Lines.Count -gt $TextboxMaxLines){
[System.Collections.ArrayList]$AL = $textBox.Lines
[int]$LC = ($textBox.Lines.Count - $TextboxMaxLines)
$Al.RemoveRange($TextboxMaxLines, $LC)
$textbox.Lines = $AL
$textbox.SelectionStart = ($textbox.Text.Length)
$textbox.SelectionLength = 0
}
})

Powershell Windows Form listbox selection validation

I have created a powershell script using windows forms containing list boxes to run a cmd command (helps eliminate user-error and expedites process a bit). The only problem I run into is the command will still attempt to run even if an item is not selected on one of the forms I have populate. This can cause the script to simply not run, or it can cause mass amounts of data to be downloaded (the script pulls log files from a server, the listbox helps narrow down the data to be pulled). Is there a way to create error checking for the listbox that will essentially say "hey, you didn't select anything!" before continuing?
Thanks!
Edit (example of first list box):
$form = New-Object System.Windows.Forms.Form
$form.Text = "Select a production environment"
$form.Size = New-Object System.Drawing.Size(190,250)
$form.StartPosition = "CenterScreen"
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Point(10,180)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"
$OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $OKButton
$form.Controls.Add($OKButton)
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Point(85,180)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = "Cancel"
$CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $CancelButton
$form.Controls.Add($CancelButton)
$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(280,20)
$label.Text = "Please select a production environment:"
$form.Controls.Add($label)
$listBox = New-Object System.Windows.Forms.ListBox
$listBox.Location = New-Object System.Drawing.Point(10,40)
$listBox.Size = New-Object System.Drawing.Size(150,20)
$listBox.Height = 140
[void] $listBox.Items.Add("server1")
[void] $listBox.Items.Add("server2")
[void] $listBox.Items.Add("server3")
$form.Controls.Add($listBox)
$form.Topmost = $True
$result = $form.ShowDialog()
if ($result -eq [System.Windows.Forms.DialogResult]::OK)
{
$Prod = $listBox.SelectedItem
$Prod
}
There might be a way to perform this kind of validation using Windows Forms methods, but this uses PowerShell.
Perform $result = $form.ShowDialog() in a Do..Until or Do..While loop and continue showing the dialogue until the user has selected at least one item, and pressed OK - or the user exits the dialogue - else, show a warning and show the dialogue again.
Here is the relevant PowerShell code:
do
{
$result = $form.ShowDialog()
if ($ListBox.SelectedIndices.Count -lt 1 -and $result -eq [System.Windows.Forms.DialogResult]::OK)
{
Write-Warning 'Nothing was selected, please select a server.'
}
}
until (($result -eq [System.Windows.Forms.DialogResult]::OK -and $listBox.SelectedIndices.Count -ge 1) -or $result -ne [System.Windows.Forms.DialogResult]::OK)
Of course, you can replace Write-Warning with whatever you want, such as a message box.
PS: You can use the AddRange method to add an array of items to the $listBox collection, like so: [void] $listBox.Items.AddRange(#("server1", "server2", "server3"))

Powershell Timer without pausing form

Good day all
As usual I am stuck, I have a simple script that is designed to show you the status of a list of systems bitlocker. Give it a txt of system names, it does the rest. All works as intended; however its updating the list on a ticking Timer, which when executing will make the window unresponsive and appear to be broken (to those users who dont understand what its doing). Is there a way to branch this off in some fashion to avoid this hangingup?
I considered doing a branch but I do now know how to make that branch update an object in its parent... if thats even possible.
CODE:
[void] [Reflection.Assembly]::LoadWithPartialName( 'System.Windows.Forms' )
$d = New-Object Windows.Forms.OpenFileDialog
$d.ShowHelp = $true
$d.filter = "System ID List (*.txt)| *.txt"
$result = $d.ShowDialog( )
$names = #()
$names = Get-Content $d.filename
[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")
$myWindow = new-object System.Windows.Forms.form
$myDataGrid = new-object System.windows.forms.DataGridView
$myDataGrid.Location = new-object System.Drawing.Size(20,30)
$myDataGrid.size = new-object System.Drawing.Size(450,480)
$myDataGrid.AllowUserToAddRows = $False
$myDataGrid.AutoSizeColumnsMode = [System.Windows.Forms.DataGridViewAutoSizeColumnsMode]::Fill
$myDataGrid.RowsDefaultCellStyle.BackColor = [System.Drawing.Color]::Bisque
$myDataGrid.AlternatingRowsDefaultCellStyle.BackColor = [System.Drawing.Color]::Beige
$myDataGrid.BorderStyle = [System.Windows.Forms.BorderStyle]::Fixed3D
$myDataGrid.ColumnHeadersDefaultCellSTyle.ForeColor = [System.Drawing.Color]::Maroon
$myDataGrid.ColumnHeadersDefaultCellStyle.BackColor = [System.Drawing.Color]::Tan
$myDataGrid.RowHeadersDefaultCellStyle.BackColor = [System.Drawing.Color]::Tan
$myDataGrid.ColumnHeadersHeightSizeMode = [System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode]::AutoSize
$myWindow.Controls.Add($myDataGrid)
# Define menus
$myMenuStrip = new-object System.Windows.Forms.MenuStrip
$FileExit = new-object System.Windows.Forms.ToolStripMenuItem("&Exit")
$FileExit.add_Click({ $myWindow.close() })
$myMenuStrip.Items.Add($FileMenu)
$myWindow.Controls.Add($myMenuStrip)
$timer = New-Object System.Windows.Forms.Timer
$timer.Interval = 1000
$timer.add_tick({
$dataTable = New-Object System.Data.DataTable
$dataTable.Columns.Add("System") | Out-Null
$dataTable.Columns.Add("BitLocker % (C:)") | Out-Null
foreach ($name in $names) {
$stat = (manage-bde.exe -cn $name -status C:)[11].split(":")[1]
$row = $dataTable.NewRow()
$row["System"] = $name
$row["BitLocker % (C:)"] = $stat
$dataTable.Rows.Add($row)
}
$myDataGrid.DataSource = $dataTable
})
# main program body
$myWindow.Text = "BitLocker Status"
$myWindow.size = new-object System.Drawing.Size(500,600)
$myWindow.autoscroll = $true
$myWindow.Add_Shown({$myWindow.Activate()})
$timer.Start()
$myWindow.ShowDialog()
I cannot believe nobody answered this, perhaps I wasn't clear.
Eitherway the solution was easy, write-output $object, then receive-job.
Done

Resources