Get latest installed update with PowerShell

Assuming you have an array of computers (be it from LDAP or otherwise) you can quickly enumerate them using the WMI Win32_QuickFixEngineering class to check the most recently installed HotFix.

Whilst WSUS will likely provide much of this functionality for those using it, this may still prove useful to some.

$compList = "LONDON", "BRISBANE"
$ErrorActionPreference = "Stop";
$tblResults = New-Object System.Data.DataTable "Results"

$colA = New-Object System.Data.DataColumn ComputerName, ([string])
$colB = New-Object System.Data.DataColumn LastHotFixID, ([string])
$colC = New-Object System.Data.DataColumn LastUpdated, ([string])

$tblResults.Columns.Add( $colA )
$tblResults.Columns.Add( $colB )
$tblResults.Columns.Add( $colC )

foreach ($computer in $compList)
{
	try
	{
		$latestUpdate = Get-WMIObject -Class Win32_QuickFixEngineering -ComputerName $computer -Filter "HotFixID != 'File 1'"| ? {$_.InstalledON} |sort InstalledOn | select -last 1
		$newRow = $tblResults.newrow()
		$newRow.ComputerName = $computer
		$newRow.LastHotFixID = $latestUpdate.HotFixID
		$newRow.LastUpdated = "{0:dd/MM/yyyy}" -f [DateTime] $latestUpdate.InstalledOn.Date
		$tblResults.Rows.Add( $newRow )
	}
	catch
	{
		$computer
	}
}
$tblResults

Save the above to a file with the “ps1” extension and adjust the $compList variable to contain the computers you wish to scan.

The only oddity in this I’ve discovered is if the updates are slipstreamed into the installation WIM they do not have an install date associated with them.

Using powershell to list users accessing OWA

Sometimes it’s useful to identify how many users are using Outlook Web Access, particularly for capacity management. Just because an account has OWA enabled, doesn’t mean it’s being used.

The below PowerShell script will enumerate the IIS logs looking for OWA access, if found it’ll add the user account to a list of accounts accessing OWA.

$path = "C:\WINDOWS\system32\LogFiles\W3SVC1\ex*"

# Create new DataTable to hold log entries
$tblLog = New-Object System.Data.DataTable "Log"
$arrUsers = New-Object System.Collections.ArrayList($null)
$bFirstRun = $TRUE;

foreach ($file in Get-ChildItem $path)
{
	# Get the contents of the file, excluding the first three lines.
	$fileContents = Get-Content $file.FullName | where {$_ -notLike "#[D,S-V]*" }

	# Create DataTable columns. No handling for different columns in
	# each log file.
	if( $bFirstRun )
	{
		$columns = (($fileContents[0].TrimEnd()) -replace "#Fields: ", "" -replace "-","" -replace "\(","" -replace "\)","").Split(" ")
		$colCount = $columns.Length

		# Create a DataColumn from the column string and add to our DataTable.
		foreach ($column in $columns)
		{
			$colNew = New-Object System.Data.DataColumn $column, ([string])
			$tblLog.Columns.Add( $colNew )
		}
		$bFirstRun = $FALSE;
		Write-Host "Columns complete"
	}
	
	# Get the row contents from the file, filtering what I want to retrieve.
	$rows = $fileContents | where {$_ -like "*/owa/Default.aspx*"}

	# Loop through rows in the log file.
	foreach ($row in $rows)
	{
		if(!$row)
		{
			continue
		}

		$rowContents = $row.Split(" ")
		$newRow = $tblLog.newrow()
		for($i=0;$i -lt $colCount; $i++)
		{
			$columnName = $columns[$i]
			$newRow.$columnName = $rowContents[$i]
		}
		$tblLog.Rows.Add( $newRow )
	}
	Write-Host $file.Name "Done"
}
$tblLog | foreach {  if(! $arrUsers.Contains( $_.csusername ) ) { $arrUsers.Add( $_.csusername ) } }
$arrUsers

Continue reading Using powershell to list users accessing OWA

How To – Check crashed servers using PowerShell

Following on from my previous post about how to check disk space and volume fragmentation of servers, it may be useful to also determine if a system has crashed in a given timeframe. From Windows 2008 R2 onwards a new WMI class was introduced, Win32_ReliabilityRecords. This class contains EventLog information relating to Windows Reliability.

The PowerShell script below will connect to each server in a list ($compList) and check for reboots.

$compList = "LONDON,BRISBANE"
$date = [System.Management.ManagementDateTimeConverter]::ToDMTFDateTime((Get-Date "01/11/2012"))
foreach ($computerName in $compList)
{
	$compCrashes = 0
	try
	{
		$compCrashes = Get-WmiObject -Computername $computerName -Class Win32_ReliabilityRecords -Filter "SourceName='EventLog' AND EventIdentifier='6008' AND Timegenerated >= '$date'" | group __CLASS | select Count
	}
	catch{}
	Write-Host $ComputerName $compCrashes.Count
}

This could be expanded to store the results in a table and send the results using Send-MailMessage, but I’ll leave that to the reader.
Continue reading How To – Check crashed servers using PowerShell