I saw an interesting post yesterday by Keith Garner on using PowerShell’s “Select-string” to search OS deployment logs and find errors by searching on the entry type instead of the usual way that the CMTrace utility does it – by highlighting keywords. I decided to take the idea further and create a script that will search my deployment logging shares, allow me to choose which deployed computer to search on, which log file to search, and then return the errors into CMTrace for easy viewing.
Here’a a quick demo:
I run the script and it searches my OSD logging directory (“SLShare” variable in the customsettings.ini) and returns all deployments in the last 10 days:
I select the deployment I want and click OK. Then it searches recursively for all the log files in that directory, and asks me to choose one:
I want to search the smsts.log for errors, so I select it and click OK. It then puts all the errors into a temporary log file and invokes it. As .log files open with CMTrace by default, I can read through the errors more easily.
The script will then watch the CMTrace process, wait until you exit it, and delete the temporary log.
Configure the Script
The script has comment-based help, and there are some parameters you can use. You will need to set the defaults in the script as the parameters are not mandatory.
$NumberOfDays – The script will search the logging share for deployments in the last x number of days
$LogDirectory – The location of your OSD logging share, eg your MDT “SLShare” directory
$Dynamic – Use this switch to search the dynamic logging share instead, eg your MDT “SLShareDynamicLogging” directory
$DynamicLogDirectory – the location of the “SLShareDynamicLogging” directory
The Script
<# .SYNOPSIS Retrieves error entries from logs used by MDT and ConfigMgr during OSD .DESCRIPTION This script searches the OSD logs for error entries. You can: - specify the location of the log files, for example your deployment logging share - choose which computer's log files to search - choose which log file to search The errors will be added to a temporary log file, which will open with CMTrace (you need to set that as the default viewer for log files). This script is based on an idea from Keith Garner: https://keithga.wordpress.com/2015/05/04/find-errors-quickly-in-a-sccm-or-mdt-log-file/ .PARAMETER LogDirectory The location of your OSD logging directory, for example your "SLShare" .PARAMETER DynamicLogDirectory The location of your OSD dynamic logging directory, for example your "SLShareDynamicLogging". Use with the -Dynamic switch. .PARAMETER NumberOfDays The number of days of deployment logs to retrieve, for example all deployments in the last 5 days .PARAMETER Dynamic Use this switch to search the dynamic logging directory .EXAMPLE .\Get-OSDLogErrors.ps1 Searches the default logging directory for all deployments in the default number of days past, prompts you to choose the computer, then the log, then displays the error entries in a temporary log file .EXAMPLE .\Get-OSDLogErrors.ps1 -LogDirectory \\mymdtserver\MDT_Logs$ -NumberOfDays 10 Searches the logging directory specified for all deployments in the last 10 days, prompts you to choose the computer, then the log, then displays the error entries in a temporary log file .EXAMPLE .\Get-OSDLogErrors.ps1 -Dynamic Searches the default dynamic logging directory for all deployments in the default number of days past, prompts you to choose the computer, then the log, then displays the error entries in a temporary log file .NOTES Script name: Get-OSDLogErrors.ps1 Author: Trevor Jones Contact: @trevor_smsagent DateCreated: 2015-05-11 Link: https://smsagent.wordpress.com #> [CmdletBinding()] param ( [parameter(Mandatory=$False, HelpMessage="The number of days of deployment log files to check")] [string]$NumberOfDays = 5, [Parameter(Mandatory=$False, HelpMessage="The location of the OSD logging directory")] [string]$LogDirectory = "\\sccmserver01\MDT_Logs$", [parameter(Mandatory=$False)] [switch]$Dynamic, [Parameter(Mandatory=$False, HelpMessage="The location of the OSD dynamic logging directory")] [string]$DynamicLogDirectory = "\\sccmserver01\MDT_Logs$\Dynamic" ) if ($Dynamic) {$LogDirectory = $DynamicLogDirectory} # Get the directory listing of deployed computers, and prompt to choose if (test-path $LogDirectory) { $Computer = Get-ChildItem $LogDirectory | Where-Object {$_.LastWriteTime -ge (Get-Date).AddDays(-$NumberOfDays) -and $_.Name -notin ('Dynamic','Variables')} | Sort LastWriteTime -Descending | Select Name, LastWriteTime | Out-GridView -Title "Choose a deployed computer" -OutputMode Single | Select -ExpandProperty Name } Else {Write-Warning "Could not access the log directory"; break} # Get the list of log files for that computer, and prompt to choose if ($Computer -ne $null) { $LogFile = Get-ChildItem "$LogDirectory\$Computer" -Recurse | Where-Object {$_.Mode -ne "d----"} | Select Name, @{N='Size (KB)'; E={[math]::Round(($_.Length / 1KB), 2)}}, LastWriteTime, @{N='Location'; E={$_.FullName}} | Sort Name | Out-GridView -Title "Choose a log file" -OutputMode Single | Select -ExpandProperty Location # Search the log file for entries of type 2 or 3 $Entries = Select-String -Path "$LogFile" -Pattern "type=""(2|3)""" } Else {break} if ($Entries -eq $Null) {Write-Warning "No error entries found."; break} Else { # Output each log entry to a temporary log file and invoke it $x = -1 foreach ($Line in $Entries) { $x ++ $Entries[$x].Line | Out-File "$env:TEMP\OSDerrors.log" -Append } Invoke-Item "$env:TEMP\OSDerrors.log" # Wait for CMTrace to start do {Start-Sleep -Seconds 2} until ((Get-Process CMTrace -ErrorAction Ignore) -ne $null) # wait until CMTrace is closed, then delete the temporary log file do { start-sleep -Seconds 2 $process = Get-process -name CMTrace -ErrorAction Ignore } until ($process -eq $null) Remove-Item "$env:TEMP\OSDerrors.log" }