Synchronize folder/directory contents

Standard

It is often useful to be able to synchronize the contents of certain folders. Yesterday I needed a way to make sure that files in separate folders on some of my servers are kept up to date. I wrote the script in this post to help me accomplish that. Incidentally it also proved useful in syncing some private files between dropbox and google drive etc.. 🙂

How does the script work?

The basic idea of the script is to sync files from a source dir to a destination dir. Also, since I work with many large files I only want to copy them if there actually is a difference between the file versions in the source and destination dir. To do all this I came up with these logical steps.

1. Loop through all the files in the source dir.
2. If the file doesn’t exist in the destination dir then copy it.
3. If the file exists in the destination dir then calculate the MD5 hashes of both source and destination files and compare. If the hashes match then the files are identical and can be skipped. If not then copy the file.

The script itself

The comments I put in the code should explain how I built the script according to the logical steps above.

###############################################################################
##script:			Sync-Folders.ps1
##
##Description:		Syncs/copies contents of one dir to another. Uses MD5
#+					checksums to verify the version of the files and if they
#+					need to be synced.
##Created by:		Noam Wajnman
##Creation Date:	June 9, 2014
###############################################################################
#FUNCTIONS
function Get-FileMD5 {
    Param([string]$file)
	$md5 = [System.Security.Cryptography.HashAlgorithm]::Create("MD5")
	$IO = New-Object System.IO.FileStream($file, [System.IO.FileMode]::Open)
	$StringBuilder = New-Object System.Text.StringBuilder
	$md5.ComputeHash($IO) | % { [void] $StringBuilder.Append($_.ToString("x2")) }
	$hash = $StringBuilder.ToString() 
	$IO.Dispose()
	return $hash
}
#VARIABLES
$DebugPreference = "continue"
#parameters
$SRC_DIR = 'c:\sourcefolder\'
$DST_DIR = 'C:\destfolder\'
#SCRIPT MAIN
clear
$SourceFiles = GCI -Recurse $SRC_DIR | ? { $_.PSIsContainer -eq $false} #get the files in the source dir.
$SourceFiles | % { # loop through the source dir files
	$src = $_.FullName #current source dir file
	Write-Debug $src
	$dest = $src -replace $SRC_DIR.Replace('\','\\'),$DST_DIR #current destination dir file
	if (test-path $dest) { #if file exists in destination folder check MD5 hash
		$srcMD5 = Get-FileMD5 -file $src
		Write-Debug "Source file hash: $srcMD5"
		$destMD5 = Get-FileMD5 -file $dest
		Write-Debug "Destination file hash: $destMD5"
		if ($srcMD5 -eq $destMD5) { #if the MD5 hashes match then the files are the same
			Write-Debug "File hashes match. File already exists in destination folder and will be skipped."
			$cpy = $false
		}
		else { #if the MD5 hashes are different then copy the file and overwrite the older version in the destination dir
			$cpy = $true
			Write-Debug "File hashes don't match. File will be copied to destination folder."
		}
	}
	else { #if the file doesn't in the destination dir it will be copied.
		Write-Debug "File doesn't exist in destination folder and will be copied."
		$cpy = $true
	}
	Write-Debug "Copy is $cpy"
	if ($cpy -eq $true) { #copy the file if file version is newer or if it doesn't exist in the destination dir.
		Write-Debug "Copying $src to $dest"
		if (!(test-path $dest)) {
			New-Item -ItemType "File" -Path $dest -Force	
		}
		Copy-Item -Path $src -Destination $dest -Force
	}
}

How do I use/run the script?

First of all remember to enter the paths for your source and destination dirs/folders in the #parameters section of the script.
You can run the script manually and synchronize on a need to basis but I recommend using the windows task scheduler to run it regularly and keep your dirs synchronized at all times with minimal effort.
In order to configure a scheduled task which runs the script you can follow the below steps (for windows 2008 R2/windows 7).
1. Start the windows task scheduler.
2. Stand on “task scheduler library” and click “Create Basic Task”.
3. Give your task a name and a description.
Task_Name
4. In the next steps choose a schedule for the task and Click “Next” until you get to “action”.
Task_Action
5. Choose “Start a program” and click “Next”.
6. Under “Program/script:” simply write powershell. In the “Add arguments:” field write -command “& ‘c:\pathtoscript\sync-folders.ps1′”(change c:\pathtoscript\ to where your sync-folders.ps1 file is located). Click “Next”.
Task_StartAProgram
7. You should now see a summary of the task looking sort of like this.
Task_Summary
8. Click “Finish”.

That’s it! You’re done.

I hope you find the script useful. Good luck!

Advertisement

Powershell and .NET forms. Write your own GUI – File Checksum Tool

Standard

I often encapsulate my scripts in a small GUI after I write them. This makes the scripts much easier to use for other people as it provides a more intuitive way to give the input parameters and also interpret the results.
I am writing this post in order to showcase how you can easily create a small GUI and create a tool which you and your colleagues can use. As an examples I have chosen to create a simple tool which can compute the checksum of a file using a few of the most common hash algorithms out there.
When creating this GUI I used primalforms to help build it. Primalforms is a great free program which allows you to construct a .NET form complete with the needed objects and the layout that you want.

Creating the form using PrimalForms

PrimalFormsScreenDump
To create the file checksum tool I need two fields for input. One for the path of the file to check and the other to choose the hash algorithm used. For the file name field I decided to use an object of the type “TextBox” and for the algorithm field I chose a “ComboBox” which is a dropdown menu. To describe the fields I added some “Label” objects over the fields. To get the file path input I decided to add a “Button” object which I will later use to open a small window and allow users to browse and select files. I added a second button which will later be used to calculate the file checksum with the given inputs. Lastly I added a “RichTextBox” object which I will use to display the output (the computed hash string).
After placing the objects where I wanted them I populated the text properties of the objects with the strings I wanted e.g. “Select File:”, “Browse” etc. I then populated the “ComboBox” dropdown with list of choices for hash algorithms MD5, SHA1, SHA256 etc.
After this has been done the form is basically ready. Use the “Export Powershell” function in PrimalForms and copy the form code to your powershell editor. the exported code looks like this:

#Generated Form Function
function GenerateForm {
########################################################################
# Code Generated By: SAPIEN Technologies PrimalForms (Community Edition) v1.0.10.0
# Generated On: 5/7/2014 2:02 PM
# Generated By: noam wajnman
########################################################################

#region Import the Assemblies
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
#endregion

#region Generated Form Objects
$form1 = New-Object System.Windows.Forms.Form
$label3 = New-Object System.Windows.Forms.Label
$richTextBox1 = New-Object System.Windows.Forms.RichTextBox
$label2 = New-Object System.Windows.Forms.Label
$label1 = New-Object System.Windows.Forms.Label
$comboBox1 = New-Object System.Windows.Forms.ComboBox
$textBox1 = New-Object System.Windows.Forms.TextBox
$button2 = New-Object System.Windows.Forms.Button
$button1 = New-Object System.Windows.Forms.Button
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects

#----------------------------------------------
#Generated Event Script Blocks
#----------------------------------------------
#Provide Custom Code for events specified in PrimalForms.
$button1_OnClick= 
{
#TODO: Place custom script here

}

$button2_OnClick= 
{
#TODO: Place custom script here

}

$OnLoadForm_StateCorrection=
{#Correct the initial state of the form to prevent the .Net maximized form issue
	$form1.WindowState = $InitialFormWindowState
}

#----------------------------------------------
#region Generated Form Code
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 364
$System_Drawing_Size.Width = 430
$form1.ClientSize = $System_Drawing_Size
$form1.DataBindings.DefaultDataSourceUpdateMode = 0
$form1.Font = New-Object System.Drawing.Font("Arial",9.75,0,3,1)
$form1.Name = "form1"
$form1.Text = "File Checksum Tool"

$label3.DataBindings.DefaultDataSourceUpdateMode = 0
$label3.Font = New-Object System.Drawing.Font("Arial",8.25,0,3,1)

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 24
$System_Drawing_Point.Y = 330
$label3.Location = $System_Drawing_Point
$label3.Name = "label3"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 36
$System_Drawing_Size.Width = 202
$label3.Size = $System_Drawing_Size
$label3.TabIndex = 7
$label3.Text = "Created by Noam Wajnman May 2014. https://noamwajnman.wordpress.com"

$form1.Controls.Add($label3)

$richTextBox1.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 24
$System_Drawing_Point.Y = 199
$richTextBox1.Location = $System_Drawing_Point
$richTextBox1.Name = "richTextBox1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 107
$System_Drawing_Size.Width = 388
$richTextBox1.Size = $System_Drawing_Size
$richTextBox1.TabIndex = 6
$richTextBox1.Text = ''

$form1.Controls.Add($richTextBox1)

$label2.DataBindings.DefaultDataSourceUpdateMode = 0
$label2.Font = New-Object System.Drawing.Font("Arial Black",12,0,3,1)

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 24
$System_Drawing_Point.Y = 97
$label2.Location = $System_Drawing_Point
$label2.Name = "label2"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 261
$label2.Size = $System_Drawing_Size
$label2.TabIndex = 5
$label2.Text = "Select Algorithm"

$form1.Controls.Add($label2)

$label1.DataBindings.DefaultDataSourceUpdateMode = 0
$label1.Font = New-Object System.Drawing.Font("Arial Black",12,0,3,1)

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 24
$System_Drawing_Point.Y = 13
$label1.Location = $System_Drawing_Point
$label1.Name = "label1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 261
$label1.Size = $System_Drawing_Size
$label1.TabIndex = 4
$label1.Text = "Select file:"

$form1.Controls.Add($label1)

$comboBox1.DataBindings.DefaultDataSourceUpdateMode = 0
$comboBox1.FormattingEnabled = $True
$comboBox1.Items.Add("MD5")|Out-Null
$comboBox1.Items.Add("SHA1")|Out-Null
$comboBox1.Items.Add("SHA256")|Out-Null
$comboBox1.Items.Add("SHA384")|Out-Null
$comboBox1.Items.Add("SHA512")|Out-Null
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 24
$System_Drawing_Point.Y = 133
$comboBox1.Location = $System_Drawing_Point
$comboBox1.Name = "comboBox1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 24
$System_Drawing_Size.Width = 261
$comboBox1.Size = $System_Drawing_Size
$comboBox1.TabIndex = 3

$form1.Controls.Add($comboBox1)

$textBox1.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 24
$System_Drawing_Point.Y = 46
$textBox1.Location = $System_Drawing_Point
$textBox1.Name = "textBox1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 22
$System_Drawing_Size.Width = 261
$textBox1.Size = $System_Drawing_Size
$textBox1.TabIndex = 2

$form1.Controls.Add($textBox1)


$button2.DataBindings.DefaultDataSourceUpdateMode = 0
$button2.Font = New-Object System.Drawing.Font("Arial Black",8.25,0,3,1)

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 304
$System_Drawing_Point.Y = 114
$button2.Location = $System_Drawing_Point
$button2.Name = "button2"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 57
$System_Drawing_Size.Width = 108
$button2.Size = $System_Drawing_Size
$button2.TabIndex = 1
$button2.Text = "Get File Checksum"
$button2.UseVisualStyleBackColor = $True
$button2.add_Click($button2_OnClick)

$form1.Controls.Add($button2)


$button1.DataBindings.DefaultDataSourceUpdateMode = 0
$button1.Font = New-Object System.Drawing.Font("Arial Black",8.25,0,3,1)

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 304
$System_Drawing_Point.Y = 46
$button1.Location = $System_Drawing_Point
$button1.Name = "button1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 22
$System_Drawing_Size.Width = 108
$button1.Size = $System_Drawing_Size
$button1.TabIndex = 0
$button1.Text = "Browse"
$button1.UseVisualStyleBackColor = $True
$button1.add_Click($button1_OnClick)

$form1.Controls.Add($button1)

#endregion Generated Form Code

#Save the initial state of the form
$InitialFormWindowState = $form1.WindowState
#Init the OnLoad event to correct the initial state of the form
$form1.add_Load($OnLoadForm_StateCorrection)
#Show the Form
$form1.ShowDialog()| Out-Null

} #End Function

#Call the Function
GenerateForm

All that remains now is to write the button scripts so they execute the code you want when you press them.

Writing the button scripts

If you look in the form code exported in primalforms you will notice a few places where it says “#TODO: Place custom script here”. It is here that we must place our custom scripts which will be executed when the buttons are pressed. I chose to simply write the button scripts in separate files and then “dot source” the files as shown below.

#----------------------------------------------
#Generated Event Script Blocks
#----------------------------------------------	
$button1_OnClick= 
{
#########################################################################################
#Dot Source button script
$ScriptPath = $script:MyInvocation.MyCommand.Path
$ScriptDir = Split-Path $scriptpath
. "$ScriptDir\BrowseFileDialogue.ps1"
#########################################################################################
}

$button2_OnClick= 
{
#########################################################################################
#Dot Source button script
$ScriptPath = $script:MyInvocation.MyCommand.Path
$ScriptDir = Split-Path $scriptpath
. "$ScriptDir\Get-FileChecksum.ps1"
#########################################################################################
}

These two lines of code:
$ScriptPath = $script:MyInvocation.MyCommand.Path
$ScriptDir = Split-Path $scriptpath
are very useful. They enable me to create the object $ScriptDir which always points to the folder in which the form/script was executed. I can then create a script and copy it there. All I now need to do to execute it with the button in the form, is to add:
. “$ScriptDir\some_script.ps1
I will now briefly go over the two button scripts I use in the form.
1. BrowseFileDialogue.ps1

###############################################################################
##script:			BrowseFileDialogue.ps1
##
##Description:		Opens a window with a browse file dialogue and returns the
#+					filename selected.
##Created by:		Noam Wajnman
##Creation Date:	May 7, 2014
###############################################################################
#VARIABLES
$initialDirectory = "c:\"
#SCRIPT MAIN
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = $initialDirectory
$OpenFileDialog.filter = "All files (*.*)| *.*"
$OpenFileDialog.ShowHelp = $true
$OpenFileDialog.ShowDialog() | Out-Null
$fileSelected = $OpenFileDialog.filename
$textbox1.text = $fileSelected

Here I simply create an object of the type System.Windows.Forms.OpenFileDialog. I then use the ShowDialog() method on this object to make the browse file window appear. I then save the selected file name in $fileSelected. Lastly I add the selected filepath/filename to the first input field in the GUI/Form like this:
$textbox1.text = $fileSelected
Voila! now the filepath will appear in the textbox when you have selected a file.
2. Get-FileChecksum

###############################################################################
##script:			Get-FileChecksum.ps1
##
##Description:		Takes two parameters filename and algorithm and returns the
#+					computed file checksum hash.
##Created by:		Noam Wajnman
##Creation Date:	May 7, 2014
###############################################################################
#VARIABLES
$algorithm = $combobox1.text
$filename = $textbox1.text
#FUNCTIONS
function Update-RichTextBox {	
	$RichTextBox1.refresh()
	$RichTextBox1.SelectionStart = $RichTextBox1.Text.Length
    $RichTextBox1.ScrollToCaret()
}
function Write-RichTextBox {
	param (
		[string]$message
	)
	$time = Get-Date -Format "yyyy-MM-dd HH:mm:ss"	
	$RichTextBox1.AppendText("$time`n$message`n")
	Update-RichTextBox
}
function Show-ErrorBox {
    param (        
        $errorTitle,
        $errorText
    )    
    [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
    [System.Windows.Forms.MessageBox]::Show($errorText,$errorTitle)
}
function Get-FileMD5 {
    Param([string]$file)
	$md5 = [System.Security.Cryptography.HashAlgorithm]::Create("MD5")
	$IO = New-Object System.IO.FileStream($file, [System.IO.FileMode]::Open)
	$StringBuilder = New-Object System.Text.StringBuilder
	$md5.ComputeHash($IO) | % { [void] $StringBuilder.Append($_.ToString("x2")) }
	$hash = $StringBuilder.ToString() 
	$IO.Dispose()
	return $hash
}
function Get-FileSHA1 {
	Param([string]$file)	
	$sha1 = new-object -TypeName System.Security.Cryptography.SHA1CryptoServiceProvider
	$IO = [System.IO.File]::Open($file,[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)
	$hash = ([System.BitConverter]::ToString($sha1.ComputeHash($IO)) -replace '-','').ToLower()
	$IO.Dispose()
	return $hash
}
function Get-FileSHA384 {
	Param([string]$file)	
	$sha384 = new-object -TypeName System.Security.Cryptography.SHA384CryptoServiceProvider
	$IO = [System.IO.File]::Open($file,[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)
	$hash = ([System.BitConverter]::ToString($sha384.ComputeHash($IO)) -replace '-','').ToLower()
	$IO.Dispose()
	return $hash
}
function Get-FileSHA512 {
	Param([string]$file)	
	$sha512 = new-object -TypeName System.Security.Cryptography.SHA512CryptoServiceProvider
	$IO = [System.IO.File]::Open($file,[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)
	$hash = ([System.BitConverter]::ToString($sha512.ComputeHash($IO)) -replace '-','').ToLower()
	$IO.Dispose()
	return $hash
}
#SCRIPT MAIN
if ((test-path -PathType Leaf -Path $filename) -and $algorithm) {
	switch ($algorithm) {
		"MD5" { $hash = Get-FileMD5 -file $filename }
		"SHA1" { $hash = Get-FileSHA1 -file $filename }
		"SHA256" { $hash = Get-FileSHA256 -file $filename }
		"SHA384" { $hash = Get-FileSHA384 -file $filename }
		"SHA512" { $hash = Get-FileSHA512 -file $filename }
	}
	$result = "$algorithm hash of $filename is:`n$hash"
	Write-RichTextBox -message $result
}
else {
	$errorTitle = "Error - File name and algorithm not selected."
	$errorText = "Please select a valid file name and a hash algorithm and try again."
	Show-ErrorBox -errorText $errorText -errorTitle $errorTitle
}

To simplify the structure of this button script I have divided it into three sections variables, functions and script main. In the #VARIABLES section I just collect the input from the input fields (textbox and combobox) like so:
$algorithm = $combobox1.text
$filename = $textbox1.text
In the #FUNCTIONS section I have written the functions I need to work with the form output and calculate the hashes/checksums. I won’t go over them in detail here as the post will become far too long. I will however explain how I use them below in the walkthrough of the #SCRIPT MAIN section.

#SCRIPT MAIN
if ((test-path -PathType Leaf -Path $filename) -and $algorithm) {
	switch ($algorithm) {
		"MD5" { $hash = Get-FileMD5 -file $filename }
		"SHA1" { $hash = Get-FileSHA1 -file $filename }
		"SHA256" { $hash = Get-FileSHA256 -file $filename }
		"SHA384" { $hash = Get-FileSHA384 -file $filename }
		"SHA512" { $hash = Get-FileSHA512 -file $filename }
	}
	$result = "$algorithm hash of $filename is:`n$hash"
	Write-RichTextBox -message $result
}
else {
	$errorTitle = "Error - File name and algorithm not selected."
	$errorText = "Please select a valid file name and a hash algorithm and try again."
	Show-ErrorBox -errorText $errorText -errorTitle $errorTitle
}

The first thing I do in the button script main is to validate the input a little. I use an “If” statement to make sure both inputs are given in the form. If not the script goes into the “Else” script block and runs the “Show-ErrorBox” function which makes a little error window popup which asks the user to provide valid input. Assuming the input is ok I then use a “switch” statement on the $algorithm object in order to run different functions based on the selected hash algorithm. For instance if “MD5” was selected then the function “Get-FileMD5” will be run on the $filename object given as input. The result is then saved in the $hash object. Finally, after the switch block I use the function “Write-RichTextBox” to display the $hash string object in the RichTextBox in the form. Voila! now the file checksum will be displayed as output on the form.

Well that pretty much covers everything. All you need to do is create the form script and the two button scripts and “dot source” them as explained above. You can now simply run the form code script and your GUI will appear, ready to use!
PrimalFormsScreenDump2
I have copied the full code of all three scripts below. I hope this helps you to write your own small GUIs in the future. Good luck 🙂

###############################################################################
##script:			FileChecksumTool.ps1
##
##Description:		Small GUI tool which can calculate the checksum of a file
#+					using a selection of the most common hash algorithms.
##Created by:		Noam Wajnman
##Creation Date:	May 7, 2014
###############################################################################
function GenerateForm {
	#region Import the Assemblies
	[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
	[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
	#endregion

	#region Generated Form Objects
	$form1 = New-Object System.Windows.Forms.Form
	$label3 = New-Object System.Windows.Forms.Label
	$richTextBox1 = New-Object System.Windows.Forms.RichTextBox
	$label2 = New-Object System.Windows.Forms.Label
	$label1 = New-Object System.Windows.Forms.Label
	$comboBox1 = New-Object System.Windows.Forms.ComboBox
	$textBox1 = New-Object System.Windows.Forms.TextBox
	$button2 = New-Object System.Windows.Forms.Button
	$button1 = New-Object System.Windows.Forms.Button
	$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
	#endregion Generated Form Objects

	#----------------------------------------------
	#Generated Event Script Blocks
	#----------------------------------------------	
	$button1_OnClick= 
	{
	#########################################################################################
	#Dot Source button script
	$ScriptPath = $script:MyInvocation.MyCommand.Path
	$ScriptDir = Split-Path $scriptpath
	. "$ScriptDir\BrowseFileDialogue.ps1"
	#########################################################################################
	}

	$button2_OnClick= 
	{
	#########################################################################################
	#Dot Source button script
	$ScriptPath = $script:MyInvocation.MyCommand.Path
	$ScriptDir = Split-Path $scriptpath
	. "$ScriptDir\Get-FileChecksum.ps1"
	#########################################################################################
	}

	$OnLoadForm_StateCorrection=
	{#Correct the initial state of the form to prevent the .Net maximized form issue
		$form1.WindowState = $InitialFormWindowState
	}

	#----------------------------------------------
	#region Generated Form Code
	$System_Drawing_Size = New-Object System.Drawing.Size
	$System_Drawing_Size.Height = 364
	$System_Drawing_Size.Width = 430
	$form1.ClientSize = $System_Drawing_Size
	$form1.DataBindings.DefaultDataSourceUpdateMode = 0
	$form1.Font = New-Object System.Drawing.Font("Arial",9.75,0,3,0)
	$form1.Name = "form1"
	$form1.Text = "File Checksum Tool"

	$label3.DataBindings.DefaultDataSourceUpdateMode = 0
	$label3.Font = New-Object System.Drawing.Font("Arial",8.25,0,3,0)

	$System_Drawing_Point = New-Object System.Drawing.Point
	$System_Drawing_Point.X = 24
	$System_Drawing_Point.Y = 330
	$label3.Location = $System_Drawing_Point
	$label3.Name = "label3"
	$System_Drawing_Size = New-Object System.Drawing.Size
	$System_Drawing_Size.Height = 36
	$System_Drawing_Size.Width = 202
	$label3.Size = $System_Drawing_Size
	$label3.TabIndex = 7
	$label3.Text = "Created by Noam Wajnman May 2014. https://noamwajnman.wordpress.com"

	$form1.Controls.Add($label3)

	$richTextBox1.DataBindings.DefaultDataSourceUpdateMode = 0
	$System_Drawing_Point = New-Object System.Drawing.Point
	$System_Drawing_Point.X = 24
	$System_Drawing_Point.Y = 199
	$richTextBox1.Location = $System_Drawing_Point
	$richTextBox1.Name = "richTextBox1"
	$System_Drawing_Size = New-Object System.Drawing.Size
	$System_Drawing_Size.Height = 107
	$System_Drawing_Size.Width = 388
	$richTextBox1.Size = $System_Drawing_Size
	$richTextBox1.TabIndex = 6
	$richTextBox1.Text = ''

	$form1.Controls.Add($richTextBox1)

	$label2.DataBindings.DefaultDataSourceUpdateMode = 0
	$label2.Font = New-Object System.Drawing.Font("Arial Black",12,0,3,0)

	$System_Drawing_Point = New-Object System.Drawing.Point
	$System_Drawing_Point.X = 24
	$System_Drawing_Point.Y = 97
	$label2.Location = $System_Drawing_Point
	$label2.Name = "label2"
	$System_Drawing_Size = New-Object System.Drawing.Size
	$System_Drawing_Size.Height = 23
	$System_Drawing_Size.Width = 261
	$label2.Size = $System_Drawing_Size
	$label2.TabIndex = 5
	$label2.Text = "Select Algorithm"

	$form1.Controls.Add($label2)

	$label1.DataBindings.DefaultDataSourceUpdateMode = 0
	$label1.Font = New-Object System.Drawing.Font("Arial Black",12,0,3,0)

	$System_Drawing_Point = New-Object System.Drawing.Point
	$System_Drawing_Point.X = 24
	$System_Drawing_Point.Y = 13
	$label1.Location = $System_Drawing_Point
	$label1.Name = "label1"
	$System_Drawing_Size = New-Object System.Drawing.Size
	$System_Drawing_Size.Height = 23
	$System_Drawing_Size.Width = 261
	$label1.Size = $System_Drawing_Size
	$label1.TabIndex = 4
	$label1.Text = "Select file:"

	$form1.Controls.Add($label1)

	$comboBox1.DataBindings.DefaultDataSourceUpdateMode = 0
	$comboBox1.FormattingEnabled = $True
	$comboBox1.Items.Add("MD5")|Out-Null	
	$comboBox1.Items.Add("SHA1")|Out-Null	
	$comboBox1.Items.Add("SHA256")|Out-Null
	$comboBox1.Items.Add("SHA384")|Out-Null
	$comboBox1.Items.Add("SHA512")|Out-Null
	$System_Drawing_Point = New-Object System.Drawing.Point
	$System_Drawing_Point.X = 24
	$System_Drawing_Point.Y = 133
	$comboBox1.Location = $System_Drawing_Point
	$comboBox1.Name = "comboBox1"
	$System_Drawing_Size = New-Object System.Drawing.Size
	$System_Drawing_Size.Height = 24
	$System_Drawing_Size.Width = 261
	$comboBox1.Size = $System_Drawing_Size
	$comboBox1.TabIndex = 3

	$form1.Controls.Add($comboBox1)

	$textBox1.DataBindings.DefaultDataSourceUpdateMode = 0
	$System_Drawing_Point = New-Object System.Drawing.Point
	$System_Drawing_Point.X = 24
	$System_Drawing_Point.Y = 46
	$textBox1.Location = $System_Drawing_Point
	$textBox1.Name = "textBox1"
	$System_Drawing_Size = New-Object System.Drawing.Size
	$System_Drawing_Size.Height = 22
	$System_Drawing_Size.Width = 261
	$textBox1.Size = $System_Drawing_Size
	$textBox1.TabIndex = 2

	$form1.Controls.Add($textBox1)


	$button2.DataBindings.DefaultDataSourceUpdateMode = 0
	$button2.Font = New-Object System.Drawing.Font("Arial Black",8.25,0,3,0)

	$System_Drawing_Point = New-Object System.Drawing.Point
	$System_Drawing_Point.X = 304
	$System_Drawing_Point.Y = 114
	$button2.Location = $System_Drawing_Point
	$button2.Name = "button2"
	$System_Drawing_Size = New-Object System.Drawing.Size
	$System_Drawing_Size.Height = 57
	$System_Drawing_Size.Width = 108
	$button2.Size = $System_Drawing_Size
	$button2.TabIndex = 1
	$button2.Text = "Get File Checksum"
	$button2.UseVisualStyleBackColor = $True
	$button2.add_Click($button2_OnClick)

	$form1.Controls.Add($button2)


	$button1.DataBindings.DefaultDataSourceUpdateMode = 0
	$button1.Font = New-Object System.Drawing.Font("Arial Black",8.25,0,3,0)

	$System_Drawing_Point = New-Object System.Drawing.Point
	$System_Drawing_Point.X = 304
	$System_Drawing_Point.Y = 46
	$button1.Location = $System_Drawing_Point
	$button1.Name = "button1"
	$System_Drawing_Size = New-Object System.Drawing.Size
	$System_Drawing_Size.Height = 22
	$System_Drawing_Size.Width = 108
	$button1.Size = $System_Drawing_Size
	$button1.TabIndex = 0
	$button1.Text = "Browse"
	$button1.UseVisualStyleBackColor = $True
	$button1.add_Click($button1_OnClick)

	$form1.Controls.Add($button1)

	#endregion Generated Form Code

	#Save the initial state of the form
	$InitialFormWindowState = $form1.WindowState
	#Init the OnLoad event to correct the initial state of the form
	$form1.add_Load($OnLoadForm_StateCorrection)
	#Show the Form
	$form1.ShowDialog()| Out-Null

} #End Function

#Call the Function
GenerateForm



###############################################################################
##script:			BrowseFileDialogue.ps1
##
##Description:		Opens a window with a browse file dialogue and returns the
#+					filename selected.
##Created by:		Noam Wajnman
##Creation Date:	May 7, 2014
###############################################################################
#VARIABLES
$initialDirectory = "c:\"
#SCRIPT MAIN
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = $initialDirectory
$OpenFileDialog.filter = "All files (*.*)| *.*"
$OpenFileDialog.ShowHelp = $true
$OpenFileDialog.ShowDialog() | Out-Null
$fileSelected = $OpenFileDialog.filename
$textbox1.text = $fileSelected


###############################################################################
##script:			Get-FileChecksum.ps1
##
##Description:		Takes two parameters filename and algorithm and returns the
#+					computed file checksum hash.
##Created by:		Noam Wajnman
##Creation Date:	May 7, 2014
###############################################################################
#VARIABLES
$algorithm = $combobox1.text
$filename = $textbox1.text
#FUNCTIONS
function Update-RichTextBox {	
	$RichTextBox1.refresh()
	$RichTextBox1.SelectionStart = $RichTextBox1.Text.Length
    $RichTextBox1.ScrollToCaret()
}
function Write-RichTextBox {
	param (
		[string]$message
	)
	$time = Get-Date -Format "yyyy-MM-dd HH:mm:ss"	
	$RichTextBox1.AppendText("$time`n$message`n")
	Update-RichTextBox
}
function Show-ErrorBox {
    param (        
        $errorTitle,
        $errorText
    )    
    [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
    [System.Windows.Forms.MessageBox]::Show($errorText,$errorTitle)
}
function Get-FileMD5 {
    Param([string]$file)
	$md5 = [System.Security.Cryptography.HashAlgorithm]::Create("MD5")
	$IO = New-Object System.IO.FileStream($file, [System.IO.FileMode]::Open)
	$StringBuilder = New-Object System.Text.StringBuilder
	$md5.ComputeHash($IO) | % { [void] $StringBuilder.Append($_.ToString("x2")) }
	$hash = $StringBuilder.ToString() 
	$IO.Dispose()
	return $hash
}
function Get-FileSHA1 {
	Param([string]$file)	
	$sha1 = new-object -TypeName System.Security.Cryptography.SHA1CryptoServiceProvider
	$IO = [System.IO.File]::Open($file,[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)
	$hash = ([System.BitConverter]::ToString($sha1.ComputeHash($IO)) -replace '-','').ToLower()
	$IO.Dispose()
	return $hash
}
function Get-FileSHA384 {
	Param([string]$file)	
	$sha384 = new-object -TypeName System.Security.Cryptography.SHA384CryptoServiceProvider
	$IO = [System.IO.File]::Open($file,[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)
	$hash = ([System.BitConverter]::ToString($sha384.ComputeHash($IO)) -replace '-','').ToLower()
	$IO.Dispose()
	return $hash
}
function Get-FileSHA512 {
	Param([string]$file)	
	$sha512 = new-object -TypeName System.Security.Cryptography.SHA512CryptoServiceProvider
	$IO = [System.IO.File]::Open($file,[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)
	$hash = ([System.BitConverter]::ToString($sha512.ComputeHash($IO)) -replace '-','').ToLower()
	$IO.Dispose()
	return $hash
}
#SCRIPT MAIN
if ((test-path -PathType Leaf -Path $filename) -and $algorithm) {
	switch ($algorithm) {
		"MD5" { $hash = Get-FileMD5 -file $filename }
		"SHA1" { $hash = Get-FileSHA1 -file $filename }
		"SHA256" { $hash = Get-FileSHA256 -file $filename }
		"SHA384" { $hash = Get-FileSHA384 -file $filename }
		"SHA512" { $hash = Get-FileSHA512 -file $filename }
	}
	$result = "$algorithm hash of $filename is:`n$hash"
	Write-RichTextBox -message $result
}
else {
	$errorTitle = "Error - File name and algorithm not selected."
	$errorText = "Please select a valid file name and a hash algorithm and try again."
	Show-ErrorBox -errorText $errorText -errorTitle $errorTitle
}