Thursday, August 15, 2013

First Script - Computer Hardware Inventory Script that helps with SQL Licensing

Here is my first Script!
It is based on PowerShell.

It queries each computer from a text file (one computer line by line) and gathers some hardware information like number of CPUs, physical memory, model etc and logs it to a file. The script will also search for SQL instances and will gather the details on each SQL instance setup on the system as well.

This might come in handy during a licensing true-up...

<#
Title: GetHardwareInfo-forLicensing.ps1
Description: Gathers OS, CPU, Memory and SQL Information from remote systems
Comments: None
Author: Daniel Sarfati
Original Date: August 15, 2013
Modified Date: 
Version: 1.4
#>
Add-type -AssemblyName "System.Windows.Forms"
$HKLM = [UInt32] "0x80000002"
#Custom Ping function which returns 0 if ping fails, 1 if ping passes
Function Ping($computername)
{
 $query = "select * from win32_pingstatus where address = '"   $computername   "'"
 $wmi = get-wmiobject -query $query
 if ($($wmi.statuscode) -eq $null)
  {
  $rtnvalue = $($wmi.PrimaryAddressResolutionStatus)
  }
 else {$rtnvalue = $($wmi.statuscode)}
 if ( $rtnvalue -eq 0 ) {$true}
 else {$false}
 
}
#Custom WMI Test function, just in case ping is working but WMI is down, PS shouldn't throw an error
Function WMIConnectionTest($computername)
{
 $wmiClass = "Win32_OperatingSystem"
 if ((Get-WmiObject -ComputerName $computerName win32_operatingsystem -ErrorAction silentlycontinue)) 
  { return $true } 
 else { return $false } 
}

#Main Code of the program
Function Get-HardwareDetails($ComputerName)
{
 #Create a WMI Connection to the destination computer's Win32_OperatingSystem namespace
 $OSWMI = Get-WmiObject -ComputerName $ComputerName win32_operatingsystem
 #Get some OS Information
 $OperatingSystem = $OSWMI.Caption
 $ServicePack = $OSWMI.ServicePackMajorVersion
 #Close WMI Win32_OperatingSystem connection
 $OSWMI = $null
 #Create a WMI connection to the destination computer's Win32_Processor namespace
 $ProcWMI = Get-WmiObject -ComputerName $ComputerName Win32_Processor
 #Get some Processor information, including CPU architecture x86/x64, number of cores, number of procs, etc
 $Architecture = @($ProcWMI.AddressWidth)[0]
 $CPUDescription = @($ProcWMI.Name)[0]
 $Cores = @($ProcWMI.NumberOfCores)[0]
 $ProcessorCount = @($ProcWMI.NumberOfLogicalProcessors).count
 #Close WMI Win32_OperatingSystem connection
 $ProcWMI = $null
 #Create a WMI Connection to the destination computer's Win32_OperatingSystem namespace
 $ComputerWMI = Get-WmiObject -ComputerName $ComputerName Win32_ComputerSystem
 #Get some memory and computer model information
 $TotalMemory = $ComputerWMI.TotalPhysicalMemory
 $Manufacturer = $ComputerWMI.Manufacturer
 $Model = $ComputerWMI.Model
 $ComputerWMI = $null
 #$ComputerIPs = @(([System.Net.Dns]::GetHostAddresses($ComputerName)))
 #This only works with Windows 2003 and higher
 #$SQLInstances = @(Get-WmiObject -ComputerName $computername -query "select * from win32_service where Name LIKE 'MSSQL%' and Description LIKE '%transaction%'").Count
 #Get a list of all services, for Windows 2000 Compatibility, WQL doesn't have the like operand
 $AllServices = Get-WmiObject -ComputerName $computername -query "select * from win32_service"
 #Filter for SQL Transaction service instances
 $SQLInstances = @($AllServices | where-object {$_.name -like "*MSSQL*" -and $_.description -like "*transaction*"}).count 
 #if any SQL Transaction services exists
 if ($SQLInstances -gt 0)
 {
  #Create an array of SQL service instances to investigate
  $SQLRoot = @($AllServices | where-object {$_.name -like "*MSSQL*" -and $_.description -like "*transaction*"}) | Select-Object pathname
  foreach ($SQL in $SQLRoot)
  {
   $binPath=$SQL.pathname.ToString()
   #Get the path of the binn folder from the service path, replace the : with $ and remove the quotes from the path string
   $LocalSqlInstPath=$binPath.Substring(0,$binPath.IndexOf("Binn")) -replace ":", "$" -replace "`"","" #"
   #Build the folder path, as we will connect to the remote server through UNC
   $sqlInstPath = '\\'   $ComputerName  '\'   $LocalSqlInstPath
   #Get the information and save it to the array
   $thisInstance = GetSQLInformation $sqlInstPath
   $Script:AllSQLInstances =@($thisInstance)
  }
 }
 #Close the services query
 $AllServices = $null
 #Build the object we will send back for easier CSV exports and return it
 $CompOSObj = New-Object PSObject
 Add-Member -InputObject $CompOSObj -MemberType NoteProperty -Name ComputerName -Value $ComputerName
 Add-Member -InputObject $CompOSObj -MemberType NoteProperty -Name Connection -Value $true
 #Add-Member -InputObject $CompOSObj -MemberType NoteProperty -Name ComputerIP -Value $ComputerIP
 Add-Member -InputObject $CompOSObj -MemberType NoteProperty -Name OperatingSystem -Value $OperatingSystem
 Add-Member -InputObject $CompOSObj -MemberType NoteProperty -Name ServicePack -Value $ServicePack
 Add-Member -InputObject $CompOSObj -MemberType NoteProperty -Name Architecture -Value $Architecture
 Add-Member -InputObject $CompOSObj -MemberType NoteProperty -Name CPUDescription -Value $CPUDescription
 Add-Member -InputObject $CompOSObj -MemberType NoteProperty -Name NumberOfCores -Value $Cores
 Add-Member -InputObject $CompOSObj -MemberType NoteProperty -Name NumberOfProcessors -Value $ProcessorCount
 Add-Member -InputObject $CompOSObj -MemberType NoteProperty -Name TotalMemory -Value $TotalMemory
 Add-Member -InputObject $CompOSObj -MemberType NoteProperty -Name ComputerManufacturer -Value $Manufacturer
 Add-Member -InputObject $CompOSObj -MemberType NoteProperty -Name ComputerModel -Value $Model
 Add-Member -InputObject $CompOSObj -MemberType NoteProperty -Name SQLInstances -Value $SQLInstances
 Return $CompOSObj
}

Function GetSQLInformation($sqlInstPath)
{
 #Build the sql log path
 $SqlLog=  $sqlInstPath   'Log\Errorlog'
 #Open the Errorlog file, and find the Edition string
 $SqlLogFile = get-content $sqllog
 $Edition = ($SqlLogFile | select-string Edition).ToString()
 $Edition = $Edition.Trim()
 $Version = $SqlLogFile[0].ToString()
 #With the Errorlog file open, and find Microsoft string, this will tell us what SQL version it is
 $SQLVersion = $Version.Substring($Version.IndexOF("Microsoft"))
 #Build the object we will send back for easier CSV exports and return it
 $SQLInstanceObj = New-Object PSObject
 Add-Member -InputObject $SQLInstanceObj -MemberType NoteProperty -Name ComputerName -Value $ComputerName
 Add-Member -InputObject $SQLInstanceObj -MemberType NoteProperty -Name SQLEdition -Value $Edition
 Add-Member -InputObject $SQLInstanceObj -MemberType NoteProperty -Name SQLVersion -Value $SQLVersion
 $SqlLogFile=$null
 Return $SQLInstanceObj
}

#Open a file dialog box
$fd = new-object System.Windows.Forms.OpenFileDialog
$fd.title = %u201CSelect Input File%u201D
$fd.Filter = %u201CText Files (*.txt) | *.txt%u201D
$fd.ShowHelp = $true
$fd.ShowDialog()

#$InputFile = Read-Host -Prompt "Please enter the name of the file you'd like to scan for" -
$ComputerList = Get-Content -Path $fd.FileName
forEach ($ComputerName in $ComputerList)
{
 #If the system is pingable and passes WMI tests, connect to it run the main function in the program, save that output to array a
 if (Ping($ComputerName) -eq $true -and if (WMIConnectionTest($ComputerName) -eq $true))
 {
  $a =@(Get-HardwareDetails $ComputerName)
 }
 #if the system can't connect, build an object and save it to array a
 Else
 {
  $CantConnectObj = New-Object PSObject 
  Add-Member -InputObject $CantConnectObj -MemberType NoteProperty -Name ComputerName -Value $ComputerName
  Add-Member -InputObject $CantConnectObj -MemberType NoteProperty -Name Connection -Value $false
  #Add-Member -InputObject $CantConnectObj -MemberType NoteProperty -Name ComputerIP -Value $ComputerIP
  Add-Member -InputObject $CantConnectObj -MemberType NoteProperty -Name OperatingSystem -Value $false
  Add-Member -InputObject $CantConnectObj -MemberType NoteProperty -Name ServicePack -Value $false
  Add-Member -InputObject $CantConnectObj -MemberType NoteProperty -Name Architecture -Value $false
  Add-Member -InputObject $CantConnectObj -MemberType NoteProperty -Name CPUDescription -Value $false
  Add-Member -InputObject $CantConnectObj -MemberType NoteProperty -Name NumberOfCores -Value $false
  Add-Member -InputObject $CantConnectObj -MemberType NoteProperty -Name NumberOfProcessors -Value $false
  Add-Member -InputObject $CantConnectObj -MemberType NoteProperty -Name TotalMemory -Value $false
  Add-Member -InputObject $CantConnectObj -MemberType NoteProperty -Name ComputerManufacturer -Value $false
  Add-Member -InputObject $CantConnectObj -MemberType NoteProperty -Name ComputerModel -Value $false
  Add-Member -InputObject $CantConnectObj -MemberType NoteProperty -Name SQLInstances -Value $false
  $a =@($CantConnectObj)
 }
}

$a | Export-Csv -Path ".\Export-List-HardwareDetails.csv" -notypeinformation
$Script:AllSQLInstances | Export-Csv -Path ".\Export-List-SQLInstanceDeatils.csv" -notypeinformation

Tuesday, August 13, 2013

Welcome

Welcome to my Blog!

I write a lot of Windows focused system administration scripts at work, and decided I should probably start a blog about it.

My strongest language is VBScript, although I have done some coding with PHP, ASP, ASP.NET, Java. My latest passion is with PowerShell, so I hope to build a nice little script repository between PowerShell and VBScript on this blog.

I'm very passionate about IT, and am well versed with MS Exchange, Citrix XenApp, Windows Servers, Active Directory, and VMware. In addition I have a working knowledge of Linux (my latest distro I'm using is CentOS, have used Ubuntu, Red Hat and FreeBSD in the past), though my shell scripting skills aren't quite there yet. I also love Android devices and am a very active member on a number of android related forums.