Execute PowerShell GUI locally but send output over the network - windows

I am using the excellent Chrome-Kiosk script from https://github.com/alex-tomin/Tomin.Tools.KioskMode and it works great. I have modified it for our display boards at work and we use it flawlessly with 11 screens.
I wanted to modify it to make a single screen launcher, so I can open a small GUI box, enter the URL to display, and then the screen number that it should display on. I have created a small script and it works perfectly on my local machine. What I want to do is open the GUI on my screen and then send the two variables over the network to the display PC on the network. I had hoped that I would be able to do this with remote execution as found here: https://www.howtogeek.com/117192/how-to-run-powershell-commands-on-remote-computers/, but no luck.
Here is the GUI code:
function button ($title,$mailbx, $WF, $TF) {
[void][System.Reflection.Assembly]::LoadWithPartialName( "System.Windows.Forms")
[void][System.Reflection.Assembly]::LoadWithPartialName( "Microsoft.VisualBasic")
$form = New-Object "System.Windows.Forms.Form";
$form.Width = 500;
$form.Height = 150;
$form.Text = $title;
$form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen;
$textLabel1 = New-Object "System.Windows.Forms.Label";
$textLabel1.Left = 25;
$textLabel1.Top = 15;
$textLabel1.Text = $mailbx;
$textLabel2 = New-Object "System.Windows.Forms.Label";
$textLabel2.Left = 25;
$textLabel2.Top = 50;
$textLabel2.Text = $WF;
$textBox1 = New-Object "System.Windows.Forms.TextBox";
$textBox1.Left = 150;
$textBox1.Top = 10;
$textBox1.width = 200;
$textBox2 = New-Object "System.Windows.Forms.TextBox";
$textBox2.Left = 150;
$textBox2.Top = 50;
$textBox2.width = 200;
$defaultValue = ""
$textBox1.Text = $defaultValue;
$textBox2.Text = $defaultValue;
$button = New-Object "System.Windows.Forms.Button";
$button.Left = 360;
$button.Top = 85;
$button.Width = 100;
$button.Text = "Ok";
$eventHandler = [System.EventHandler]{
$textBox1.Text;
$textBox2.Text;
$form.Close();
};
$button.Add_Click($eventHandler) ;
# Add controls to all the above objects defined
$form.Controls.Add($button);
$form.Controls.Add($textLabel1);
$form.Controls.Add($textLabel2);
$form.Controls.Add($textLabel3);
$form.Controls.Add($textBox1);
$form.Controls.Add($textBox2);
$form.Controls.Add($textBox3);
$ret = $form.ShowDialog();
return $textBox1.Text, $textBox2.Text#, $textBox3.Text
}
$return= button "Monitoring Screen Selector" "Enter URL" "Enter Screen # from 1 to 11" #"Target Folder"
$return[0]
$return[1]
The first part of the script is the GUI, it passes $return[0] and $return[1] into the second part of the script which is below:
$chromePath = 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe'
$chromeArguments = '--new-window'
# if Window not moved (especially on machine start) - try increasing the delay.
$ChromeStartDelay = 3
Set-Location $PSScriptRoot
. .\HelperFunctions.ps1
# Kill all running instances
# &taskkill /im chrome* /F
Chrome-Kiosk $return[0] -MonitorNum $return[1]
So the GUI should open on the local PC, then send $return[0] and $return[1] to the computer with all of the displays plugged into it so that the second part of the script can receive those two inputs from the GUI and then activate the screen and URL.
The idea as that during an incident or event that isn't covered by our normal screens, we can throw a web page up there until it is resolved, then close it manually afterwards (unless somebody knows how to catch the PID of a specific Chrome instance, which I very much doubt, so that it can be terminated somehow)
Any hints on how I could do this?

Ok, so here is what I have done to make this work. I have created server end scripts that check a folder for 2 specific files, and once it sees them it sends that data to the main script that is expecting a monitor number and a URL. Hope somebody finds this useful.
You will need to go and download the original Chrome-Kiosk from https://alextomin.wordpress.com/2015/04/10/kiosk-mode-in-windows-chrome-on-multiple-displays/
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)
# 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
CLIENT SIDE
menu.PS1 - If you are wanting to push a specific screen to the display computer over the network then setup Network Path, but if you are connected to the local PC then Local Path is the one to setup. As long as looper is able to see the folder then it will work. There is a little logic in the menu so that the script wont execute if you close the window without putting in any details. (if you run launcher with no parameters it still executes chrome and sends it to a screen that is out of the array normally number 2 for some reason)
#################Local Path###################
Set-Location -Path c:\scripts\ICVT
#################Network Path#################
#Set-Location -Path \\somecomputer\c$\scripts\ICVT
function button ($title,$mailbx, $WF, $TF) {
###################Load Assembly for creating form & button######
[void][System.Reflection.Assembly]::LoadWithPartialName( “System.Windows.Forms”)
[void][System.Reflection.Assembly]::LoadWithPartialName( “Microsoft.VisualBasic”)
#####Define the form size & placement
$form = New-Object “System.Windows.Forms.Form”;
$form.Width = 500;
$form.Height = 150;
$form.Text = $title;
$form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen;
##############Define text label1
$textLabel1 = New-Object “System.Windows.Forms.Label”;
$textLabel1.Left = 25;
$textLabel1.Top = 15;
$textLabel1.Text = $mailbx;
##############Define text label2
$textLabel2 = New-Object “System.Windows.Forms.Label”;
$textLabel2.Left = 25;
$textLabel2.Top = 50;
$textLabel2.Text = $WF;
##############Define text label3
#$textLabel3 = New-Object “System.Windows.Forms.Label”;
#$textLabel3.Left = 25;
#$textLabel3.Top = 85;
#$textLabel3.Text = $TF;
############Define text box1 for input
$textBox1 = New-Object “System.Windows.Forms.TextBox”;
$textBox1.Left = 150;
$textBox1.Top = 10;
$textBox1.width = 200;
############Define text box2 for input
$textBox2 = New-Object “System.Windows.Forms.TextBox”;
$textBox2.Left = 150;
$textBox2.Top = 50;
$textBox2.width = 200;
############Define text box3 for input
#$textBox3 = New-Object “System.Windows.Forms.TextBox”;
#$textBox3.Left = 150;
#$textBox3.Top = 90;
#$textBox3.width = 200;
#############Define default values for the input boxes
$defaultValue = “”
$textBox1.Text = $defaultValue;
$textBox2.Text = $defaultValue;
#$textBox3.Text = $defaultValue;
#############define OK button
$button = New-Object “System.Windows.Forms.Button”;
$button.Left = 360;
$button.Top = 85;
$button.Width = 100;
$button.Text = “Ok”;
############# This is when you have to close the form after getting values
$eventHandler = [System.EventHandler]{
$textBox1.Text;
$textBox2.Text;
#$textBox3.Text;
$form.Close();};
$button.Add_Click($eventHandler) ;
#############Add controls to all the above objects defined
$form.Controls.Add($button);
$form.Controls.Add($textLabel1);
$form.Controls.Add($textLabel2);
$form.Controls.Add($textLabel3);
$form.Controls.Add($textBox1);
$form.Controls.Add($textBox2);
$form.Controls.Add($textBox3);
$ret = $form.ShowDialog();
#################return values
return $textBox1.Text, $textBox2.Text#, $textBox3.Text
}
$return= button “Monitoring Screen Selector” “Enter URL” “Enter Screen # from 1 to 11” #“Target Folder”
if ($return[0] -ne "") {
$return[0] > web.txt
}
if ($return[0] -eq "") {
exit
}
if ($return[1] -ne "") {
$return[1] > mon.txt
}
if ($return[0] -eq "") {
exit
}

Related

Can PowerShell be an ActiveScriptEventConsumer?

I need to continuously watch a particular "drop" folder for (tiny) pdfs and auto-print and delete them. The printing itself is being handled by SumatraPDF (because I don't think there is a built-in, Windows method).
Creating a temporary WMI event monitor in PowerShell is pretty straightforward:
$WQLquery = "SELECT * FROM __InstanceCreationEvent WITHIN 5 " +
"WHERE TargetInstance ISA 'CIM_DataFile' " +
"AND TargetInstance.Extension = 'pdf' " +
"AND TargetInstance.Drive = '$($Drive):' " +
"AND TargetInstance.Path = '$($Folder.replace('\','\\'))'"
$Action = {
$TimedOut = $null
$PrintProcess = Start-Process -FilePath $Sumatra -ArgumentList "-Print-To $Printer `"$($EventArgs.NewEvent.TargetInstance.Name)`"" -PassThru
$PrintProcess | Wait-Process -Timeout 10 -ErrorAction SilentlyContinue -ErrorVariable TimedOut
if ($TimedOut) {
"Printing $($EventArgs.NewEvent.TargetInstance.Name) timed out." | Out-File $ErrorLogPath -Append
$PrintProcess.kill
} elseif ($PrintProcess.ExitCode -ne 0) {
"Error for $($EventArgs.NewEvent.TargetInstance.Name) : $($PrintProcess.ExitCode)" | Out-File $ErrorLogPath -Append
} else {
Remove-Item $EventArgs.NewEvent.TargetInstance.Name -Force
}
}
Register-CimIndicationEvent -Query $wqlquery -SourceIdentifier 'FileCreated' -Action $Action
When it comes to creating a permanent event subscription, I can replace the Action and Register-CimIndicationEvent with:
# This creates a permanent event monitor that lasts through a reboot
# Step One: Create a Filter object
$FilterArgs = #{
ClassName = '__EventFilter'
NameSpace = 'root\subscription'
Computername = $env:COMPUTERNAME
ErrorAction = 'Stop'
Property = #{
Name = 'PDFCreatedFilter'
EventNamespace = 'root\CIMV2'
QueryLanguage = 'WQL'
Query = $WQLQuery
}
}
$FilterInstance = New-CimInstance #FilterArgs
# Step Two: Create a Consumer object
$ConsumerArgs = #{
ClassName = 'ActiveScriptEventConsumer'
NameSpace = 'root\subscription'
Computername = $env:COMPUTERNAME
ErrorAction = 'Stop'
Property = #{
Name = 'FileCreatedConsumer'
EventNamespace = 'root\CIMV2'
ScriptingEngine = '' # <---- What goes here for PowerShell?
ScriptFileName = '' # <---- What goes here for PowerShell?
}
}
$ConsumerInstance = New-CimInstance #ConsumerArgs
# Step Three: Create a Binding object between the Filter and Consumer
$BindingArgs = #{
ClassName = '__FilterToConsumerBinding'
NameSpace = 'root\subscription'
Computername = $env:COMPUTERNAME
ErrorAction = 'Stop'
Property = #{
Filter = [Ref]$FilterArgs
Consumer = [Ref]$ConsumerArgs
}
}
$BindingInstance = New-CimInstance #BindingArgs
However, and you can see, I am unsure about the ActiveScriptEventConsumer. Microsoft's documentation says it can be "in an arbitrary scripting language", but every example I can find uses VBScript only. I'd really like to use PowerShell.
Is PowerShell a valid Scripting Engine?
If yes, can someone provide the syntax for the ScriptingEngine and ScriptText properties to get it to work?
If no, am I better off hacking together some noob VBScript (yuck!) or using an CommandLineEventConsumer to start a PowerShell script (that I then have to watch/protect)?
Thanks!

Disk Storage alert email - Powershell

Script originally created by GhillieHammer
I've added additional features to work for me.
# $drives = #("D","E","F");
$drives = $null
# The minimum disk size to check for raising the warning
$minSize = 20GB
$MathminSize = [math]::round($minSize/1GB,2)
$minString = ($MathminSize).ToString()
$minString = $minString + "GB"
$email_to_addressArray = #("");
# $email_to_addressArray = #("toSingle#company.com")
#Set a couple needed variables
$SendIt = $Null
$ThisHost = $env:computername
$IPAddy = Invoke-RestMethod -Uri ('http://ipinfo.io/'+(Invoke-WebRequest -uri "http://ifconfig.me/ip").Content) | Select ip
#Check for $Drives query mode and make an array of them
if ($drives -eq $null -Or $drives -lt 1) {
$localVolumes = Get-WmiObject win32_volume;
$drives = #();
foreach ($vol in $localVolumes) {
if ($vol.DriveType -eq 3 -And $vol.DriveLetter -ne $null ) {
$drives += $vol.DriveLetter[0];
}
}
}
# Enumerate through the array of drives
# check to see if any are below minimum
# if so, set a flag saying as much and then
# add them and their information to the array we'll be adding to the email
foreach ($d in $drives) {
$disk = Get-PSDrive $d;
$MathDiskFree = [math]::round($disk.Free/1GB,2)
$MathDiskUsed = [math]::round($disk.Used/1GB,2)
$MathDisktotal = [math]::round($MathDiskFree + $MathDiskUsed)
$MathDiskPerc = ($MathDiskFree / $MathDiskUsed).tostring("P")
if ($disk.Free -lt $minSize) {
$SendIt = 1
$space += ("Free space on drive " + $d + " = " + $MathDiskFree + "GB. This is equal to only " + $MathDiskPerc + " of the " + $MathDisktotal + "GB total space available on this drive.<br>")
}
}
# Check the flag to see if it's set, meaning there's at least one drive below minimum free space, and if so, fire off the email(s)
If ($SendIt -eq 1) {
# Enumerate through the array of email addresses and fire off a formatted email to each
foreach ($toAddress in $email_to_addressArray) {
$User = "diskspace#"
$File = (Get-Content C:\Temp\pw.txt | ConvertTo-SecureString)
$MyCredential = New-Object -TypeName System.Management.Automation.PSCredential `
-ArgumentList $User, $File
$To = $toAddress
$from = ""
$EmailSubject = "WARNING: one or more disk on $ThisHost low on space"
$smtp = "auth.smtp.1and1.co.uk"
$DefaultMessage="
<p>Dear colleague,</p>
<p>There is a hard drive space issue on $ThisHost IPv4: $IPAddy </p>
<p>$space<br></p>
<p>This message only fires off if one or more disks have less than $minString GB of free space left.</p>
<p>Sincerely,<br>
Robot Monitor.<br><br>
</p>"
$MailMessage = #{
To = $To
From = $from
# BCC = $Bcc
Subject = $EmailSubject
Body = $DefaultMessage
priority = "High"
Smtpserver = $smtp
Credential = $MyCredential
ErrorAction = "SilentlyContinue"
}
Send-MailMessage #MailMessage -bodyashtml
}
}
The script works perfectly but can't seem to get it stop generating the following information
Can't seem to find or understand how it's generating additional lines of text. Any insight would be greatly appreciated!
Try using a more simplified code like the one below. I use this with a scheduled task on the machines I need it on. It only sends on email if disk space gets below threshold. You could modify it to work with the other drives you have. It's not really clear how you are getting multiple line output but modifying it would help resolve your problem and simplify your code.
$minGbThreshold = 10;
$computers = $env:COMPUTERNAME;
$smtpAddress = "smtp.yourdomain.com";
$toAddress = "anyone#gmail.com";
$fromAddress = "someone#gmail.com";
foreach($computer in $computers)
{
$disks = Get-WmiObject -ComputerName $computer -Class Win32_LogicalDisk -Filter "DriveType = 3";
$computer = $computer.toupper();
$deviceID = $disk.DeviceID;
foreach($disk in $disks)
{
$freeSpaceGB = [Math]::Round([float]$disk.FreeSpace / 1073741824, 2);
if($freeSpaceGB -lt $minGbThreshold)
{
$smtp = New-Object Net.Mail.SmtpClient($smtpAddress)
$msg = New-Object Net.Mail.MailMessage
$msg.To.Add($toAddress)
$msg.From = $fromAddress
$msg.Subject = “Diskspace below threshold ” + $computer + "\" + $disk.DeviceId
$msg.Body = $computer + "\" + $disk.DeviceId + " " + $freeSpaceGB + "GB Remaining";
$smtp.Send($msg)
}
}
}

PowerShell script to open four different Windows Explorer paths and position each window

I am trying to write a script that opens up Windows Explorer four times (each window with a different path) and positions each window in a corner of the screen so that they cover equal areas. The script will be used on machines with different screen resolutions so ideally it should be based on window size, but this isn't an absolute must, just as long as they're not overlapping (I think the min screen resolution it will be used on is 1366x768).
I am new to PowerShell scripting so I've managed to get some things working, I'm just struggling to fit it all together. I was able to get four separate Windows Explorer windows to open where I wanted:
ii $path1
ii $path2
ii $path3
ii $path4
I was also able to open Internet Explorer to a set size using -ComObject:
$IE = New-Object -ComObject Internetexplorer.application
$IE.Left = 0
$IE.Width = 500
$IE.Top = 0
$IE.Height = 500
$IE.Navigate($URL)
$IE.Visible = $True
I can't get it to work with Windows Explorer though. I've also managed to get the resolution for the monitor:
$monitor = Get-Wmiobject Win32_Videocontroller
$monitor.CurrentHorizontalResolution
$monitor.CurrentVerticalResolution
Unfortunately this provides 2 resolutions because I have two monitors, and I'm not sure how to extract the resolution for just one of them. Additionally, I don't know what that would mean if the script was run on a machine with only one monitor.
So with what I currently have, I would specifically like to know:
How to open my Windows Explorer windows to a certain size and position as I have done with IE (doesn't have to be with ii either, anything that works)
How to extract a single value for monitor resolution that I can do some maths with to get the optimum sizing.
Thanks.
EDIT: I have found a quick-fix but it's not quite there. By examining the commands available to me with the shell, and came up with this:
$Shell = New-Object -ComObject Shell.Application
ii $path1
ii $path2
ii $path3
ii $path4
$Shell.TileHorizontally()
This should work, because it's likely that the user will have only these four windows open and nothing else. Unfortunately, TileHorizontally()works on all open windows, but it looks like the ii commands don't execute fast enough or something, because they don't tile when the script is run. They do if you run it a second time, once the script is already open. I thought that the -Wait option would help me here, but it doesn't seem to work with ii. Anyone see a solution to this?
EDIT 2: My current code, using Set-Window with doc comments removed:
Function Set-Window {
[OutputType('System.Automation.WindowInfo')]
[cmdletbinding()]
Param (
[parameter(ValueFromPipelineByPropertyName=$True)]
$ProcessId,
[int]$X,
[int]$Y,
[int]$Width,
[int]$Height,
[switch]$Passthru
)
Begin {
Try{
[void][Window]
} Catch {
Add-Type #"
using System;
using System.Runtime.InteropServices;
public class Window {
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("User32.dll")]
public extern static bool MoveWindow(IntPtr handle, int x, int y, int width, int height, bool redraw);
}
public struct RECT
{
public int Left; // x position of upper-left corner
public int Top; // y position of upper-left corner
public int Right; // x position of lower-right corner
public int Bottom; // y position of lower-right corner
}
"#
}
}
Process {
$Rectangle = New-Object RECT
$Handle = (Get-Process -Id $ProcessId).MainWindowHandle
$Return = [Window]::GetWindowRect($Handle,[ref]$Rectangle)
If (-NOT $PSBoundParameters.ContainsKey('Width')) {
$Width = $Rectangle.Right - $Rectangle.Left
}
If (-NOT $PSBoundParameters.ContainsKey('Height')) {
$Height = $Rectangle.Bottom - $Rectangle.Top
}
If ($Return) {
$Return = [Window]::MoveWindow($Handle, $x, $y, $Width, $Height,$True)
}
If ($PSBoundParameters.ContainsKey('Passthru')) {
$Rectangle = New-Object RECT
$Return = [Window]::GetWindowRect($Handle,[ref]$Rectangle)
If ($Return) {
$Height = $Rectangle.Bottom - $Rectangle.Top
$Width = $Rectangle.Right - $Rectangle.Left
$Size = New-Object System.Management.Automation.Host.Size -ArgumentList $Width, $Height
$TopLeft = New-Object System.Management.Automation.Host.Coordinates -ArgumentList $Rectangle.Left, $Rectangle.Top
$BottomRight = New-Object System.Management.Automation.Host.Coordinates -ArgumentList $Rectangle.Right, $Rectangle.Bottom
If ($Rectangle.Top -lt 0 -AND $Rectangle.Left -lt 0) {
Write-Warning "Window is minimized! Coordinates will not be accurate."
}
$Object = [pscustomobject]#{
Id = $ProcessId
Size = $Size
TopLeft = $TopLeft
BottomRight = $BottomRight
}
$Object.PSTypeNames.insert(0,'System.Automation.WindowInfo')
$Object
}
}
}
}
Get-Process -Id (Start-Process -FilePath C:\windows\explorer.exe -ArgumentList "." -Wait -Passthru).Id | Set-Window -X 500 -Y 500 -Height 500 -Width 500 -Passthru

Background job to refresh data on a form while script is running?

Hope some brave will help me !
I’m working from a few days now on a Powershell tool that display a dashboard on the screen corner to give some network “real-time” diagnostics of the computer. This dashboard can be minimized in the notification area.
First, I created a function that get the diagnostics and display the status on the form. I tried to refresh data with a timer (See: Real Time Data With Powershell GUI).
The problem was that my function took too much time to be executed and it froze the interface. So buttons on the form were no more usable… (See: Mouse event don't work after first timer Tick ).
Now, I try to use background jobs. My idea is to launch a job in a loop mode and get his status on a timer interval.
First, the Job couldn’t call a function declared in my main script (line 361). I know that I can use global and/or don’t use a function but write the code directly on the ScriptBlock but… even with this, I don’t know how to let the job turning in a loop and get his status by interval (line 368)…
You can see that I’m not really experimented in PowerShell and GUI… It’s been a while since I have developed and it was in another language…
Thank you in advance for your kind help
If you want to run it, I’ve uploaded the images folder here:
https://omerta.is/2A1L
Here is my code below
####################################### FUNCTIONS ########################################
#Get diagnostics status
function GetStatus
{
#Create a return table
[hashtable]$Return = #{}
###Test LAN adapter###
$EthernetAdapter = (Get-WMIObject Win32_NetworkAdapter | Select Name, NetConnectionStatus | Where Name -like "*Gigabit*")
If ($EthernetAdapter -ne $null)
{
If ($EthernetAdapter.NetConnectionStatus -eq 2)
{$Return.LANOnStatus = $True}
else
{$Return.LANOnStatus = $False}
}
else
{
$Return.LANOnStatus = $False
}
###Test Wi-Fi adapter###
$WiFiAdapter = (Get-WMIObject Win32_NetworkAdapter | Select Name, NetConnectionStatus | Where Name -like "*Wireless*")
If ($WiFiAdapter -ne $null)
{
If ($WiFiAdapter.NetConnectionStatus -eq 2)
{$Return.WiFiOnStatus = $True}
else
{$Return.WiFiOnStatus = $False}
}
else
{
$Return.WiFiOnStatus = $False
}
###Test Network (Default Gateway Reachable)###
$DefaultGateway = (Get-WmiObject -Class Win32_IP4RouteTable | where { $_.destination -eq '0.0.0.0' -and $_.mask -eq '0.0.0.0'} | Sort-Object metric1 | select nexthop, metric1, interfaceindex).nexthop
If ($DefaultGateway -ne $null)
{
If (Test-Connection -ComputerName $DefaultGateway -Count 1 -TTL 4 -Quiet)
{$Return.NetworkStatus = $True}
else
{$Return.NetworkStatus = $False}
}
else
{
$Return.NetworkStatus = $False
}
#Test Internet connection
$GoogleWebSite = "www.google.com"
Try
{$Return.GoogleStatus = Test-Connection -ComputerName $GoogleWebSite -Count 1 -TTL 64 -Quiet}
Catch
{$Return.GoogleStatus = $False}
###DontReplyToo###
$DontReplyTooWebSite = "mdm.pictet.com"
Try
{$Return.DontReplyTooStatus = Test-Connection -ComputerName $DontReplyTooWebSite -Count 1 -TTL 64 -Quiet}
Catch
{$Return.DontReplyTooStatus = $False}
###DONT REPLY###
$DontReplyWebsite = "www.idontreply.com"
Try
{$Return.DontReplyStatus = Test-Connection -ComputerName $DontReplyWebsite -Count 1 -TTL 64 -Quiet}
Catch
{$Return.DontReplyStatus = $False}
#Return the table
Return $Return
}
########################################### EVENTS ###########################################
#Manual Synchronization
function ManualSync
{
Sync-Content
}
#Open Browser from dashboard
function Open-Browser
{
&($BrowserExe)
}
#Open a help message on click on help icon
function Open-Help($HelpText)
{
[System.Windows.Forms.MessageBox]::Show($HelpText,"Hotlines",0,32)
}
#Close Dashboard form on click on minimize icon
function Minimize-Dashboard
{
#Close Dashboard on click minimize
$Form.WindowState = "Minimize"
$Form.Visible = $False
$objNotifyIcon.Visible = $True
#!!!!! TO CHECK !!!!!
Wait-Event -Timeout 15 -SourceIdentifier NotifyIcon_Event
Remove-Event -SourceIdentifier NotifyIcon_Event
}
#Open Dashboard form on double click on agent icon in notification area
function OpenDashboard
{
#Open Dashboard on double-click
$Form.Visible = $True
$Form.WindowState = "Normal"
}
######################################### ASSEMBLIES #########################################
[void] [Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Timers")
[void] [System.Windows.Forms.Application]::EnableVisualStyles()
######################################### VAR & CONST ########################################
#Screen placement
$Screen = [system.windows.forms.screen]::PrimaryScreen
$FormPos = $Screen.Bounds.Width - 160
#Dashboard Timer
$Timer = New-Object 'System.Windows.Forms.Timer'
$Timer.Interval = 3000
#Home directory of the program
$HomeDir = Split-Path $script:MyInvocation.MyCommand.Path
#Dashboard Images
$Background = [system.drawing.image]::FromFile("$HomeDir\img\interface.png")
$GreenLight = [system.drawing.image]::FromFile("$HomeDir\img\greenlight.png")
$RedLight = [system.drawing.image]::FromFile("$HomeDir\img\redlight.png")
$SyncImg = [system.drawing.image]::FromFile("$HomeDir\img\sync.png")
$BrowserImg = [system.drawing.image]::FromFile("$HomeDir\img\browser.png")
$HelpImg = [system.drawing.image]::FromFile("$HomeDir\img\help.png")
$MinimizeImg = [system.drawing.image]::FromFile("$HomeDir\img\minimize.png")
#Agent Images
$IconStd = New-Object system.drawing.icon ("$HomeDir\img\icon.ico")
$IconFocus = New-Object system.drawing.icon ("$HomeDir\img\icon_focus.ico")
#Log files
$LogLastSync = ("$HomeDir\Logs\LastSync.log")
$LogSyncAgent = ("$HomeDir\Logs\SyncAgentError.log")
#Browser Module
$BrowserExe = "$HomeDir\bin\Browser.exe"
#Free File Sync Module
$SyncAgentExe = "$HomeDir\bin\SyncAgent.exe"
$SyncJob = "$HomeDir\bin\SyncSettings.xml"
#Strings
$HelpText = "Hotline: 432423432423423"
########################################### FORMS ###########################################
#Dashboard Windows Forms
$Form = New-Object System.Windows.Forms.Form
$Font = New-Object System.Drawing.Font("Arial Unicode MS",10,[System.Drawing.FontStyle]::Bold)
$Lb_LANOn = New-Object System.Windows.Forms.Label
$Lb_WiFiOn = New-Object System.Windows.Forms.Label
$Lb_Network = New-Object System.Windows.Forms.Label
$Lb_Google = New-Object System.Windows.Forms.Label
$Lb_DontReplyToo = New-Object System.Windows.Forms.Label
$Lb_DontReply = New-Object System.Windows.Forms.Label
$Pb_LANOn = New-Object System.Windows.Forms.PictureBox
$Pb_WiFiOn = New-Object System.Windows.Forms.PictureBox
$Pb_Network = New-Object System.Windows.Forms.PictureBox
$Pb_Google = New-Object System.Windows.Forms.PictureBox
$Pb_DontReplyToo = New-Object System.Windows.Forms.PictureBox
$Pb_DontReply = New-Object System.Windows.Forms.PictureBox
$Pb_Sync = New-Object System.Windows.Forms.PictureBox
$Pb_Browser = New-Object System.Windows.Forms.PictureBox
$Pb_Help = New-Object System.Windows.Forms.PictureBox
$Pb_Minimize = New-Object System.Windows.Forms.PictureBox
#Agent Windows Form
$objNotifyIcon = New-Object System.Windows.Forms.NotifyIcon
$objNotifyIcon.Add_Click({OpenDashboard})
Register-ObjectEvent $objNotifyIcon Click NotifyIcon_Event
#Dashboard Interface Generation
$Form.Size = '150, 220'
$Form.FormBorderStyle = 'None'
$Form.Name = "Form"
$Form.StartPosition = 'Manual'
$Form.Location = $FormPos.ToString()+', 10'
$Form.Text = "Dashboard"
$Form.Font = $Font
$Form.BackgroundImage = $Background
$Form.BackgroundImageLayout = "None"
$Form.TransparencyKey = "White"
$Form.BackColor = "White"
#$Form.Opacity = '.85'
$Form.Controls.Add($Lb_LANOn)
$Lb_LANOn.Location = '10, 30'
$Lb_LANOn.Size = '75, 20'
$Lb_LANOn.Text = "LAN On"
$Lb_LANOn.ForeColor = 'Gray'
$Lb_LANOn.BackColor = "Transparent"
$Form.Controls.Add($Lb_WiFiOn)
$Lb_WiFiOn.Location = '10, 55'
$Lb_WiFiOn.Size = '75, 20'
$Lb_WiFiOn.Text = "Wi-Fi On"
$Lb_WiFiOn.ForeColor = 'Gray'
$Lb_WiFiOn.BackColor = "Transparent"
$Form.Controls.Add($Lb_Network)
$Lb_Network.Location = '10, 80'
$Lb_Network.Size = '75, 20'
$Lb_Network.Text = "Network"
$Lb_Network.ForeColor = 'Gray'
$Lb_Network.BackColor = "Transparent"
$Form.Controls.Add($Lb_Google)
$Lb_Google.Location = '10, 105'
$Lb_Google.Size = '75, 20'
$Lb_Google.Text = "Google"
$Lb_Google.ForeColor = 'Gray'
$Lb_Google.BackColor = "Transparent"
$Form.Controls.Add($Lb_DontReplyToo)
$Lb_DontReplyToo.Location = '10, 130'
$Lb_DontReplyToo.Size = '75, 20'
$Lb_DontReplyToo.Text = "DontReplyToo"
$Lb_DontReplyToo.ForeColor = 'Gray'
$Lb_DontReplyToo.BackColor = "Transparent"
$Form.Controls.Add($Lb_DontReply)
$Lb_DontReply.Location = '10, 155'
$Lb_DontReply.Size = '75, 20'
$Lb_DontReply.Text = "Dont Reply"
$Lb_DontReply.ForeColor = 'Gray'
$Lb_DontReply.BackColor = "Transparent"
$Form.Controls.Add($Pb_LANOn)
$Pb_LANOn.Location = '115, 33'
$Pb_LANOn.Size = '15, 15'
$Pb_LANOn.Image = $RedLight
$Pb_LANOn.BackColor = "Transparent"
$Form.Controls.Add($Pb_WiFiOn)
$Pb_WiFiOn.Location = '115, 58'
$Pb_WiFiOn.Size = '15, 15'
$Pb_WiFiOn.Image = $RedLight
$Pb_WiFiOn.BackColor = "Transparent"
$Form.Controls.Add($Pb_Network)
$Pb_Network.Location = '115, 83'
$Pb_Network.Size = '15, 15'
$Pb_Network.Image = $RedLight
$Pb_Network.BackColor = "Transparent"
$Form.Controls.Add($Pb_Google)
$Pb_Google.Location = '115, 108'
$Pb_Google.Size = '15, 15'
$Pb_Google.Image = $RedLight
$Pb_Google.BackColor = "Transparent"
$Form.Controls.Add($Pb_DontReplyToo)
$Pb_DontReplyToo.Location = '115, 133'
$Pb_DontReplyToo.Size = '15, 15'
$Pb_DontReplyToo.Image = $RedLight
$Pb_DontReplyToo.BackColor = "Transparent"
$Form.Controls.Add($Pb_DontReply)
$Pb_DontReply.Location = '115, 158'
$Pb_DontReply.Size = '15, 15'
$Pb_DontReply.Image = $RedLight
$Pb_DontReply.BackColor = "Transparent"
#Toolbar
$Form.Controls.Add($Pb_Sync)
$Pb_Sync.Location = '20, 195'
$Pb_Sync.Size = '20, 20'
$Pb_Sync.Image = $SyncImg
$Pb_Sync.BackColor = "Transparent"
$Pb_Sync.Add_Click({Sync-Content})
$Form.Controls.Add($Pb_Browser)
$Pb_Browser.Location = '51, 195'
$Pb_Browser.Size = '20, 20'
$Pb_Browser.Image = $BrowserImg
$Pb_Browser.BackColor = "Transparent"
$Pb_Browser.Add_Click({Open-Browser})
$Form.Controls.Add($Pb_Help)
$Pb_Help.Location = '82, 195'
$Pb_Help.Size = '20, 20'
$Pb_Help.Image = $HelpImg
$Pb_Help.BackColor = "Transparent"
$Pb_Help.Add_Click({Open-Help($HelpText)})
$Form.Controls.Add($Pb_Minimize)
$Pb_Minimize.Location = '113, 195'
$Pb_Minimize.Size = '20, 20'
$Pb_Minimize.Image = $MinimizeImg
$Pb_Minimize.BackColor = "Transparent"
$Pb_Minimize.Add_Click({Minimize-Dashboard})
########## MAIN
#Status Init
#$Status = GetStatus
#Create the Status Background Job
Start-Job -Name "jobGetStatus" -ScriptBlock {$Status = GetStatus} #function not recognized by Background Job
#Wait for job result
While (Get-Job -Name "jobGetStatus" | where { $_.State -eq "Running" })
{Start-Sleep 1}
#Get Status on Timer Tick
$Timer.Add_Tick({Get-Job -Name "jobGetStatus" | Receive-Job}) #job not updated
#Display new status on tick
$Timer.Add_Tick({
#LAN
If ($Status.LANOnStatus -eq $True)
{$Pb_LANOn.Image = $GreenLight}
else
{$Pb_LANOn.Image = $RedLight}
#WIFI
If ($Status.WiFiOnStatus -eq $True)
{$Pb_WiFiOn.Image = $GreenLight}
else
{$Pb_WiFiOn.Image = $RedLight}
#NETWORK
If ($Status.NetworkStatus -eq $True)
{$Pb_Network.Image = $GreenLight}
else
{$Pb_Network.Image = $RedLight}
#GOOGLE
If ($Status.GoogleStatus -eq $True)
{$Pb_Google.Image = $GreenLight}
else
{$Pb_Google.Image = $RedLight}
#DontReplyToo
If ($Status.DontReplyTooStatus -eq $True)
{$Pb_DontReplyToo.Image = $GreenLight}
else
{$Pb_DontReplyToo.Image = $RedLight}
#BING
If ($Status.DontReplyStatus -eq $True)
{$Pb_DontReply.Image = $GreenLight}
else
{$Pb_DontReply.Image = $RedLight}
})
#Start Timer
$Timer.Enabled = $True
#Agent Init
$objNotifyIcon.Icon = $IconStd
$objNotifyIcon.Text = "Dashboard"
$objNotifyIcon.Visible = $True
#Show Interface
$Form.ShowDialog()
############## END
Nice little utility.
I removed all references to the Job, and added the code from the job into the Tick itself:
$Timer.Add_Tick({
$Status = GetStatus
#LAN
If ($Status.LANOnStatus -eq $True)
{$Pb_LANOn.Image = $GreenLight}
else
{$Pb_LANOn.Image = $RedLight}
...
})
Since you mentioned the function took too much time, I also increased the Tick interval from 3 to 10 seconds. This seems to work fine on my PC.

How to build a CD ISO image file from the windows command line?

In an effort to satisfy "The Joel Test" question #2 "Can you make a build in one step?", I'm trying to complete a release candidate build script with the creation of a CD iso from the collection of files gathered and generated by the installer creator.
There seem to be many good tools (many free) out there that will create ISOs, but I need to find one that can be run at the windows command line so I can integrate it into the NAnt build script that's fired off by Cruise Control.
Build environment is:
Windows Server 2003
.NET 1.1 - 3.5 (application we're creating is built on 2.0)
NullSoft installer (NSIS)
CruiseControl.net
NAnt
I've been googling around, but no luck yet.
Anyone have a recommendation?
Try mkisofs. It's part of the cdrecord project.
Creating a simple CD ISO
I've found a significantly easier approach, and it doesn't require Cygwin: CDBurnerXP
It's not really advertised on the site, but it includes a command-line edition, as cdbxpcmd.exe. There is also some documentation about the command-line options.
Of particular interest are the -iso and -format options; used something like:
cdbxpcmd --burn-data -folder:input -iso:output.iso -format:iso -changefiledates
to generate an ISO called output.iso from the files in the input folder
Creating a Bootable ISO
The command line tool doesn't appear to let you make a bootable CD directly. However, if you know your list of files isn't going to change (ie only the content of those files), you could try the following (untested):
Load up the CDBurnerXP GUI version
Add the files interactively
Select Disc->Burn Options...
Set up your boot image
Select File->Save to create a DXP file (which is CDBurnerXP's compilation format)
Then, you can use the following command
cdbxpcmd --burn-data -layout:mycompilation.dxp -iso:output.iso -format:iso
Blatant plug, but I've just released an alpha version of an OpenSource C# library that can create ISO files. Doesn't directly integrate with Nant, but you could wrap up the library to achieve that. Theres a sample app (ISOCreate) that creates ISOs from a directory structure, but this sample could also get you started:
CDBuilder builder = new CDBuilder();
builder.UseJoliet = true;
builder.VolumeIdentifier = "A_SAMPLE_DISK";
builder.AddFile(#"Folder\Hello.txt", Encoding.ASCII.GetBytes("Hello World!"));
builder.Build(#"C:\temp\sample.iso");
.NET DiscUtils (on GitHub)
Get mkisofs here - it is part of cdrtools. Available for most platforms.
USAGE examples:
mkisofs -v -dvd-video -V "VOLUME_NAME" -o "c:\my movies\iso\movie.iso" "c:\my movies\dvd"
mkisofs -r -R -J -l -L -o image-file.iso c:\project\install
Powershell can create an ISO. The below example includes a GUI. Credit to http://blog.apps.id.au/?p=5321
# Author: Hrisan Dzhankardashliyski
# Date: 20/05/2015
# Inspiration from
#
# http://blogs.msdn.com/b/opticalstorage/archive/2010/08/13/writing-optical-discs-using-imapi-2-in-powershell.aspx</a>
#
# and
#
# http://tools.start-automating.com/Install-ExportISOCommand/</a>
#
# with help from
#
# http://stackoverflow.com/a/9802807/223837</a>
$InputFolder = ""
function WriteIStreamToFile([__ComObject] $istream, [string] $fileName)
{
# NOTE: We cannot use [System.Runtime.InteropServices.ComTypes.IStream],
# since PowerShell apparently cannot convert an IStream COM object to this
# Powershell type. (See http://stackoverflow.com/a/9037299/223837 for
# details.)
#
# It turns out that .NET/CLR _can_ do this conversion.
#
# That is the reason why method FileUtil.WriteIStreamToFile(), below,
# takes an object, and casts it to an IStream, instead of directly
# taking an IStream inputStream argument.
$cp = New-Object CodeDom.Compiler.CompilerParameters
$cp.CompilerOptions = "/unsafe"
$cp.WarningLevel = 4
$cp.TreatWarningsAsErrors = $true
Add-Type -CompilerParameters $cp -TypeDefinition #"
using System;
using System.IO;
using System.Runtime.InteropServices.ComTypes;
namespace My
{
public static class FileUtil {
public static void WriteIStreamToFile(object i, string fileName) {
IStream inputStream = i as IStream;
FileStream outputFileStream = File.OpenWrite(fileName);
int bytesRead = 0;
int offset = 0;
byte[] data;
do {
data = Read(inputStream, 2048, out bytesRead);
outputFileStream.Write(data, 0, bytesRead);
offset += bytesRead;
} while (bytesRead == 2048);
outputFileStream.Flush();
outputFileStream.Close();
}
unsafe static private byte[] Read(IStream stream, int toRead, out int read) {
byte[] buffer = new byte[toRead];
int bytesRead = 0;
int* ptr = &bytesRead;
stream.Read(buffer, toRead, (IntPtr)ptr);
read = bytesRead;
return buffer;
}
}
}
"#
[My.FileUtil]::WriteIStreamToFile($istream, $fileName)
}
# The Function defines the ISO parameturs and writes it to file
function createISO([string]$VolName,[string]$Folder,[bool]$IncludeRoot,[string]$ISOFile){
# Constants from http://msdn.microsoft.com/en-us/library/windows/desktop/aa364840.aspx
$FsiFileSystemISO9660 = 1
$FsiFileSystemJoliet = 2
$FsiFileSystemUDF = 4
$fsi = New-Object -ComObject IMAPI2FS.MsftFileSystemImage
#$fsi.FileSystemsToCreate = $FsiFileSystemISO9660 + $FsiFileSystemJoliet
$fsi.FileSystemsToCreate = $FsiFileSystemUDF
#When FreeMediaBlocks is set to 0 it allows the ISO file to be with unlimited size
$fsi.FreeMediaBlocks = 0
$fsi.VolumeName = $VolName
$fsi.Root.AddTree($Folder, $IncludeRoot)
WriteIStreamToFile $fsi.CreateResultImage().ImageStream $ISOFile
}
Function Get-Folder($initialDirectory)
{
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")
$foldername = New-Object System.Windows.Forms.FolderBrowserDialog
$foldername.rootfolder = "MyComputer"
if($foldername.ShowDialog() -eq "OK")
{
$folder += [string]$foldername.SelectedPath
}
return $folder
}
# Show an Open Folder Dialog and return the directory selected by the user.
function Read-FolderBrowserDialog([string]$Message, [string]$InitialDirectory, [switch]$NoNewFolderButton)
{
$browseForFolderOptions = 0
if ($NoNewFolderButton) { $browseForFolderOptions += 512 }
$app = New-Object -ComObject Shell.Application
$folder = $app.BrowseForFolder(0, $Message, $browseForFolderOptions, $InitialDirectory)
if ($folder) { $selectedDirectory = $folder.Self.Path }
else { $selectedDirectory = '' }
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($app) > $null
return $selectedDirectory
}
#Prompts the user to save the ISO file, if the files does not exists it will create it otherwise overwrite without prompt
Function Get-SaveFile($initialDirectory)
{
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") |
Out-Null
$SaveFileDialog = New-Object System.Windows.Forms.SaveFileDialog
$SaveFileDialog.CreatePrompt = $false
$SaveFileDialog.OverwritePrompt = $false
$SaveFileDialog.initialDirectory = $initialDirectory
$SaveFileDialog.filter = "ISO files (*.iso)| *.iso"
$SaveFileDialog.ShowHelp = $true
$SaveFileDialog.ShowDialog() | Out-Null
$SaveFileDialog.filename
}
# Show message box popup and return the button clicked by the user.
function Read-MessageBoxDialog([string]$Message, [string]$WindowTitle, [System.Windows.Forms.MessageBoxButtons]$Buttons = [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]$Icon = [System.Windows.Forms.MessageBoxIcon]::None)
{
Add-Type -AssemblyName System.Windows.Forms
return [System.Windows.Forms.MessageBox]::Show($Message, $WindowTitle, $Buttons, $Icon)
}
# GUI interface for the PowerShell script
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") #loading the necessary .net libraries (using void to suppress output)
$Form = New-Object System.Windows.Forms.Form #creating the form (this will be the "primary" window)
$Form.Text = "ISO Creator Tool:"
$Form.Size = New-Object System.Drawing.Size(600,300) #the size in px of the window length, height
$Form.FormBorderStyle = 'FixedDialog'
$Form.MaximizeBox = $false
$Form.MinimizeBox = $false
$objLabel = New-Object System.Windows.Forms.Label
$objLabel.Location = New-Object System.Drawing.Size(20,20)
$objLabel.Size = New-Object System.Drawing.Size(120,20)
$objLabel.Text = "Please select a Folder:"
$Form.Controls.Add($objLabel)
$InputBox = New-Object System.Windows.Forms.TextBox
$InputBox.Location = New-Object System.Drawing.Size(150,20)
$InputBox.Size = New-Object System.Drawing.Size(300,20)
$InputBox.Enabled = $false
$Form.Controls.Add($InputBox)
$objLabel2 = New-Object System.Windows.Forms.Label
$objLabel2.Location = New-Object System.Drawing.Size(20,80)
$objLabel2.Size = New-Object System.Drawing.Size(120,20)
$objLabel2.Text = "ISO File Name:"
$Form.Controls.Add($objLabel2)
$InputBox2 = New-Object System.Windows.Forms.TextBox
$InputBox2.Location = New-Object System.Drawing.Size(150,80)
$InputBox2.Size = New-Object System.Drawing.Size(300,20)
$InputBox2.Enabled = $false
$Form.Controls.Add($InputBox2)
$objLabel3 = New-Object System.Windows.Forms.Label
$objLabel3.Location = New-Object System.Drawing.Size(20,50)
$objLabel3.Size = New-Object System.Drawing.Size(120,20)
$objLabel3.Text = "ISO Volume Name:"
$Form.Controls.Add($objLabel3)
$InputBox3 = New-Object System.Windows.Forms.TextBox
$InputBox3.Location = New-Object System.Drawing.Size(150,50)
$InputBox3.Size = New-Object System.Drawing.Size(150,20)
$Form.Controls.Add($InputBox3)
$objLabel4 = New-Object System.Windows.Forms.Label
$objLabel4.Location = New-Object System.Drawing.Size(20,120)
$objLabel4.Size = New-Object System.Drawing.Size(120,20)
$objLabel4.Text = "Status Msg:"
$Form.Controls.Add($objLabel4)
$InputBox4 = New-Object System.Windows.Forms.TextBox
$InputBox4.Location = New-Object System.Drawing.Size(150,120)
$InputBox4.Size = New-Object System.Drawing.Size(200,20)
$InputBox4.Enabled = $false
$InputBox4.Text = "Set ISO Parameters..."
$InputBox4.BackColor = "LimeGreen"
$Form.Controls.Add($InputBox4)
$Button = New-Object System.Windows.Forms.Button
$Button.Location = New-Object System.Drawing.Size(470,20)
$Button.Size = New-Object System.Drawing.Size(80,20)
$Button.Text = "Browse"
$Button.Add_Click({
$InputBox.Text=Read-FolderBrowserDialog
$InputBox4.Text = "Set ISO Parameters..."
})
$Form.Controls.Add($Button)
$Button2 = New-Object System.Windows.Forms.Button
$Button2.Location = New-Object System.Drawing.Size(470,120)
$Button2.Size = New-Object System.Drawing.Size(80,80)
$Button2.Text = "CreateISO"
$Button2.Add_Click({
if(($InputBox.Text -eq "") -or ($InputBox3.Text -eq "")){
Read-MessageBoxDialog "You have to select folder and specify ISO Volume Name" "Error: No Parameters entered!"
} else{
$SaveDialog = Get-SaveFile
#If you click cancel when save file dialog is called
if ($SaveDialog -eq ""){
return
}
$InputBox2.Text= $SaveDialog
$InputBox2.Refresh()
if($checkBox1.Checked){
$includeRoot=$true
}
else{
$includeRoot=$false
}
$InputBox4.BackColor = "Red"
$InputBox4.Text = "Generating ISO File!"
$InputBox4.Refresh()
createISO $InputBox3.Text $InputBox.Text $includeRoot $InputBox2.Text
$InputBox4.BackColor = "LimeGreen"
$InputBox4.Text = "ISO Creation Finished!"
$InputBox4.Refresh()
}
})
$Form.Controls.Add($Button2)
$objLabel5 = New-Object System.Windows.Forms.Label
$objLabel5.Location = New-Object System.Drawing.Size(20,160)
$objLabel5.Size = New-Object System.Drawing.Size(280,20)
$objLabel5.Text = "Check the box if you want to include the top folder:"
$Form.Controls.Add($objLabel5)
$checkBox1 = New-Object System.Windows.Forms.CheckBox
$checkBox1.Location = New-Object System.Drawing.Size(300,156)
$Form.Controls.Add($checkBox1)
$Form.Add_Shown({$Form.Activate()})
[void] $Form.ShowDialog()
If you want to be Microsoft addictive (not install additional software). You can use IMAPI, build into Windows to burn images. Additional information regarding scripting IMAPI can be found in MSDN
I've used magiciso, but haven't tested it extensivly. (I may try some of the others mentioned here after some testing) I first make an installer (single file) then just make this an iso.
http://www.magiciso.com/
Here's the result of my struggle to get this working in python:
add_option = '-a'
add_option_value = installer_fullpath
response_option = '-py' # answer yes to all options
# Get the tempfile name -- to resolve long name issue
# --> My file names were initially too long for MagicIso and it would choke
f_handle = tempfile.TemporaryFile(suffix='.iso', prefix='mi_', dir='.')
temp_filename = f_handle.name
f_handle.close() # File automatically deleted on close
args = (magiciso_exe_fullpath,temp_filename,response_option,add_option,add_option_value)
# log output to file
magiciso_con_f = open(MAGICISO_CON_LOG,'w')
magiciso_process = subprocess.Popen(args,stdout=magiciso_con_f,stderr=magiciso_con_f)
magiciso_process.wait()
I am using mkisofs.exe from the installation kit of nLite or BartPE, from where I also learned the required parameters for building a bootable cd.

Resources