Wednesday, April 1, 2009

Powershell-GUI: EventLog Manager

Problem Statement: Recently. there was a requirement for me to clear or save event logs of different systems on the network. The number of systems in the network were at least 10 and the requirement demanded that I had to Save Event logs or Clear Event Logs on all/selected servers (separated by commas), in one go!



Now here's what I came up with:






Script:
Function Main{
[reflection.assembly]::LoadWithPartialName( "System.Windows.Forms")
$form = New-Object Windows.Forms.Form $form.text = "Event Log Manager"
$form.height = 400
$label_logname = New-Object Windows.Forms.Label
$label_logname.Location = New-Object Drawing.Point 50,30
$label_logname.Size = New-Object Drawing.Point 200,30
$label_logname.text = "Enter the EventLog Name"
$combo = new-object System.Windows.Forms.ComboBox
$combo.Location = new-object System.Drawing.Size(50,60)
$combo.Size = new-object System.Drawing.Size(200,15)
$combo.Items.Add("Enter EventLog") $combo.Items.Add("Application")
$combo.Items.Add("System")
$label_server = New-Object Windows.Forms.Label
$label_server.Location = New-Object Drawing.Point 50,110
$label_server.Size = New-Object Drawing.Point 200,30
$label_server.text = "Enter the Server Names separated by commas"
$combo1 = new-object System.Windows.Forms.ComboBox
$combo1.Location = new-object System.Drawing.Size(50,150)
$combo1.Size = new-object System.Drawing.Size(200,15)
$combo1.Items.Add("10.2.2.3")
$button = New-Object Windows.Forms.Button
$button.text = "Save EventLog"
$button.Location = New-Object Drawing.Point 50,200
$button.Size = New-Object Drawing.Point 200,25
$button1 = New-Object Windows.Forms.Button
$button1.text = "Clear EventLog"
$button1.Location = New-Object Drawing.Point 50,250
$button1.Size = New-Object Drawing.Point 200,25
$button2 = New-Object Windows.Forms.Button
$button2.text = "Quit..."
$button2.Location = New-Object Drawing.Point 50,300
$button2.Size = New-Object Drawing.Point 200,25
$button.add_click({ $form.hide()
SaveEvtLog $combo1.text $combo.text })
$button1.add_click({ $form.hide()
ClearEvtLog $combo1.text $combo.text })
$button2.add_click({ $form.dispose() })
$form.controls.add($button)
$form.controls.add($label_logname)
$form.controls.add($label_server)
$form.controls.add($button1)
$form.controls.add($button2)
$form.controls.add($combo)
$form.controls.add($combo1)
$form.ShowDialog()
}

Function SaveEvtLog {
param ($computer,$evtlog)
$servers = $computer.split(',')
foreach ($server in $servers) {
[reflection.assembly]::LoadWithPartialName( "System.Windows.Forms")
$form1 = New-Object Windows.Forms.Form $form1.height = 300 $form1.width = 300 $label2 = New-Object Windows.Forms.Label
$label2.Location = New-Object Drawing.Point 50,30
$label2.Size = New-Object Drawing.Point 200,90
$ALive=get-wmiobject win32_pingstatus -Filter "Address='$server'" Select-Object statuscode
if($ALive.statuscode -ne 0)
{ "Host $server is Unreachable...`n" out-file log.txt -append }
else { $filename = "Log_" + $evtlog + "_" + $server + ".evt"
if((Test-Path -path c:\$filename) -ne $False) { remove-item C:\$filename } wmic /node:"$server" nteventlog where "logfilename='$evtlog'" call backupeventlog "C:\$filename" out-file null
remove-item null
copy-item file://$server/c$/$filename C:\
remove-item file://$server/c$/$filename
$lbl_text = "EventLog copied at c:\$filename" out-file log.txt -append } }
$lbl = get-content log.txt
$label2.text = $lbl
$button4 = New-Object Windows.Forms.Button
$button4.text = "Back to Main..."
$button4.Location = New-Object Drawing.Point 50,180
$button4.Size = New-Object Drawing.Point 200,25 remove-item log.txt
$button4.add_click({ $form1.hide()
Main })
$form1.controls.add($label2)
$form1.controls.add($button4)
$form1.ShowDialog() }

Function ClearEvtLog {
param ($computer,$evtlog)
$servers = $computer.split(',')
foreach ($server in $servers) {
[reflection.assembly]::LoadWithPartialName( "System.Windows.Forms")
$form1 = New-Object Windows.Forms.Form
$form1.height = 300 $form1.width = 300
$label2 = New-Object Windows.Forms.Label
$label2.Location = New-Object Drawing.Point 50,30
$label2.Size = New-Object Drawing.Point 200,90
$ALive=get-wmiobject win32_pingstatus -Filter "Address='$server'" Select-Object statuscode
if($ALive.statuscode -ne 0)
{ "Host $server is Unreachable...`n" out-file evt.txt -append }
else { $logs = [System.Diagnostics.Eventlog]::GetEventLogs("$server")
$Applogs = $logswhere-object {$_.logdisplayname -eq "$evtlog" }
if($Applogs -ne $null)
{$Applogs.clear()
"$evtlog Event Log Cleared at $server `n" out-file evt.txt -append}
else {"Event log is already cleared or it doesnt exist `n" out-file evt.txt -append} } } $lbl = get-content evt.txt
$label2.text = $lbl
$button4 = New-Object Windows.Forms.Button
$button4.text = "Back to Main..."
$button4.Location = New-Object Drawing.Point 50,180
$button4.Size = New-Object Drawing.Point 200,25 remove-item evt.txt
$button4.add_click({ $form1.hide()
Main })
$form1.controls.add($label2)
$form1.controls.add($button4)
$form1.ShowDialog() }

Main



Hope this helps!! Let me know your comments...

PERL: Base64 Encoding

What is Base64: Base64 is MIME character tranafer encoding...Its like any other encoding that uses a-zA-Z0-9/+ (64 characters and = for padding) for converting the string...An important encoding format....Between, have you wondered if we could use a Base64 encoded string as a filename?? Think??

Here's a small PERL script that would help you in encoding and decoding the input string:

C0de:
#! /usr/bin/perl
use MIME::Base64;
print "Enter the Choice\n";
print "1. Encode to Base 64\n";
print "2. Decode from Base64\n";print "Enter the choice::";
my $choice=<STDIN>;
if($choice==1)
{ print "Please enter a string that is to be encoded:"; my $str=; my $encode=encode_base64($str); print "String ENCODED as:$encode"; }
if($choice==2)
{ print "Please enter a Base 64 string that is to be decoded:"; my $str=; my $decode=decode_base64($str); print "String DECODED as:$decode"; }

Hope this helps!!!

PowerShell: Script for getting the inventory details....

Hya!! After a long gap, I am here again...
This time I have come up with an utility that takes the details of your inventory.

Problem Statement: I have a lot of servers on my network and my manager comes and tell me, "Can you get me details like the total RAM, HDD, Manufacturer, Serial Number and ServerName of all these servers?? I need to report this to Infrastructure team! Please get this in 2 hours time!!" Sounds laborious..Isn't it??

Here's the script:

"IP`tHardDisk`tRAM`tSystemName`tManufacturer`tSerialNumber" out-file C:\Results.csv -append

Function HDDInfo { param($ip) $alldrives = get-wmiobject win32_logicaldisk -filter "DriveType=3" -computername $ip $HDD = 0 foreach ($i in $alldrives) { $HDD = $HDD + ($i.size)/(1gb) } $HDD }

Function RAMInfo { param($ip) $ram = get-wmiobject win32_ComputerSystem -computername $ip $RAM = ($ram.TotalPhysicalMemory)/(1gb) $RAM }

Function SystemName { param($ip) $bios = get-wmiobject win32_bios -computer $ip $bios.name }

Function Manufacturer { param($ip) $bios = get-wmiobject win32_bios -computer $ip $bios.manufacturer } Function SerialNumber { param($ip) $bios = get-wmiobject win32_bios -computer $ip $bios.SerialNumber }

$address = "10.2.2."
2..254 foreach-object { $ip = $address + $_
$ping = get-wmiobject win32_pingstatus -filter "Address = '$ip'" select-object statuscode
if($ping.statuscode -eq 0) { $HDD = HDDInfo $ip sleep 1 $RAM = RAMInfo $ip sleep 1 $SystemName = SystemName $ip $Manufacturer = Manufacturer $ip $SerialNumber = SerialNumber $ip
"$ip`t$HDD`t$RAM`t$SystemName`t$Manufacturer`t$SerialNumber" out-file C:\Results.csv -append } else { "$ip is Offline or Not Reachable.." out-file C:\Results.csv -append }
}


In this script, I assume all your systems on the network are in the IP range of 10.2.2.x and I am collecting the details of IPs: 10.2.2.2 - 10.2.2.254

Run the script, wait for 4-5 minutes and get the results in Results.csv file. :-)

Hope this helps!!

Friday, February 13, 2009

PowerShell: OS Statistics for a Remote Host

Here's a small PowerShell Script that would enable you to get the OS Statistics for a Host...
----------OS-Statistics.ps1------------------
Function Main {
# Load the Winforms assembly
[reflection.assembly]::LoadWithPartialName( "System.Windows.Forms")
# Create the form
$form = New-Object Windows.Forms.Form
#Set the dialog title
$form.text = "OS Statistics"














# Create the label control and set text, size and location
$label = New-Object Windows.Forms.Label
$label.Location = New-Object Drawing.Point 50,50
$label.Size = New-Object Drawing.Point 200,15
$label.text = "Enter Hostname"

$combo = new-object System.Windows.Forms.ComboBox
$combo.Location = new-object System.Drawing.Size(50,80)
$combo.Size = new-object System.Drawing.Size(200,25)
$combo.Items.Add("ComputerName / IP")
$combo.Items.Add("192.168.219.")
$combo.Items.Add("127.0.0.1")

# Create Button and set text and location
$button = New-Object Windows.Forms.Button
$button.text = "Get OS Statistics"
$button.Location = New-Object Drawing.Point 50,130
$button.Size = New-Object Drawing.Point 200,25

$button3 = New-Object Windows.Forms.Button
$button3.text = "Quit...."
$button3.Location = New-Object Drawing.Point 50,180
$button3.Size = New-Object Drawing.Point 200,25

# Set up event handler to extarct text from TextBox and display it on the Label.
$button.add_click({ NewForm $combo.text })
$button3.add_click({ $form.dispose() })

# Add the controls to the Form
$form.controls.add($button)
$form.controls.add($button3)
$form.controls.add($label)
$form.controls.add($combo)

# Display the dialog
$form.ShowDialog()
}

Function NewForm
{
Param ($ip)

$ALive=get-wmiobject win32_pingstatus -Filter "Address='$ip'" Select-Object statuscode
if($ALive.statuscode -ne 0)
{
[reflection.assembly]::LoadWithPartialName( "System.Windows.Forms")
$form1 = New-Object Windows.Forms.Form
$form1.height = 180
$label1 = New-Object Windows.Forms.Label
$label1.Location = New-Object Drawing.Point 50,10
$label1.Size = New-Object Drawing.Point 200,50
$label1.text = "Sorry!! The Host is Unreachable `n`n Check if" + $ip + " is Online..."
$button2 = New-Object Windows.Forms.Button
$button2.text = "Click to Get Back"
$button2.Location = New-Object Drawing.Point 50,80
$button2.Size = New-Object Drawing.Point 200,25
$button2.add_click({
$form1.dispose()
})
$form1.controls.add($button2)
$form1.controls.add($label1)
$form1.showdialog()
}
























else{
[reflection.assembly]::LoadWithPartialName( "System.Windows.Forms")
$form1 = New-Object Windows.Forms.Form
$form1.height = 600
$form1.width = 300
$label1 = New-Object Windows.Forms.Label
$label1.Location = New-Object Drawing.Point 50,10
$label1.Size = New-Object Drawing.Point 200,600
$perf= get-wmiobject Win32_PerfFormattedData_PerfOS_System -computer $ip
$uptime=$perf.SystemUpTime/3600
$freedisk = get-wmiobject win32_logicaldisk -filter "DriveType=3" -computer $ip foreach-object {"`n{0} {1}" -f $_.DeviceID,($_.freespace/1gb)}
$result = "`n--------------------------------------------`n" + "OS STATISTICS :: " + $ip + "`n--------------------------------------------`n`n" + "Processes:`t" + $perf.Processes + "`n`nThreads:`t" + $perf.Threads + "`n`nSystem UpTime In hours:`t" + $uptime + "`n`nAlignment Fixups/sec:`t" + $perf.AlignmentFixupsPersec + "`n`nContext Switches/sec:`t" + $perf.ContextSwitchesPersec + "`n`nException Dispatches/sec:`t" + $perf.ExceptionDispatchesPersec + "`n`nFile Control Bytes/sec:`t" + $perf.FileControlBytesPersec + "`n`nFile Control Operations/sec:`t" + $perf.FileControlOperationsPersec + "`n`nFile Data OperationsPersec:`t" + $perf.FileDataOperationsPersec+ "`n`nFile Read Bytes/sec:`t" + $perf.FileReadBytesPersec + "`n`nFile Read Operations/sec:`t" + $perf.FileReadOperationsPersec + "`n`nFile Write Bytes/sec:`t"+ $perf.FileWriteBytesPersec +"`n`nFile Write Operations/sec:`t" + $perf.FileWriteOperationsPersec + "`n`nSystem Calls/sec:`t"+ $perf.SystemCallsPersec + "`n`nFree Disk Space in GB:`n" + $freedisk
$label1.text = "$result"
$button1 = New-Object Windows.Forms.Button
$button1.text = "Click to Get Back"
$button1.Location = New-Object Drawing.Point 50,520
$button1.Size = New-Object Drawing.Point 200,25
$button1.add_click({
$form1.dispose()
})
$form1.controls.add($button1)
$form1.controls.add($label1)
$form1.showdialog()
}

}

Main

Monday, February 9, 2009

PowerShell<->Perl: Reading UNICODE files

Problem Statement:
Recently, I faced a tricky situation at work. I had a CSV file generated out of a PowerShell script. I was trying to read the CSV file and generate a graph using Perl TK module. To my surprise, no value from the CSV file got plotted on the graph! Why would this happen?

Reason:

After some tussle, I found that, this was because PowerShell generated the CSV file in a UNICODE format. PERL opens the Unicode file but can’t recognize the content. This is because “Unicode format is not a character encoding”. Hence the issue!

Resolution:
In such cases, one needs to open the Unicode files using any other Perl supported encoding format. Say, we open the file as:
Open (FH, “<:utf-8”, “filepath”);
OR
Open (FH, “<:encoding(utf-8)”, “filepath”);

Thus, Unicode text files are read exactly the same way that other files are read: by specifying a text encoding.

Wednesday, February 4, 2009

PowerShell: Ensure Successful Build Installation

Here’s one problem statement. Let’s say, you have an application installed on multiple systems i.e.; more than 1 system. And you need to know, the files that get installed on these systems once you have installed the application. To top it, the application gets installed on either C: or D: How do you do this? In PowerShell it’s easy.

Code:
Disclaimer: I’m not responsible for any inadvertent consequences you face after running this script.
Below, ‘test’ is the folder where the application gets installed.
FileName: Files-AfterInstall.ps1

foreach ($computer in $args)
{
"-----------------" | out-file BuildInstalled.txt -append
"$computer" | out-file BuildInstalled.txt -append
"-----------------" | out-file BuildInstalled.txt -append

if ((Test-Path -path \\$computer\c$\test) -ne $True)
{}
else
{
get-childitem -recurse \\$computer\c$\test -include *.* | foreach-object {$_.FullName} | out-file BuildInstalled.txt -append
}

if ((Test-Path -path \\$computer\d$\test) -ne $True)
{}
else
{
get-childitem -recurse \\$computer\d$\test -include *.* | foreach-object {$_.FullName} | out-file BuildInstalled.txt -append
}

}

Run as: .\Files-AfterInstall.ps1 system1 system2 (system1, system2 ... system n are the systems where build is installed)

Output:
As output, you would receive a file named BuildInstalled.txt which gets created where the script is running. This file would contain the full path of the files that get installed.

Monday, February 2, 2009

PowerShell: GetFileVersion Information as Build Verification Test

As a Dev or QA, we often are worried about the FileVersion information being present on the binaries that we develop and that are shipped to customers. Here’s a small PowerShell script that would help in finding whether we have the fileversion data on all the binaries or not (Currently it checks for .exe and .dll files). Those who know a bit of programming would definitely be able to customize the script as per their requirement.

Please run this carefully. I’m not responsible for any inadvertent consequences.

$files = get-childitem $args -recurse -include *.dll,*.exe
if($files -eq $null)
{
Write-Host "No Exe or dll files present in the folder";
}
else
{
foreach ($i in $files)
{
$ver = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($i).FileVersion
if($ver -eq $null)
{
$i.FullName Out-File NoVersion.txt -append
}
else
{
"{0}`t{1}"-f $i.FullName, [System.Diagnostics.FileVersionInfo]::GetVersionInfo($i).FileVersion out-file Version.xls -append
}
}
}

Run as:
If the above code is copied in a file named: Build-FileVersion-Info.ps1
.\ Build-FileVersion-Info.ps1 FolderName FolderName - is the build folder

Output:
1. We have a file called Version.xls as output that would give the filepaths and fileversion of all the binaries that have fileversion information.
2. Output is also a Noversion.txt file that would give the filepaths of the files that have no fileversion.
3. Output can also be No Exe or dll files present in the folder, which should be self explanatory.

Hope this was useful!!