Creating a Dynamically Changing WinForm

This is a fairly simple thing, if you know what you’re doing or if you have done it before. But if, like me, you are at a complete lost and sick of searching only to find half complete or even completely contradictory answers, then this is the guide for you.

My goals for this GUI was to have the form resize IF a tick box was $true (ticked)

First I started off created a blank form with a single checkbox item, you can see this below:

$form = New-Object System.Windows.Forms.Form
$form.Text = "New User Form"
$form.Size = New-Object System.Drawing.Size(500,540)
$form.StartPosition = "CenterScreen"
$form.FormBorderStyle = "Fixed3D"
$form.MaximizeBox = $false
$form.MinimizeBox = $false

$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Point(165,470)
$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(245,470)
$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)

$checkbox = New-Object System.Windows.Forms.CheckBox
$checkbox.Location = New-Object System.Drawing.Point(100,100)
$checkbox.Size = New-Object System.Drawing.Size(100,25)
$checkbox.Text = "Test Checkbox"
$form.controls.Add($checkbox)

$result = $form.ShowDialog()

That will create an empty form like the one below:

Initial Form

Now I will add the following code after all the objects but before the end $result variable which displays the form:

$checkbox.add_checkstatechanged({

 if ($checkbox.Checked -eq $True){

  $form.size = new-object system.drawing.size(800,540)

 }else{

  $form.size = new-object system.drawing.size(500,540)

}

})

 

this is the part that will make the form larger if the checkbox is checked and return it to the original size if it isn’t checked. You can do SO many other things as well. For example, having a textbox enabled or disabled, changing the forms title, changing the colour of the form and to be honest just about anything you can think of.

This is the complete script you will need:

$form = New-Object System.Windows.Forms.Form
$form.Text = "New User Form"
$form.Size = New-Object System.Drawing.Size(500,540)
$form.StartPosition = "CenterScreen"
$form.FormBorderStyle = "Fixed3D"
$form.MaximizeBox = $false
$form.MinimizeBox = $false

$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Point(165,470)
$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(245,470)
$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)

$checkbox = New-Object System.Windows.Forms.CheckBox
$checkbox.Location = New-Object System.Drawing.Point(100,100)
$checkbox.Size = New-Object System.Drawing.Size(100,25)
$checkbox.Text = "Test Checkbox"
$form.controls.Add($checkbox)

$checkbox.add_checkstatechanged({
 if ($checkbox.Checked -eq $true){
  $form.Size = New-Object System.Drawing.Size(800,540)
 }else{
  $form.Size = New-Object System.Drawing.Size(500,540)
 }
})

$result = $form.ShowDialog()

This script will create a form like in the screenshots below. In this screenshot the checkbox is not ticked:

Initial Form

And in this screenshot the checkbox has been ticked, making the form size noticeably wider:

Ticked Form

Hope this helps someone struggling with getting started with some of the more complex WinForm tricks. Enjoy and comment if you need any help!

 

 

 

 

Better Credentials Checking in PowerShell

This is something that I have recently created so that when a script asks for a credentials and there is an error, it doesn’t display a big, ugly and often intimidating error message for any poor soul trying to run my scripts.

That’s why I have recently (as in yesterday) “created” a “fool proof” way of entering and validating credentials against a domain.

This was a problem because whenever someone ran my script and did ANYTHING other than enter perfectly correct credentials, it would throw and error and exit the script. Or even carry on with the script WITHOUT THE CREDENTIALS, which obviously wouldn’t work. I know, I know. Amateur hour! But it was a crap system I must admit.

That’d why I spent and hour or so creating this beauty! It captures any errors, such as null credentials and incorrect credentials and only continues if a user exists with the same samaccountname as the one entered at the credentials prompt and if the user is in the domain admins group. Just for added “security”. Really I just want the appropriate people to be using the script.

This is the code I use!

#PROMPTING FOR CREDENTIALS
$cred = $host.UI.PromptForCredential("Need credentials", "Please enter your username and password.", "", "")
if ($cred -ne $null -and $cred -ne ''){
 #CHECKING IF THE CREDENTIAL USERNAME EXISTS
 $check = $(try {Get-ADUser -Identity $cred.UserName} catch {$null})

  if ($check -ne $null){
  #GETTING CREDENTIAL USERNAME GROUPMEMBERSHIP
  $checkadmin = Get-ADPrincipalGroupMembership -Identity $cred.UserName
  $checkadminrefined = $checkadmin.SamAccountName
  #PUTTING GROUP MEMBERSHIP INTO AN ARRAY
  $array = $checkadminrefined
  #CHECKING IF USER GROUP LIST CONTAINS DOMAIN ADMINS
  if ($array -contains "Domain Admins"){
   Write-Host "Credentials are GOOD! - Continuing with script" -ForegroundColor Green
   Start-Sleep -Seconds 1
  }else{
   #RESULT IF USER IS NOT DOMAIN ADMINS
   Clear-Host
   Write-Host "Credentials are not a domain admin! - Close and start again" -ForegroundColor Red ;
   $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
   Exit
  }
 }else{
  #RESULT IF NO USER CAN BE FOUND FROM CREDENTIAL USERNAME
  Clear-Host
  Write-Host "Check is empty - No user found matching credentials supplied! - Close and start again" -ForegroundColor Red
  $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
  Exit
 }
}else{
 #RESULT IF PROMPT IS CLOSED / NO CREDENTIALS SUPPLIED
 Clear-Host
 write-host "No credentials supplied - Close and start again" -ForegroundColor Red
 $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
 Exit
}

You should be able to read the script and see which each part does. I left comments in the script which I don’t normally do since it might be easier for you to see what its doing with pointers at each stage.

Enjoy!

Create, Store & Use Encrypted Passwords With PowerShell

This is just a neat little “tactic” I use when I need to connect to the same machine over and over again but don’t want to drive myself insane with having to constantly enter the same username and password. For example, when testing a script.

First you need to enter your password, in plain text, into this script so that it can get the password. This a perfectly safe as it will only be at this point where the password is in plain text.

$password = "PUT PASSWORD HERE" | ConvertTo-SecureString -AsPlainText -Force

This gets the password that you just entered and encrypts it and also puts it into the variable “password”

Now you need to convert the password to an encrypted string of characters using the below command:

$Password2 = $password | ConvertFrom-SecureString | Out-File "PATH TO TEXT FILE TO STORE PASSWORD"

This puts the encrypted password into the text file for later use.

Now, whenever you need to connect to a machine, you can put this into a variable along with the username. Then put them together into a credential and away you go:

$Username = "DOMAIN\username"

$EcryptedPassword = Get-Content "LOCATION TO TEXT FILE" | ConvertTo-SecureString

$Credential = New-Object System.Management.Automation.PSCredential($Username, $EncryptedPassword)

This builds the credential which you can now use with something similar to below:

Invoke-Command -Credential $Credential -ScriptBlock {echo "test"} -ComputerName "COMPNAME" -Authentication CredCSSP

Enjoy!

Linux New Users Form

Following on from my recent upload on Linux scripting, I have yet again created a BASH script to make my Linux’ing life easier. This is also my second script created in BASH so I guess i’ve accomplished something by not running for the hills…

What I needed was a script to make creating FTP users easier on my CentOS box. Below is a list of things I needed the script to accomplish:

  • Get a username from a user prompt
  • Get a Description from a user prompt
  • Create the new user
  • Change the users password
  • Add the username to /etc/vsftpd.userlist
  • Add the username to /etc/vsftpd/chroot_list
  • Make a directory in the home folder of the user called “ftp”
  • Change the permissions and ownership on this directory
  • Make a directory in the “ftp” folder called “files”
  • Change the permissions and ownership on this directory
  • Ask the user to create a share or not
  • Get a share name from user prompt
  • Make a directory in the users “files” folder with the same name as the share name
  • Mount the share to the “files” directory
  • Ask if the new user is the owner of the share
    • if so then change the ownershipa and permissions on the share
    • if not then just change the permissions on the share
  • Finish

Here is my script for achieving these goals:

#!/bin/bash
#Creating new FTP users

##Gathering Variables
echo "Enter a username"
read Username

echo "Enter a description"
read Description

useradd -m -c "$Description" -s /bin/bash $Username

passwd $Username

echo "$Username" | tee -a /etc/vsftpd.userlist
echo "$Username" | tee -a /etc/vsftpd/chroot_list

mkdir /home/$Username/ftp
chown nobody:nobody /home/$Username/ftp
chmod a-w /home/$Username/ftp

mkdir /home/$Username/ftp/files
chown $Username:$Username /home/$Username/ftp/files
chmod 0700 /home/$Username/ftp/files

read -p "Create a share? [yn]: " CreateShare
if [[ $CreateShare = y ]] ; then

 read -p "Enter a share name: " ShareName

 mkdir /home/$Username/ftp/files/$ShareName
 mkdir /home/shares/$ShareName
 mount --bind /home/shares/$ShareName /home/$Username/ftp/files/$ShareName
elif [[ $CreateShare = n ]] ; then
 read -p "Enter the pre-existing share name: " ShareName
 mkdir /home/$Username/ftp/files/$ShareName
 if [ -d /home/shares/$ShareName ] ; then
  echo "Mounting share"
  mount --bind /home/shares/$ShareName /home/$Username/ftp/files/$ShareName
 else
  echo "Cannot find the share name : $ShareName"
 fi
else
 echo "Not a y or n"
fi

read -p "Is $Username the owner of this share? [yn]: " ShareOwner
if [[ $ShareOwner = y ]] ; then
 chown $Username:$Username /home/shares/$ShareName
 chmod 0775 /home/shares/$ShareName
else
 echo "$Username is not the owner of $ShareName"
 chmod 0775 /home/shares/$ShareName
fi

echo "Finished creating user : $Username" * Insert your code here

Hopefully somebody gains something from this, probably not though. Enjoy!

Linux Mounting Script

Recently I have set up a VSFTPD CentOS 7 server and chrooted all the local users to their home directory. *If you know what that means $YourPoints = $YourPoints + 5*

But when ever the system was rebooted or for any other reason that I don’t fully understand yet, the mounts from the shares to the users home directory would get lost. Because the users were chrooted into their home directories, I couldn’t use symbolic or hard links. Instead I had to use the:

mount --bind

option to make the mount accessible to the chrooted users.

But since the mount kepts getting lost and I had grown tired of the users complaining that they couldn’t access the share. Plus it was taking too long manually remounting all the shares, let alone finding out which ones had become disconnected before the users started to complain. So I created a script to check and ask me if I wanted to mount the share.

Just so you know, this is my first time scripting in BASH and I only did it because of my short lived love with Linux. Below is an example of the code in my script, I basically created one of these functions for each user:

#TESTING USER3
if mountpoint -q /home/user3/ftp/files/share
 then
 echo "user3 is mounted"
 else
 echo "user3 is not mounted"
 read -p "Do you want to mount share? (y or n):" REPLY
 if [[ $REPLY = y ]]
  then
  mount --bind /home/shares/share/ /home/user3/ftp/files/share
 fi
fi

This way all I have to do is run this script and it will mount all of the shares for me. Let me know if there is an easier way to do this or if im missing something obviouse. Enjoy!

Windows Favourites Folder Spelt “Favorites”

Something a little off topic today. Windows naming is weird… that’s it. I found this when trying to run a RoboCopy script to back-up my favourites “Internet Explorer” (Award winning, grama nominated, amazing browser).

This is what my script for RoboCopy used to look like:

robocopy C:\Users\harwoodm\Favourites d:\robocopy\Favourites /MIR /R:1 /W:5 /FFT /LOG:"C:\users\harwoodm\robocopy logs\favourites.txt" /TEE /NP /NFL /NDL

I was getting Error 2, path not found.

Little did I know that, even though in the Explorer it’s spelt “Favourites” the path has it as “Favorites”

EVIDENCE!!!

Favorites

Does this make any sense to you, doesn’t to me…

Anway, hope this helped. Enjoy!

Rock, Paper, Scissors In PowerShell

Another game today, I’ll be adding this to my big Games Project soon. Just need to implement it into the script.

First I started off by making the PowerShell window the correct size. I did this by adding:

$pshost = get-host
$pswindow = $pshost.ui.rawui
$newsize = $pswindow.buffersize
$newsize.height = 500
$newsize.width = 500
$pswindow.buffersize = $newsize
$newsize = $pswindow.windowsize
$newsize.height = 22
$newsize.width = 85
$pswindow.windowsize = $newsize
$pswindow.WindowTitle = "Rock, Paper, Scissors"

to the start of the function.

Next I created the meat of the game, here its just a simple do statement until either the score of the user or the score of the computer has reached or exceeded 3. Best of three sort of thing. Heres that part:

do {
 $options = @("Rock","Paper","Scissors")
 $option = $options | Get-Random -Count 1
 Clear-Host
 Write-Host "Your Score - $score" -ForegroundColor Green
 Write-Host "Computer's Score - $computerscore" -ForegroundColor Red
 do {$selection = Read-Host "Selection"}while (("Rock","Paper","Scissors") -notcontains $selection)
  if ($selection -eq "rock" -and $option -eq "paper"){
   Write-Host "You lose, the computer chose $option";
   Start-Sleep -Seconds 1
   $computerscore = $computerscore + 1
  }elseif($selection -eq "paper" -and $option -eq "scissors"){
   Write-Host "You lose, the computer chose $option"
   Start-Sleep -Seconds 1
   $computerscore = $computerscore + 1
  }elseif($selection -eq "scissors" -and $option -eq "rock"){
   write-host "You lose, the computer chose $option"
   Start-Sleep -Seconds 1
   $computerscore = $computerscore + 1
  }elseif ($selection -eq $option){
   Write-Host "Its a draw"
   Start-Sleep -Seconds 1
  }else{
   Write-Host "You won, the computer chose $option"
   Start-Sleep -Seconds 1
   $score = $score + 1
  }
 }until (($score -eq 3) -or ($computerscore -eq 3))
 if ($computerscore -gt $score){
  Clear-Host
  Write-Host "You lost, the computer scored $computerscore points whilst you only scored $score points" -ForegroundColor Red
 }else{
  Clear-Host
  Write-Host "You won, you got $score points. More than the computer's $computerscore" -ForegroundColor Green
 }
}

Finally, I ended the code of by showing the user who won and giving then the option to exit the game or play again. Here is the code for that:

do {$playagain = Read-Host "Do you want to play again? Y or N"} while (("Y","N") -notcontains $playagain)
if ($playagain -eq "y"){
 RPS
}elseif ($playagain -eq "n"){
 exit
}

===================================================================================================

Hopefully you can see how this all comes together. Here is the entire script for the game:

function RPS{
 $pshost = get-host
 $pswindow = $pshost.ui.rawui
 $newsize = $pswindow.buffersize
 $newsize.height = 500
 $newsize.width = 500
 $pswindow.buffersize = $newsize
 $newsize = $pswindow.windowsize
 $newsize.height = 22
 $newsize.width = 85
 $pswindow.windowsize = $newsize
 $pswindow.WindowTitle = "Rock, Paper, Scissors"

 [int]$score = 0
 [int]$computerscore = 0

 do {
  $options = @("Rock","Paper","Scissors")
  $option = $options | Get-Random -Count 1
  Clear-Host
  Write-Host "Your Score - $score" -ForegroundColor Green
  Write-Host "Computer's Score - $computerscore" -ForegroundColor Red
  do {$selection = Read-Host "Selection"}while (("Rock","Paper","Scissors") -notcontains $selection)
  if ($selection -eq "rock" -and $option -eq "paper"){
   Write-Host "You lose, the computer chose $option";
   Start-Sleep -Seconds 1
   $computerscore = $computerscore + 1
  }elseif($selection -eq "paper" -and $option -eq "scissors"){
   Write-Host "You lose, the computer chose $option"
   Start-Sleep -Seconds 1
   $computerscore = $computerscore + 1
  }elseif($selection -eq "scissors" -and $option -eq "rock"){
   write-host "You lose, the computer chose $option"
   Start-Sleep -Seconds 1
   $computerscore = $computerscore + 1
  }elseif ($selection -eq $option){
   Write-Host "Its a draw"
   Start-Sleep -Seconds 1
  }else{
   Write-Host "You won, the computer chose $option"
   Start-Sleep -Seconds 1
   $score = $score + 1
  }
 }until (($score -eq 3) -or ($computerscore -eq 3)) 
 if ($computerscore -gt $score){
  Clear-Host
  Write-Host "You lost, the computer scored $computerscore points whilst you only scored $score points" -ForegroundColor Red
 }else{
  Clear-Host
  Write-Host "You won, you got $score points. More than the computer's $computerscore" -ForegroundColor Green
 }

 do {$playagain = Read-Host "Do you want to play again? Y or N"} while (("Y","N") -notcontains $playagain)
 if ($playagain -eq "y"){
  RPS
 }elseif ($playagain -eq "n"){
  exit
 }
}

I was quite surprised at how short I got the script to be, I think I may try to make the Blackjake game shorter as, lets me honest. Its barbaric in its construction.

Headline News Reporter in PowerShell

Daft one today. Been a little  busy and lacking ideas as to what to do next, so don’t expect anything special in this post. That that you ever should with me…

Basically what this does is that it looks at the technology page the BBC news site and gives me the current 10 stories. Stupid right? I know, I know.

I might add this to a start-up script so that I can automatically get the latest tech news when ever I logon to my computer. Anyway, my code is below if you want to waste some hard drive space…

$result = Invoke-WebRequest -Uri http://www.bbc.co.uk/news/technology
$path = "C:\Scripts\testing.txt"
$result.Links | Select innertext | Select-String "full article *" | Out-File -FilePath $path

(Get-Content "$path") -replace "@{innerText=Full article" -replace "}","" | select -First 11

Enjoy!

Games In PowerShell – Version 4

Quite a large update to my Games in PowerShell project, adding a new game, changing some of the styling of the game and changing the loading screen of the game.

You’ll be pleased and proud to know that the games code is now over a thousand lines long…At least fake being proud then.

As mentioned earlier, I have added a new game. This one is different from my other games because it is a text based adventure game about a dino that needs capturing. The player only successfully completes the game once they have captured the dino and also not been killed by it. Tall order, I know.

I also changed how the Quick Fire Character Counting game works. It now starts by giving the player a full second to see the word and guess how many characters it contains, then, each time the user gets a correct answer reduces the viewing time of the word by 30 miliseconds. That way the game gradually gets more difficult instead of being stuck at the same length, which is boring.

Here is the link to my code for the game

I will be updating my project page with this update as well. Enjoy!

More Auto-Loading, Custom PowerShell Scripts

In this update, you’ll see how I added two or three new scripts to the environment and also changed how most of the scripts work.

One new script that I add was a script that would take CSV data and add the users to a group in Active Directory. You can see this below:

function Get-CSVAddToGroup{
 <#
 .SYNOPSIS
 This function allows you to add usernames from a CSV to a specified Active Directory group.
 It needs confirmation for each addition to a group.

 .EXAMPLE
 Get-CheckCSVAddToGroup -Groupname "all rossendale staff" -path c:\testing\test.csv

 #>
 [cmdletbinding()]
 param(
 [parameter(Mandatory=$true)]
 [string]$groupname,

 [parameter(mandatory=$true)]
 [string]$path
 )

 $csvformembership = Import-Csv -Path $path

 foreach ($b in $csvformembership){
  $name = $b.user
  Add-ADGroupMember -Identity "$groupname" -Members $name -Confirm
 }
}

Another script I added was my script for sending messages to remote computers on the network. You can see this below:

function Send-Message{

 function send-messagewithname{
  $name = Read-Host "Enter a name"
  $msg = Read-Host "enter a message"
  $adcompstocheck = Get-ADComputer -LDAPFilter "(name=$name)" -Properties name

  if ($adcompstocheck -eq $null){
   Write-Host "$name doesn't exist!"
   pause
  }else{
   Invoke-WmiMethod -Path win32_process -Name create -ArgumentList "msg * $msg" -ComputerName "$name"
  }
 }

 function send-messagewithip{
  $ip = Read-Host "enter an IP"
  $msg = Read-Host "enter a message"
  $adcompstocheckip = Get-ADComputer -Filter * -Properties ipv4address, name | select ipv4address
  if ($adcompstocheckip -eq $null){
   write-host "$ip doesn't exist"
   pause
  }else{
   Invoke-WmiMethod -Path win32_process -Name create -ArgumentList "msg * $msg" -ComputerName "$ip"
  }
 }

 do {$nameorip = Read-Host "Do you want to use IP or Name (I or N)?"} while (("i","n") -notcontains $nameorip)
 if ($nameorip -eq "n"){
  send-messagewithname
 }else {
  send-messagewithip
 }
}

Finally, my last script that was added to my custom PowerShell environment allowed me to list all the computers on the network with a specific operating system. For example “2012” or “Professional”. The code for this is below:

function list-OSVersonComputers{
 <#
 .SYNOPSIS
 This function allows you to list all of the computers with the requested OS version.

 .EXAMPLE
 List-OSVersionComputers -OSVersion 2012

 .EXAMPLE
 List-OSVersionComputers -OSVersion standard
 #>
 [cmdletbinding()]
  param(
  [parameter(mandatory=$true)]
  [string]$OSVersion
 )

 $OSVersion2 = '*' + ($OSVersion) + '*'

 Get-ADComputer -Filter {OperatingSystem -like $OSVersion2} -Property * | Format-Table name,operatingsystem,lastlogondate -Wrap -AutoSize
}

I also added help menus to most of my scripts to make them more professional.