Recently, we ran into a problem when we discovered some of the newer laptops were not automatically disabling the WiFi when connected to ethernet. What made the task even more difficult was that all of our Dell Latitude 7480 systems were already deployed. Being in the legal industry, it is more difficult to ask for time to troubleshoot problems when attorneys bill by the hour.
We knew there was either a new BIOS setting for the 7480 or it had been taken away. To get a list of all the BIOS settings for the 7480, I wrote the script below that uses the Dell Command | Configure to get the BIOS options, settings, and descriptions. You can use the Dell Command | Configure GUI application, but that also requires getting time on the remote machine. This script will grab the info in the background without any interruption to the user.
The script first gets a list of all the available BIOS settings and filters out the following items since I did not see the need for these in the reports:
Once you get a list of the systems and choose which one to execute the script on, you have some options. You could either deploy the script through SCCM or you could execute it remotely using PSEXEC. Personally, I used PSEXEC. The only parameter you will need to define is the FilePath, which is the location where the .CSV will be written to.
Here is an example of a .CSV file I ran on my own machine. Some values are left blank because the output exceeded a reasonable amount for this spreadsheet, such as hddinfo. Some are also blank due to security, such as hddpwd.
You can download the script from my GitHub repository located here.
We knew there was either a new BIOS setting for the 7480 or it had been taken away. To get a list of all the BIOS settings for the 7480, I wrote the script below that uses the Dell Command | Configure to get the BIOS options, settings, and descriptions. You can use the Dell Command | Configure GUI application, but that also requires getting time on the remote machine. This script will grab the info in the background without any interruption to the user.
The script first gets a list of all the available BIOS settings and filters out the following items since I did not see the need for these in the reports:
- help
- version
- infile
- logfile
- outfile
- ovrwrt
- setuppwd
- sysdefaults
- syspwd
The next thing it does it to grab the set value for each setting and then it retrieves the description of the setting. The script formats this data into a table that is exported to a .CSV file for easy viewing. In future models, there will likely be new data, so the script will likely need to be updated. There may also be some data the script did not have access to as the firm I work at only has 8 models of Dell systems.
The first thing you need to do is to get a list of all systems with their BIOS version. You will want to run this in SCCM in order to find the systems with the latest BIOS version to generate the report on. Here is the WQL code for performing a query in SCCM.
select SMS_G_System_COMPUTER_SYSTEM.Manufacturer, SMS_G_System_COMPUTER_SYSTEM.Model, SMS_G_System_PC_BIOS.SMBIOSBIOSVersion, SMS_R_System.Name from SMS_R_System inner join SMS_G_System_PC_BIOS on SMS_G_System_PC_BIOS.ResourceID = SMS_R_System.ResourceId inner join SMS_G_System_COMPUTER_SYSTEM on SMS_G_System_COMPUTER_SYSTEM.ResourceId = SMS_R_System.ResourceId order by SMS_G_System_COMPUTER_SYSTEM.Manufacturer, SMS_G_System_PC_BIOS.SMBIOSBIOSVersion, SMS_G_System_COMPUTER_SYSTEM.Model
Once you get a list of the systems and choose which one to execute the script on, you have some options. You could either deploy the script through SCCM or you could execute it remotely using PSEXEC. Personally, I used PSEXEC. The only parameter you will need to define is the FilePath, which is the location where the .CSV will be written to.
Here is an example of a .CSV file I ran on my own machine. Some values are left blank because the output exceeded a reasonable amount for this spreadsheet, such as hddinfo. Some are also blank due to security, such as hddpwd.
You can download the script from my GitHub repository located here.
<#
.SYNOPSIS
BIOS Reporting Tool
.DESCRIPTION
This script will query the BIOS of Dell machines using the Dell Command | Configure to report the data to SCCM via WMI.
.PARAMETER FilePath
UNC path where to write the file output
.NOTES
===========================================================================
Created with: SAPIEN Technologies, Inc., PowerShell Studio 2017 v5.4.141
Created on: 7/18/2017 9:31 AM
Created by: Mick Pletcher
Filename: DellBIOSReportingTool.ps1
===========================================================================
#>
[CmdletBinding()]
param
(
[ValidateNotNullOrEmpty()][string]$FilePath
)
function Get-Architecture {
<#
.SYNOPSIS
Get-Architecture
.DESCRIPTION
Returns whether the system architecture is 32-bit or 64-bit
.EXAMPLE
Get-Architecture
.NOTES
Additional information about the function.
#>
[CmdletBinding()][OutputType([string])]
param ()
$OSArchitecture = (Get-WmiObject -Class Win32_OperatingSystem | Select-Object OSArchitecture).OSArchitecture
Return $OSArchitecture
#Returns 32-bit or 64-bit
}
function Get-RelativePath {
<#
.SYNOPSIS
Get the relative path
.DESCRIPTION
Returns the location of the currently running PowerShell script
.NOTES
Additional information about the function.
#>
[CmdletBinding()][OutputType([string])]
param ()
$Path = (split-path $SCRIPT:MyInvocation.MyCommand.Path -parent) + "\"
Return $Path
}
function Get-CCTK {
<#
.SYNOPSIS
Find CCTK.EXE
.DESCRIPTION
Find the Dell CCTK.EXE file.
.EXAMPLE
PS C:\> Get-CCTK
.NOTES
Additional information about the function.
#>
[CmdletBinding()]
param ()
$Architecture = Get-Architecture
If ($Architecture -eq "64-bit") {
$Directory = ${env:ProgramFiles(x86)} + "\Dell\"
$File = Get-ChildItem -Path $Directory -Filter cctk.exe -Recurse | Where-Object { $_.Directory -like "*_64*" }
} else {
$Directory = $env:ProgramFiles + "\Dell\"
$File = Get-ChildItem -Path $Directory -Filter cctk.exe -Recurse | Where-Object { $_.Directory -like "*x86" }
}
Return $File
}
function Get-ListOfBIOSSettings {
<#
.SYNOPSIS
Retrieve List of BIOS Settings
.DESCRIPTION
This will get a list of all BIOS settings
.PARAMETER Executable
CCTK.exe
.EXAMPLE
PS C:\> Get-ListOfBIOSSettings
.NOTES
Additional information about the function.
#>
[CmdletBinding()]
param
(
[ValidateNotNullOrEmpty()]$Executable
)
#Get the path this script is executing from
$RelativePath = Get-RelativePath
#Get list of exclusions to omit from list of BIOS settings
$File = $RelativePath + "BIOSExclusions.txt"
$BIOSExclusions = Get-Content -Path $File | Sort-Object
#Rewrite list of sorted exclusion back to text file
$BIOSExclusions | Out-File -FilePath $File -Force
#Get list of BIOS settings -- Script must be executed on a local machine and not from a UNC path
$Output = cmd.exe /c $Executable.FullName
#Remove instructional information
$Output = $Output | Where-Object { $_ -like "*--*" } | Where-Object { $_ -notlike "*cctk*" }
#Format Data and sort it
$Output = ($Output.split("--") | Where-Object { $_ -notlike "*or*" } | Where-Object{ $_.trim() -ne "" }).Trim() | Where-Object { $_ -notlike "*help*" } | Where-Object { $_ -notlike "*version*" } | Where-Object { $_ -notlike "*infile*" } | Where-Object { $_ -notlike "*logfile*" } | Where-Object { $_ -notlike "*outfile*" } | Where-Object { $_ -notlike "*ovrwrt*" } | Where-Object { $_ -notlike "*setuppwd*" } | Where-Object { $_ -notlike "*sysdefaults*" } | Where-Object { $_ -notlike "*syspwd*" } | ForEach-Object { $_.Split("*")[0] } | Where-Object { $_ -notin $BIOSExclusions }
#Add bootorder back in as -- filtered it out since it does not have the -- in front of it
$Output = $Output + "bootorder" | Sort-Object
Return $Output
}
function Get-BIOSSettings {
<#
.SYNOPSIS
Retrieve BIOS Settings Values
.DESCRIPTION
This will retrieve the value associated with the BIOS Settings
.PARAMETER Settings
List of BIOS Settings
.PARAMETER Executable
CCTK.exe file
.EXAMPLE
PS C:\> Get-BIOSSettings
.NOTES
Additional information about the function.
#>
[CmdletBinding()]
param
(
[ValidateNotNullOrEmpty()]$Settings,
[ValidateNotNullOrEmpty()]$Executable
)
#Create Array
$BIOSArray = @()
foreach ($Setting in $Settings) {
switch ($Setting) {
"advbatterychargecfg" {
$Arguments = [char]34 + $Executable.FullName + [char]34 + [char]32 + "--" + $Setting
$Value = (cmd.exe /c $Arguments).split("=")[1]
$Arguments = [char]34 + $Executable.FullName + [char]34 + [char]32 + "-h" + [char]32 + "--" + $Setting
$Description = (cmd.exe /c $Arguments | Where-Object { $_.trim() -ne "" }).split(":")[1].Trim()
}
"advsm" {
$Value = ""
$Arguments = [char]34 + $Executable.FullName + [char]34 + [char]32 + "-h" + [char]32 + $Setting
$Description = ((cmd.exe /c $Arguments) | where-object {$_.trim() -ne ""}).split(":")[1].Trim().split(".")[0]
}
"bootorder" {
$Arguments = [char]34 + $Executable.FullName + [char]34 + [char]32 + $Setting
$Output = (((((cmd.exe /c $Arguments | Where-Object { $_ -like "*Enabled*" } | Where-Object { $_ -notlike "*example*" }) -replace 'Enabled', '').Trim()) -replace '^\d+', '').Trim()) | ForEach-Object { ($_ -split ' {2,}')[1] }
$Output2 = "bootorder="
foreach ($item in $Output) {
[string]$Output2 += [string]$item + ","
}
$Value = $Output2.Substring(0,$Output2.Length-1)
$Arguments = [char]34 + $Executable.FullName + [char]34 + [char]32 + "-h" + [char]32 + $Setting
$Description = ((cmd.exe /c $Arguments) | where-object { $_.trim() -ne "" }).split(":")[1].Trim().split(".")[0]
}
"hddinfo" {
$Value = ""
$Arguments = [char]34 + $Executable.FullName + [char]34 + [char]32 + "-h" + [char]32 + $Setting
$Description = ((cmd.exe /c $Arguments) | where-object {$_.trim() -ne ""}).split(":")[1].trim().split(".")[0]
}
"hddpwd" {
$Value = ""
$Arguments = [char]34 + $Executable.FullName + [char]34 + [char]32 + "-h" + [char]32 + $Setting
$Description = ((cmd.exe /c $Arguments) | Where-Object {$_.trim() -ne ""}).split(":")[1].split(".")[0].trim()
}
"pci" {
$Value = ""
$Arguments = [char]34 + $Executable.FullName + [char]34 + [char]32 + "-h" + [char]32 + $Setting
$Description = ((cmd.exe /c $Arguments) | Where-Object { $_.trim() -ne "" }).split(":")[1].split(".")[0].trim()
}
"propowntag" {
$Arguments = [char]34 + $Executable.FullName + [char]34 + [char]32 + "--" + $Setting
$Value = ((cmd.exe /c $Arguments).split("=")[1]).trim()
$Arguments = [char]34 + $Executable.FullName + [char]34 + [char]32 + "-h" + [char]32 + $Setting
$Description = ((cmd.exe /c $Arguments) | Where-Object { $_.trim() -ne "" }).split(":")[1].trim()
}
"secureboot" {
$Arguments = [char]34 + $Executable.FullName + [char]34 + " --" + $Setting
$Output = cmd.exe /c $Arguments
if ($Output -like "*not enabled*") {
$Value = "disabled"
} else {
$Value = "enabled"
}
$Arguments = [char]34 + $Executable.FullName + [char]34 + [char]32 + "-h" + [char]32 + $Setting
$Description = ((cmd.exe /c $Arguments) | where-object { $_.trim() -ne "" }).split(":")[1].Trim().split(".")[0]
}
default {
#Get BIOS setting
$Output = $null
$Arguments = [char]34 + $Executable.FullName + [char]34 + [char]32 + "--" + $Setting
$Output = cmd.exe /c $Arguments
#Get BIOS Description
$Arguments = [char]34 + $Executable.FullName + [char]34 + [char]32 + "-h" + [char]32 + "--" + $Setting
$Description = ((cmd.exe /c $Arguments) | Where-Object { $_.trim() -ne "" }).split(":").Trim()[1]
$Value = $Output.split("=")[1]
}
}
#Add Items to object array
$objBIOS = New-Object System.Object
$objBIOS | Add-Member -MemberType NoteProperty -Name Setting -Value $Setting
$objBIOS | Add-Member -MemberType NoteProperty -Name Value -Value $Value
$objBIOS | Add-Member -MemberType NoteProperty -Name Description -Value $Description
$BIOSArray += $objBIOS
}
Return $BIOSArray
}
#Find the CCTK.exe file
$CCTK = Get-CCTK
#Get List of BIOS settings
$BIOSList = Get-ListOfBIOSSettings -Executable $CCTK
#Get all BIOS settings
$BIOSSettings = Get-BIOSSettings -Executable $CCTK -Settings $BIOSList
#Add Computer Model to FileName
$FileName = ((Get-WmiObject -Class win32_computersystem -Namespace root\cimv2).Model).Trim()
#Add BIOS version and .CSV extension to computer name
$FileName += [char]32 + ((Get-WmiObject -Class win32_bios -Namespace root\cimv2).SMBIOSBIOSVersion).Trim() + ".CSV"
#Get full path to the output .CSV file
If ($FilePath[$FilePath.Length - 1] -ne "\") {
$FileName = $FilePath + "\" + $FileName
} else {
$FileName = $FilePath + $FileName
}
#Delete old .CSV if it exists
If ((Test-Path $FileName) -eq $true) {
Remove-Item -Path $FileName -Force
}
#Screen output
$BIOSSettings
#File output
$BIOSSettings | Export-Csv -Path $FileName -NoTypeInformation -Force
Hi - Can you share the download link for the script and cctk.exe file please.
ReplyDeleteThanks
RL
Done. The CCTK.exe can be extracted from the Dell Command | Configure.
Delete