Powershell – Get OS install date from remote servers

Standard

Here’s a handy little script to get the OS install date from your servers and export all the information to a CSV file.
The script is split into three sections variables, functions and script main. The script loops through all servers in the “servers.txt” file (must be placed in the same directory as the script) and gets the OS install date using WMI.

Variables

Below is a short walkthrough of the variables section of the script.

#VARIABLES
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
$servers = @(gc "$dir\servers.txt")

The first two lines of code –
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath

are really practical as it gives me an object $dir which always points to where the script was run. This makes the script more robust as I can freely move the script around and run it from many locations without having to change any paths in the script.
$servers is an array populated by running Get-Content on the servers.txt file.

Functions

The script uses two functions to do most of the work.
1. Function Get-OSInstallDate

function Get-OSInstallDate {
	param (
		$computerName = $Env:COMPUTERNAME
	)
	[datetime]$OSInstallDate = ([WMI]'').ConvertToDateTime((Get-WmiObject Win32_OperatingSystem -ComputerName $computerName).InstallDate)
	if ($?) {
		return $OSInstallDate
	}
}

This function takes a parameter $computerName and uses the WMI class Win32_OperatingSystem to get the OS install date. The OS install date is also converted so we can return it as a neat datetime object.
2. Function ExportSpecial-CSV

function ExportSpecial-CSV {
	param (
		$inputArray,
		$InfoType		
		)	
    $inputArray | Export-Csv "$dir\$InfoType.csv" -noTypeInformation -Force  
}

This function is extremely simple. It takes an array as input and exports it to CSV in the script directory.

Script Main

$OSInstallDates = @()
$servers | % {
	$date = Get-OSInstallDate -computerName $_
	if ($date) {
		$OSInstallDate = "" | Select "Computer","OSInstallDate"
		$OSInstallDate.Computer = $_
		$OSInstallDate.OSInstallDate = $date
		$OSInstallDates += $OSInstallDate
	}
}
ExportSpecial-CSV -inputArray $OSInstallDates -InfoType "OS_Install_dates"

In the script main I loop through $servers and run the Get-OSInstallDate function to get the info. If the OS install date was retrieved successfully A custom object $OSInstallDate with two properties “Computer” and “OSInstallDate” is created and then added to the array $OSInstallDates. After the foreach loop I use the function ExportSpecial-CSV to export the array $OSInstallDates to the script directory.
That’s it!
Below is the full script. Good luck!

##################################################################################################################
##Script:			Get-OSInstallDate.ps1
##Description: 		Script uses WMI to get the OS install date from the servers listed in "servers.txt" and then 
#+					exports the information to CSV.
##Usage:			Create a file "servers.txt" in the script directory and put in the names of the servers to query.
#+					Run the script and it will create a file called "OS_Install_Dates.csv" in the same directory.
##Created by:		Noam Wajnman
##Creation Date:	February 5, 2014
###################################################################################################################
#FUNCTIONS
function Get-OSInstallDate {
	param (
		$computerName = $Env:COMPUTERNAME
	)
	[datetime]$OSInstallDate = ([WMI]'').ConvertToDateTime((Get-WmiObject Win32_OperatingSystem -ComputerName $computerName).InstallDate)
	if ($?) {
		return $OSInstallDate
	}
}
function ExportSpecial-CSV {
	param (
		$inputArray,
		$InfoType		
		)	
    $inputArray | Export-Csv "$dir\$InfoType.csv" -noTypeINformation -Force  
}
#VARIABLES
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
$servers = @(gc "$dir\servers.txt")
#SCRIPT MAIN
$OSInstallDates = @()
$servers | % {
	$date = Get-OSInstallDate -computerName $_
	if ($date) {
		$OSInstallDate = "" | Select "Computer","OSInstallDate"
		$OSInstallDate.Computer = $_
		$OSInstallDate.OSInstallDate = $date
		$OSInstallDates += $OSInstallDate
	}
}
ExportSpecial-CSV -inputArray $OSInstallDates -InfoType "OS_Install_dates"

Powershell – Set static DNS on remote servers

Standard

Recently I was tasked with the job of changing the DNS search order on all the windows servers we use in my company. Since I didn’t want to change it manually by going into the TCP/IP settings of the NIC on each server I decided to write a script to help me do this.

I am working in a sensitive production environment so I needed to not only change the settings but also check that the changes were made successfully on all servers. To accomplish this I added some functionality to the script to confirm that the changes were made and write all the information to a log file. This log file could then be reviewed later for errors.

I have built the script in three different sections – variables, functions and script main. To begin with I will quickly explain the variables section.

VARIABLES

I don’t like working with too many absolute paths in my scripts because one needs to change them if they are moved to another computer or location. Therefore I use the following code so I always have an object pointing to the script directory.

$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath

When used, $dir will always point to the directory where the script was run. $log_dir specifies the path to a directory names /logs which will be used later on.

The script takes input from a file called “servers.txt” which must be placed in the script directory. $servers is an array created and populated by running Get-Content on “servers.txt”. The parameters section contains the $dns1, $dns2, $dns3 objects which will be set on the servers listed in “servers.txt” – remember to fill these out with the appropriate values before running the script.

#VARIABLES
$DebugPreference = "continue"
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
$log_dir = "$dir\logs"
$servers = @(gc "$dir\servers.txt")
#parameters - Add the desired DNS servers below
[string]$dns1 = "192.168.1.2"
[string]$dns2 = "192.168.1.3"
[string]$dns3 = "192.168.1.4"

That covers the variables section – now to the functions. The script is built on four different functions which I will go over now.

FUNCTIONS

1. Function Create-Log

function Create-Log {
	$time = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
	$logFilePath = "$log_dir\SetStaticDNS_$time.log"
	New-Item -ItemType File $logFilePath -Force
}
 

This little function simply creates a logfile in $dir\logs\ which will be used by the script to record the results of attempting to change the DNS settings on each server.

2. Function Write-ToLog

function Write-ToLog {
	param (
		[string]$message
		)
	$time = Get-Date
	$logEntryStr = "$time`t" + $message
	$logEntryStr | Out-File -Append $logFilePath -Width 400
}
 

Write-ToLog takes a parameter “message” and appends it to the log file with a time stamp

3. Get-ActiveNicIP

function Get-ActiveNicIP {
 	param (
 		[Parameter(Mandatory=$true)][string]$computer
 	)
 	Write-ToLog -message "Getting IP of 'active' interface on $computer ..."
 	$conx = Test-Connection -ComputerName $computer -Count 1
 	$ActiveIP = $conx.IPV4Address.IPAddressToString
 	Write-ToLog -message "Active IP on $computer is $ActiveIP"
 	return $ActiveIP
}

Some servers can have several NICs/Teams in use and I wanted to make sure that I only change the DNS settings on the NIC which answers to the hostname of the server. Get-ActiveNicIP simply pings the server given as the parameter “computer” and returns the IP which answers.

4. Function Set-StaticDNS

function Set-StaticDNS {
	param (
		[Parameter(Mandatory=$true)][string]$computer,
		[Parameter(Mandatory=$true)][string]$ActiveIP
	)
	Write-ToLog -message "Attempting to set DNS search order on computer 	$computer on the interface with the IP $ActiveIP"
	#get dns info via WMI
	$wmi = Get-WmiObject win32_networkadapterconfiguration -filter "ipenabled = 'true'" -ComputerName $computer | ? { $_.IPAddress -match $ActiveIP }
	#set dns search order via WMI
	$wmi.SetDNSServerSearchOrder($DnsSearchOrder)
	#confirm that dns search order was set to desired value.
	$StrdnsSearchOrder = $dnsSearchOrder | Out-String
	$wmi2 = Get-WmiObject win32_networkadapterconfiguration -filter "ipenabled = 'true'" -ComputerName $computer | ? { $_.IPAddress -match $ActiveIP }
	$StrWmiDnsSearchOrder = $wmi2.DNSServerSearchOrder | Out-String
	if ($StrWmiDnsSearchOrder -eq $StrdnsSearchOrder) {
	Write-ToLog -message "Setting the DNS search order was successful. Value is now $dnsSearchOrder"
	}
	else {
		Write-ToLog -message "Error - Setting the DNS search order failed!"
	}
}

The Set-Static DNS function takes a computer and an IP as parameters and then uses WMI to change the DNS search order on the NIC.
That covers the functions – now to the script main.

SCRIPT MAIN

#SCRIPT MAIN
clear
$dnsSearchOrder = @()
$dnsSearchOrder += @($dns1)
$dnsSearchOrder += @($dns2)
$dnsSearchOrder += @($dns3)
$logFilePath = Create-Log
Write-ToLog -message "Starting script Set-StaticDNS.ps1...."
Write-ToLog -message "Setting DNS search order on all servers in 'servers.txt' to $dnsSearchOrder"
Write-ToLog -message "----------------------------------------------------------------------------------------------------------`n`n"
$servers | % {
	$ActiveIP = Get-ActiveNicIP -computer $_
	Set-StaticDNS -computer $_ -ActiveIP $ActiveIP
}
Write-ToLog -message "`n`n----------------------------------------------------------------------------------------------------------"
Write-ToLog -message "Script run ended."

The script main simply loops through the $servers array and runs the Get-ActiveNipIP and Set-StaticDNS functions on each server.
That should explain how the script works. I have copied in the full script below.
Enjoy!

################################################################################################
##Script:		Set-StaticDNS.ps1
##
##Description:		Sets the DNS search order on the servers given as input in servers.txt
#+			to the IP addresses specified in the parameters section.
##Created by:		Noam Wajnman
##Creation Date: December 9, 2013
################################################################################################
#FUNCTIONS
function Create-Log {
	$time = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
	$logFilePath = "$log_dir\SetStaticDNS_$time.log"
	New-Item -ItemType File $logFilePath -Force
}
function Write-ToLog {
	param (
		[string]$message
	)
	$time = Get-Date
	$logEntryStr = "$time`t" + $message
	$logEntryStr | Out-File -Append $logFilePath -Width 400
}
function Get-ActiveNicIP {
	param (
		[Parameter(Mandatory=$true)][string]$computer
	)
	Write-ToLog -message "Getting IP of 'active' interface on $computer ..."
	$conx = Test-Connection -ComputerName $computer -Count 1
	$ActiveIP = $conx.IPV4Address.IPAddressToString
	Write-ToLog -message "Active IP on $computer is $ActiveIP"
	return $ActiveIP
}
function Set-StaticDNS {
	param (
		[Parameter(Mandatory=$true)][string]$computer,
		[Parameter(Mandatory=$true)][string]$ActiveIP
	)
	Write-ToLog -message "Attempting to set DNS search order on computer $computer on the interface with the IP $ActiveIP"
	#get dns info via WMI
	$wmi = Get-WmiObject win32_networkadapterconfiguration -filter "ipenabled = 'true'" -ComputerName $computer | ? { $_.IPAddress -match $ActiveIP }
	#set dns search order via WMI
	$wmi.SetDNSServerSearchOrder($DnsSearchOrder)
	#confirm that dns search order was set to desired value.
	$StrdnsSearchOrder = $dnsSearchOrder | Out-String
	$wmi2 = Get-WmiObject win32_networkadapterconfiguration -filter "ipenabled = 'true'" -ComputerName $computer | ? { $_.IPAddress -match $ActiveIP }
	$StrWmiDnsSearchOrder = $wmi2.DNSServerSearchOrder | Out-String
	if ($StrWmiDnsSearchOrder -eq $StrdnsSearchOrder) {
		Write-ToLog -message "Setting the DNS search order was successful. Value is now $dnsSearchOrder"
	}
	else {
		Write-ToLog -message "Error - Setting the DNS search order failed!"
	}
}
#VARIABLES
$DebugPreference = "continue"
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
$log_dir = "$dir\logs"
$servers = @(gc "$dir\servers.txt")
#parameters - Add the desired DNS servers below
[string]$dns1 = "192.168.1.2"
[string]$dns2 = "192.168.1.3"
[string]$dns3 = "192.168.1.4"
#SCRIPT MAIN
clear
$dnsSearchOrder = @()
$dnsSearchOrder += @($dns1)
$dnsSearchOrder += @($dns2)
$dnsSearchOrder += @($dns3)
$logFilePath = Create-Log
Write-ToLog -message "Starting script Set-StaticDNS.ps1...."
Write-ToLog -message "Setting DNS search order on all servers in 'servers.txt' to $dnsSearchOrder"
Write-ToLog -message "----------------------------------------------------------------------------------------------------------`n`n"
$servers | % {
	$ActiveIP = Get-ActiveNicIP -computer $_
	Set-StaticDNS -computer $_ -ActiveIP $ActiveIP
}
Write-ToLog -message "`n`n----------------------------------------------------------------------------------------------------------"
Write-ToLog -message "Script run ended."