Set advanced settings on all VMs in a cluster

Standard

Recently I was tasked with modifying the VM advanced settings (or VMX settings) on all of our VMs. Since I didn’t want to manually edit the VMX files on 500+ VMs I resolved to make a script which could do the job instead. I eventually made a good and working script which I will go over below.
First off I want to say that I have based a great deal of this script on some code that I found here: https://communities.vmware.com/docs/DOC-18653. Many thanks to Alan Renouf for posting this article!
The script posted here has been improved a bit and is also more complete since it also connects to vcenter on its own. This should hopefully make this script useful even to admins who aren’t experienced with powershell.

###############################################################################
##set-VMAdvancedSettings.ps1
##
##Description:		sets/creates advanced settings on VMs based on CSV input
##Created by:		Noam Wajnman
##Creation Date:	March 11, 2014
###############################################################################
#VARIABLES
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
$PathToCSV = "$dir\vmsettings.csv"
$vcenter = "some_vcenter_server" #script will connect to this vcenter server
$clusterName = "Some_cluster" #advanced settings will be set on all VMs on this cluster
#FUNCTIONS
function ConnectToVcenter {
	param(
		$vcenter
	)
	#Load snap-in and connect to vCenter
	if (-not (Get-PSSnapin -Name VMware.VimAutomation.Core)) {
		Add-PSSnapin VMware.VimAutomation.Core
	}
	if ($global:DefaultVIServers.Count -ne 1) {
		Connect-VIServer $vCenter
	}
}
function Set-VMAdvancedConfiguration { 
	###############################################################################
	##Function set-VMAdvancedConfiguration
	##
	##Description:		sets/creates advanced settings on VMs
	##Created by:		Noam Wajnman
	##Creation Date:	March 11, 2014
	##Credits:			Based on code written by alan renouf found here: 
	#+					https://communities.vmware.com/docs/DOC-18653
	###############################################################################
	[CmdletBinding()]
	[OutputType([System.String])]
  	param(  
    	[Parameter(Mandatory=$true,ValueFromPipeline=$true)]$vm,  
      	[string]$PathToCSV
    )
	begin {		
		$vmConfigSpec = new-object VMware.Vim.VirtualMachineConfigSpec  
		$vmsettings = Import-Csv $PathToCSV -Header Key,Value
		$vmsettings | Foreach {  
        	$Value = new-object vmware.vim.optionvalue  
        	$Value.key = $_.key  
        	$Value.value = $_.value  
        	$vmConfigSpec.ExtraConfig += $Value  
        	Write-Host "Adding $($_.Key) = $($_.Value) to configuration specifications"  
		}
	}
  	process {    	  
    	$Task = ($vm.ExtensionData).ReconfigVM_Task($vmConfigSpec)  
      	Write-Host "Setting Advanced configuration for $($VM.Name)"    	 
  	}
	end {
		Write-Host "Finished applying advanced settings to VMs."
	}
}

#SCRIPT MAIN
ConnectToVcenter -vcenter $vcenter
Get-cluster $clusterName | get-vm | Set-VMAdvancedConfiguration -PathToCSV $PathToCSV

All you need to do to run the script is:
1. Create a CSV file in the same directory as the script. The CSV must have two “columns”, the name of the settings and the desired value. I did it in excel and my example CSV file looks like this:
vmsettings_in_excel
2. Edit two values in the #Variables section of the script. Set $vcenter to the name of your vcenter server and $clusterName to the name of your cluster (all VMs on this cluster will have their advanced settings changed according to what you wrote in the CSV file).

You can then run the script and see all the specified settings being changed automatically on your VMs. Yay 🙂

I hope you will find the script useful!!

Advertisements

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
}

Set VMTools time synchronization mode on all VMs in a cluster

Standard

When changing the time synchronization settings in your environment you may have to also make modifications in your VMWare infrastructure. Among other things it can be necessary to control if the VM should synchronize its time from the host server or not. Normally it’s a manual process where you have to click into the VM settings and go to the Options tab and select VMWare Tools and there check the box or not. This script will do all that for you and set the VMTools host time synchronization to the value you choose, on all VMs in a given cluster. This will save you a lot of time especially if you, like me, manage a VMWare infrastructure with hundreds of VMs.
Although the script is quite short I have divided it into three sections variables, functions and script main to simplify its structure.

Variables

#VARIABLES
$DebugPreference = "continue" #comment out to disable debug info
#Parameters
$vcenter = "some_vcenter_server" #your vcenter server name
$clusterName = "Some_Cluster" #advanced settings will be set on all VMs on this cluster
$TimeSync = $true #script will enable/disable time sync on host on the VMs based on this value. Valid values are $true and $false

Before you run the script you will need to fill out the parameters in the variables section. $clustername is the name of the cluster on which you want to the change the settings for your VMs. All VMs running on the cluster will have their VMTools host time sync value set to what you specify in $TimeSync.

Functions

#FUNCTIONS
function ConnectToVcenter {
	param(
		$vcenter
	)
	#Load snap-in and connect to vCenter
	if (-not (Get-PSSnapin -Name VMware.VimAutomation.Core)) {
		Add-PSSnapin VMware.VimAutomation.Core
	}
	if ($global:DefaultVIServers.Count -lt 1) {
		Connect-VIServer $vCenter
	}
}
function Set-SyncValue {
	[CmdletBinding()]
	[OutputType([System.String])]
	param(
		[Parameter(ValueFromPipeline=$true)]$VM,
		[bool]$SyncValue
	)
	begin {
		Write-Debug "Creating configuration specification object"
		$ConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec 
		$ConfigSpec.tools = New-Object VMware.Vim.ToolsConfigInfo 
		$ConfigSpec.tools.syncTimeWithHost = $SyncValue
	}
	process {
		#configure the VM
		Write-Debug "Setting VMTools time sync to $SyncValue on $($VM.Name)"
		$View = get-view -viewtype virtualmachine -Filter @{'name'=$VM.Name} 
		$View.ReconfigVM_task($ConfigSpec)
		sleep 3 #wait for the configuration to complete
		#Check if the VM was configured as desired.
		$AfterView = get-view -viewtype virtualmachine -Filter @{'name'=$VM.Name} 
		[bool]$result = [System.Convert]::ToBoolean($AfterView.Config.Tools.syncTimeWithHost)		
		if ($result -eq $SyncValue) {
			Write-Debug "Successfully set the Tools.syncTimeWithHost on $VM to $SyncValue"
		}
		else {
			Write-Debug "Error - $VM - Couldn't set the Tools.syncTimeWithHost to the desired value of $SyncValue"
		}
	}
	end {
		Write-Debug "Finished setting time sync values on VMs."
	}
}

The script uses two functions which I will go over now.
1. Function ConnectToVcenter
This function takes one parameter $vcenter which is the name of the vcenter server. If not already done the function adds the VMWare snap-in for powershell and then connects to vcenter to make ready for the commands we will run after.
2. Function Set-SyncValue
Set-SyncValue takes two parameters $VM and $SyncValue. $VM can be passed from the pipeline which makes it easy to use in combination with other VMWare commands. The function works by first creating a configuration specification object with the value given in $SyncValue. After this it loops though the given VMs and reconfigures them accordingly. After the command to configure a VM has been sent, the script waits 3 seconds and then checks if the setting was updated to the value you wanted.

Script Main

#SCRIPT MAIN
ConnectToVcenter -vcenter $vcenter
Get-Cluster $clusterName | Get-VM | Set-SyncValue -SyncValue $TimeSync 

The script main is very short and simple. First I connect to vcenter using the function ConnectToVcenter. The actual work is then done in a one liner where I simply pipe all the VMs from the Get-Cluster and Get-VM cmdlets to the Set-SyncValue function.

That’s it. I hope you find the script useful. I have copied the full version of the script in below.

#####################################################################################################
##Script:			Set-VMTools_TimeSync.ps1
##
##Description:		enables/disables the VMTools time sync mode on all VMs in a given cluster.
##Created by:		Noam Wajnman
##Credits:			Part of this script was based on this article: 
#+					https://psvmware.wordpress.com/tag/disable-vmware-tools-time-sync-using-powercli/
##Creation Date:	April 28, 2014
#####################################################################################################
#VARIABLES
$DebugPreference = "continue" #comment out to disable debug info
#Parameters
$vcenter = "some_vcenter_server"
$clusterName = "Some_Cluster" #advanced settings will be set on all VMs on this cluster
$TimeSync = $true #script will enable/disable time sync on host on the VMs based on this value. Valid values are $true and $false
#FUNCTIONS
function ConnectToVcenter {
	param(
		$vcenter
	)
	#Load snap-in and connect to vCenter
	if (-not (Get-PSSnapin -Name VMware.VimAutomation.Core)) {
		Add-PSSnapin VMware.VimAutomation.Core
	}
	if ($global:DefaultVIServers.Count -lt 1) {
		Connect-VIServer $vCenter
	}
}
function Set-SyncValue {
	[CmdletBinding()]
	[OutputType([System.String])]
	param(
		[Parameter(ValueFromPipeline=$true)]$VM,
		[bool]$SyncValue
	)
	begin {
		Write-Debug "Creating configuration specification object"
		$ConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec 
		$ConfigSpec.tools = New-Object VMware.Vim.ToolsConfigInfo 
		$ConfigSpec.tools.syncTimeWithHost = $SyncValue
	}
	process {
		#configure the VM
		Write-Debug "Setting VMTools time sync to $SyncValue on $($VM.Name)"
		$View = get-view -viewtype virtualmachine -Filter @{'name'=$VM.Name} 
		$View.ReconfigVM_task($ConfigSpec)
		sleep 3 #wait for the configuration to complete
		#Check if the VM was configured as desired.
		$AfterView = get-view -viewtype virtualmachine -Filter @{'name'=$VM.Name} 
		[bool]$result = [System.Convert]::ToBoolean($AfterView.Config.Tools.syncTimeWithHost)		
		if ($result -eq $SyncValue) {
			Write-Debug "Successfully set the Tools.syncTimeWithHost on $VM to $SyncValue"
		}
		else {
			Write-Debug "Error - $VM - Couldn't set the Tools.syncTimeWithHost to the desired value of $SyncValue"
		}
	}
	end {
		Write-Debug "Finished setting time sync values on VMs."
	}
}
#SCRIPT MAIN
ConnectToVcenter -vcenter $vcenter
Get-Cluster $clusterName | Get-VM | Set-SyncValue -SyncValue $TimeSync

Powershell – Get inventory/slots of Dell chassis/blades

Standard

Here’s a script which will get the contents of your Dell blade chassis and export the list to a CSV file. This can be very useful to get an overview of or update your list of servers. The script uses the Dell racadm command “getslotname” and “plink.exe” to connect to the chassis and retrieve the information. You must download plink.exe (part of the putty suite) for this script to work.
I have divided the script into three sections variables, functions and script main to simplify the structure of the script. Below I will walk through the script and explain how I wrote each section.

Variables

#VARIABLES
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath #path to the directory in which the script is run.
$plink = "$dir\plink.exe" #path to plink.exe in the script directory
$CSV = "$dir\SlotNames.csv" #results will be exported to a csv file with this path
#Parameters
$username = "some_user" #username used to login to the chassis
$password = "some_password" #password used to login to the chassis
$ChassisNames = @("cmc01","cmc02","cmc03","cmc04","cmc05","cmc06") #add your chassis names or IPs in this array like shown.

The comments in the code pretty much explain all the different variables. Just remember to fill out the #parameters section according to your needs before you run the script.

Functions

1. Function Get-SlotName

function Get-SlotName {
	param (
		$ChassisName,
		$slotNumber
	)
	$EXE = $plink    
		$arg1 = "-pw"
		$arg2 = "$password"
		$arg3 = "$username@$ChassisName"
		$arg4 = "getslotname -i $slotnumber"		
		$command = "$EXE $arg1 $arg2 $arg3 $arg4"
		$output = invoke-expression -Command $command
		return $output
}

This function takes two parameters $ChassisName and $SlotNumber. It then uses plink.exe to run the command “getslotname -i slotnumber” on the chassis and return the output.

Script Main

#SCRIPT MAIN
clear
$Slots = @()
$ChassisNames | % {
	$Chassis = $_
	Write-Host "Getting information from $Chassis.."
	for ($i =1; $i -le 16; $i++) {
		$Slot = "" | select "Chassis","Slot #","Slot Name"
		$Slot.Chassis = $Chassis
		$Slot."Slot #" = $i
		$Slot."Slot Name" = Get-SlotName -ChassisName $Chassis -slotNumber $i
		$Slots += $Slot
	}
}
$Slots | Export-Csv $CSV -NoTypeInformation -Force

In the script main I start by looping through the array of chassis names $ChassisNames. As each chassis has 16 slots I then add a nested for loop to iterate over the integers 1-16. For each slot number 1-16 I create a custom object $Slot with the properties “Chassis”, “Slot #” and “Slot Name”. I use the Get-SlotName function to get the slot name value and assign it to the custom object along with the chassis and slot number values which I already have. I then add the $Slot object to the $Slots array. Finally the $Slots array is exported to CSV.
That’s it! I have copied in the full script below. I hope you find it useful. Enjoy!

################################################################################################
##Script:			Get-DellChassisSlots.ps1
##
##Description:		Gets an inventory of the slots in the given Dell blade chassis' and exports
#+					the information to a csv file. Needs plink.exe in order to run (download and
#+					place in the script directory). 
##Created by:		Noam Wajnman
##Creation Date:	April 09, 2014
################################################################################################
#FUNCTIONS
function Get-SlotName {
	param (
		$ChassisName,
		$slotNumber
	)
	$EXE = $plink    
		$arg1 = "-pw"
		$arg2 = "$password"
		$arg3 = "$username@$ChassisName"
		$arg4 = "getslotname -i $slotnumber"		
		$command = "$EXE $arg1 $arg2 $arg3 $arg4"
		$output = invoke-expression -Command $command
		return $output
}
#VARIABLES
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath #path to the directory in which the script is run.
$plink = "$dir\plink.exe" #path to plink.exe in the script directory
$CSV = "$dir\SlotNames.csv" #results will be exported to a csv file with this path
#Parameters
$username = "some_user" #username used to login to the chassis
$password = "some_password" #password used to login to the chassis
$ChassisNames = @("cmc01","cmc02","cmc03","cmc04","cmc05","cmc06") #add your chassis names or IPs in this array like shown.
#SCRIPT MAIN
clear
$Slots = @()
$ChassisNames | % {
	$Chassis = $_
	Write-Host "Getting information from $Chassis.."
	for ($i =1; $i -le 16; $i++) {
		$Slot = "" | select "Chassis","Slot #","Slot Name"
		$Slot.Chassis = $Chassis
		$Slot."Slot #" = $i
		$Slot."Slot Name" = Get-SlotName -ChassisName $Chassis -slotNumber $i
		$Slots += $Slot
	}
}
$Slots | Export-Csv $CSV -NoTypeInformation -Force

Get HBA device info from remote servers and export to CSV

Standard

If you work with SAN storage and fibre channel adapters it can be very useful to get an overview of all your HBAs (host bus adapters) on your servers. This script uses WMI to get HBA info like WWN, driver, version, model etc. from remote servers and then export it to a CSV file. You will then have a consolidated view of all your HBA devices with detailed information about them.
You will need to create the file servers.txt in the script directory and enter the names (one per line) of the servers you want to get the info from.
I have divided this script into three sections variables, functions and script main. I will now briefly explain how I created each section.

Variables

#VARIABLES
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath #path to the directory in which the script is run.
$servers = @(gc "$dir\servers.txt") #create servers.txt in the script directory and enter the names of servers you wish to query for HBA info.
$CSV = "$dir\HBAs.csv" #results will be exported to a csv file with this path

$servers is an array of server names populated by running Get-Content on the file servers.txt. $CSV is the path of the CSV file which will be created at the end of the script run. Both objects $servers and $CSV are defined using the object $dir which always points to the directory which the script was started in. This is practical as it allows me to copy and move the script around without having to change any paths.

Functions

1. Function Get-HBAInfo

#FUNCTIONS
function Get-HBAInfo {
	[CmdletBinding()]
	[OutputType([System.String])]
	param(  
		[parameter(ValueFromPipeline = $true)]$server  
	)	
	process {
		$WMI = Get-WmiObject -class MSFC_FCAdapterHBAAttributes -namespace "root\WMI" -computername $server		
		$WMI | % {
			$HBA = "" | select "server","WWN","DriverName","DriverVersion","FirmwareVersion","Model","ModelDescription"
			$HBA.server = $server
			$HBA.WWN = (($_.NodeWWN) | % {"{0:x}" -f $_}) -join ":"				
			$HBA.DriverName       = $_.DriverName  
			$HBA.DriverVersion    = $_.DriverVersion  
			$HBA.FirmwareVersion  = $_.FirmwareVersion  
			$HBA.Model            = $_.Model  
			$HBA.ModelDescription = $_.ModelDescription
			$HBA
		}			
	}	
}

This function takes a single parameter $server and runs a WMI query on it to get the HBA information. For each HBA device found on the server A custom object called $HBA is created and returned. The function can take input from the pipeline which is practical as you can simply pass the server name to the function using another script or cmdlet if you want.

Script Main

#SCRIPT MAIN
clear
$HBAs = @($servers | Get-HBAInfo)
$HBAs | Export-Csv $CSV -NoTypeInformation -Force

The script main is very simple consisting of only two lines. First I use the Get-HBAInfo function to get the HBA information from the given servers. Then, in the second line, the results are exported to CSV.

I have copied in the full script below. I hope you find it useful. Enjoy!!

################################################################################################
##Script:			Get-HBAInfo.ps1
##
##Description:		Gets information about HBAs on the given servers using WMI and exports it to 
#+					CSV. Remember to create the file servers.txt in the script directory and
#+					enter the names (one per line) of the servers you want to get the info from.
##Created by:		Noam Wajnman
##Creation Date:	February 28, 2013
##Updated:			April 08, 2014
################################################################################################
#FUNCTIONS
function Get-HBAInfo {
	[CmdletBinding()]
	[OutputType([System.String])]
	param(  
		[parameter(ValueFromPipeline = $true)]$server  
	)	
	process {
		$WMI = Get-WmiObject -class MSFC_FCAdapterHBAAttributes -namespace "root\WMI" -computername $server		
		$WMI | % {
			$HBA = "" | select "server","WWN","DriverName","DriverVersion","FirmwareVersion","Model","ModelDescription"
			$HBA.server = $server
			$HBA.WWN = (($_.NodeWWN) | % {"{0:x}" -f $_}) -join ":"				
			$HBA.DriverName       = $_.DriverName  
			$HBA.DriverVersion    = $_.DriverVersion  
			$HBA.FirmwareVersion  = $_.FirmwareVersion  
			$HBA.Model            = $_.Model  
			$HBA.ModelDescription = $_.ModelDescription
			$HBA
		}			
	}	
}
#VARIABLES
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath #path to the directory in which the script is run.
$servers = @(gc "$dir\servers.txt") #create servers.txt in the script directory and enter the names of servers you wish to query for HBA info.
$CSV = "$dir\HBAs.csv" #results will be exported to a csv file with this path
#SCRIPT MAIN
clear
$HBAs = @($servers | Get-HBAInfo)
$HBAs | Export-Csv $CSV -NoTypeInformation -Force

Powershell – Get DNS A records and export to CSV

Standard

When managing and cleaning up your IP addresses/ranges it can be very useful to get some lists of the records you have in your DNS zones. Here’s a simple script which gets the IP addresses/hostnames of the given DNS zones and exports the results to CSV.
The script is split into two parts Variables and script main. I will walk through and explain both parts below.

Variables

#VARIABLES
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
$CSV = "$dir\DNS_A_records.csv"
#parameters
$DNSServer = "Some_DNS_server"
$Zone1 = "myzone.local"
$Zone2 = "me.myzone.local"

I use the $dir object in the paths of my scripts as this object always points to the directory which the script has been run from. This is practical as it allows you to move/copy the script around without having to change any paths. $CSV is the path to the CSV file which will be created at the end of the script run.
Remember to fill out the parameters section before you run the script! $DNSServer is the name of your DNS server. $Zone1, $Zone2… etc are the names of the DNS zones which you want to get A records from. If you have more than 2 zones to get A records from then just add more objects to match the number of zones you need and add the zone names.

Script Main

#SCRIPT MAIN
clear
$DNS_Zones = @()
$DNS_Zones += $Zone1
$DNS_Zones += $Zone2
$hosts = @()
$DNS_Zones | % {
	$zone = $_
	Write-Host "Getting DNS A records from $zone"	
	$DNS_A_records = @(Get-WmiObject -Class MicrosoftDNS_AType -NameSpace Root\MicrosoftDNS -ComputerName $DNSServer -Filter "ContainerName = `'$zone`'")
	$DNS_A_records | % {
		$hostA = "" | select "hostname","IPAddress"
		$hostA.hostname = $_.OwnerName
		$hostA.IPAddress = $_.IPAddress
		$hosts += $hostA
	}
}
$hosts = $hosts | Sort-Object @{Expression={[Version]$_.IPAddress}}
$hosts | Export-Csv $CSV -NoTypeInformation -Force

In the script main I first create the array $DNS_Zones which will hold the different zone names. Then the zone names ($Zone1, $Zone2… etc.) are added to the array. If you created more than two zone objects in the variables section you must add them here too.
I now create the $hosts array which will hold the records we will wish export later. The next thing that happens is that we loop through the $DNS_Zones array. For each DNS Zone we get all A records using WMI and for each of these, a custom object with the properties hostname and IPAddress is created and added to the $hosts array.
I then sort the $hosts array by IP Address using the following code:
$hosts | Sort-Object @{Expression={[Version]$_.IPAddress}}
The @{Expression} argument allows you to add the [version] type declaration on the IPAddress property on the array elements/objects which in turn enables you to easily sort the IPs.
Finally the $hosts array is exported to CSV using the great Export-CSV powershell cmdlet.
I have copied in the full script below.I hope you find it useful. Enjoy!

################################################################################################
##Script:			Get-DNS_A_Records.ps1
##
##Description:		Gets all DNS A records from a given DNS server and exports the information 
#+					to a CSV file.
##Created by:		Noam Wajnman
##Creation Date:	April 07, 2014
################################################################################################
#VARIABLES
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
$CSV = "$dir\DNS_A_records.csv"
#parameters
$DNSServer = "Some_DNS_server"
$Zone1 = "myzone.local"
$Zone2 = "me.myzone.local"
#SCRIPT MAIN
clear
$DNS_Zones = @()
$DNS_Zones += $Zone1
$DNS_Zones += $Zone2
$hosts = @()
$DNS_Zones | % {
	$zone = $_
	Write-Host "Getting DNS A records from $zone"	
	$DNS_A_records = @(Get-WmiObject -Class MicrosoftDNS_AType -NameSpace Root\MicrosoftDNS -ComputerName $DNSServer -Filter "ContainerName = `'$zone`'")
	$DNS_A_records | % {
		$hostA = "" | select "hostname","IPAddress"
		$hostA.hostname = $_.OwnerName
		$hostA.IPAddress = $_.IPAddress
		$hosts += $hostA
	}
}
$hosts = $hosts | Sort-Object @{Expression={[Version]$_.IPAddress}}
$hosts | Export-Csv $CSV -NoTypeInformation -Force