Compare commits

5 Commits

Author SHA1 Message Date
GraceSolutions 742b01a905 Update README with comprehensive project documentation 2026-03-15 16:04:34 -04:00
freedbygrace de2979f1cc Added TLS 1.2 Configuration for web calls for Windows release history. 2023-03-20 08:44:01 -04:00
freedbygrace abe7fcbb68 Update Invoke-DriverPackageDownload.ps1 2023-03-13 17:42:04 -04:00
freedbygrace ffe9ceb895 Fixed the generic driver packages filters 2023-03-13 17:15:05 -04:00
freedbygrace fd41fdfb89 Create ts.xml 2023-02-20 16:55:34 -05:00
7 changed files with 457 additions and 163 deletions
Binary file not shown.
-94
View File
@@ -1,94 +0,0 @@
<?xml version="1.0" encoding="utf-16"?>
<?xml-stylesheet type='text/xsl' href='style.xsl'?>
<!--Please specify the configuration settings that will be used by the driver package creation powershell script.-->
<!--
By default, the settings XML will be automatically modified by the 'Invoke-DriverPackageCreation' script to include the model you execute the script on, but only if it matches one of the manufacturers within the XML.
To add a model manually, copy and paste the following code into the Powershell ISE on the specific model you want to add to this XML.
The text will be automatically copied to the clipboard.
Add the model under the desired manufacturer in order to the entry to be processed correctly.
### Begin Code Snippet ###
$PropertyList = New-Object -TypeName 'System.Collections.Generic.List[Object]'
$PropertyList.Add(@{Name = 'Enabled'; Expression = {$True}})
$PropertyList.Add('SystemProductName')
$PropertyList.Add(@{Name = 'ProductID'; Expression = {$_.BaseboardProduct}})
$PropertyList.Add('BaseboardProduct')
$PropertyList.Add('SystemSKU')
$PropertyList.Add('SystemVersion')
$PropertyList.Add('SystemFamily')
$PropertyList.Add('SystemManufacturer')
$MSSystemInformation = Get-CIMInstance -Namespace "root\WMI" -Class "MS_SystemInformation" | Select-Object -Property ($PropertyList)
$XMLAttributes = $MSSystemInformation.PSObject.Properties | ForEach-Object {"$($_.Name)=`"$($_.Value)`""}
$XMLNode = "<Model $($XMLAttributes -Join ' ') />"
Write-Output -InputObject ($XMLNode)
$Null = $XMLNode | Set-Clipboard -Verbose
### End Code Snippet ###
<ModelList>
### Copy and paste the generated text from the clipboard in between the 'ModelList' section for the desired manufacturer ###
</ModelList>
As an example, the following details are available from the following powershell command
Get-CIMInstance -Namespace 'Root\WMI' -Class 'MS_SystemInformation'
BaseBoardManufacturer : Dell Inc.
BaseBoardProduct : 01Y2TP
BaseBoardVersion : A00
BiosMajorRelease : 1
BiosMinorRelease : 6
BIOSReleaseDate : 09/05/2022
BIOSVendor : Dell Inc.
BIOSVersion : 1.6.1
ECFirmwareMajorRelease : 255
ECFirmwareMinorRelease : 255
InstanceName : ROOT\mssmbios\0000_0
SystemFamily : Latitude
SystemManufacturer : Dell Inc.
SystemProductName : Latitude 5430
SystemSKU : 0B04
SystemVersion :
-->
<Settings>
<GeneratedBy>DSW\amote</GeneratedBy>
<GeneratedOn>NBAMOTE</GeneratedOn>
<GeneratedDate>2022-11-10T15:01</GeneratedDate>
<OperatingSystemList>
<OperatingSystem Enabled="True" Vendor="Microsoft" Name="Windows 10" NameExpression=".*10.*" ArchitectureExpression=".*64.*" ReleaseExpression=".*" LatestReleaseOnly="True" />
<OperatingSystem Enabled="True" Vendor="Microsoft" Name="Windows 11" NameExpression=".*11.*" ArchitectureExpression=".*64.*" ReleaseExpression=".*" LatestReleaseOnly="True" />
</OperatingSystemList>
<ManufacturerList>
<Manufacturer Enabled="True" Name="Dell" EligibilityExpression="(^.*Dell.*$)" ProductIDPropertyName="SystemSKU">
<URLs DriverPackCatalog="https://dl.dell.com/catalog/DriverPackCatalog.cab" DownloadBase="https://dl.dell.com" />
<ModelList>
<Model Enabled="False" SystemProductName="Latitude 5420" ProductID="0A20" BaseboardProduct="0M51J7" SystemSKU="0A20" SystemVersion="" SystemFamily="Latitude" SystemManufacturer="Dell" />
</ModelList>
</Manufacturer>
<Manufacturer Enabled="True" Name="HP" EligibilityExpression="(^.*HP.*$)|(^.*Hewlett.*Packard.*$)" ProductIDPropertyName="BaseboardProduct">
<URLs DriverPackCatalog="https://ftp.hp.com/pub/caps-softpaq/cmit/HPClientDriverPackCatalog.cab" DownloadBase="" />
<ModelList>
<Model Enabled="False" SystemProductName="HP ZBook Studio G7 Mobile Workstation" ProductID="8736" BaseboardProduct="8736" SystemSKU="8YP41AV" SystemVersion="" SystemFamily="103C_5336AN HP ZBook" SystemManufacturer="HP" />
</ModelList>
</Manufacturer>
<Manufacturer Enabled="True" Name="Lenovo" EligibilityExpression="(^.*LENOVO.*$)" ProductIDPropertyName="SystemProductName">
<URLs DriverPackCatalog="https://download.lenovo.com/cdrt/td/catalogv2.xml" DownloadBase="" />
<ModelList>
<Model Enabled="False" SystemProductName="10AXS2CQ00" ProductID="10AX" BaseboardProduct="10AXS2CQ00" SystemSKU="LENOVO_MT_10AX" SystemVersion="ThinkCentre M73" SystemFamily="To be filled by O.E.M." SystemManufacturer="Lenovo" />
</ModelList>
</Manufacturer>
</ManufacturerList>
</Settings>
+71 -12
View File
@@ -152,6 +152,16 @@ Function Get-WindowsReleaseHistory
#Create an object that will contain the functions output.
$OutputObjectList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]'
#region Adjust security protocol type(s)
[System.Net.SecurityProtocolType]$DesiredSecurityProtocol = [System.Net.SecurityProtocolType]::TLS12
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to set the desired security protocol to `"$($DesiredSecurityProtocol.ToString().ToUpper())`". Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$Null = [System.Net.ServicePointManager]::SecurityProtocol = ($DesiredSecurityProtocol)
#endregion
}
Catch
{
@@ -192,7 +202,7 @@ Function Get-WindowsReleaseHistory
$OGTitle = ($MetadataList[0].Attributes | Where-Object {($_.Name -ieq 'Content')}).Value
$HistoryTableList = $HTMLDocumentObject.SelectNodes('//table') | Where-Object {($_.ID -imatch '(^HistoryTable_\d+$)')}
$Global:HistoryTableList = $HTMLDocumentObject.SelectNodes('//table') | Where-Object {($_.ID -imatch '(^HistoryTable_\d+$)')}
$RootNodeList = $HTMLDocumentObject.SelectNodes('//strong')
@@ -215,19 +225,67 @@ Function Get-WindowsReleaseHistory
$OutputObjectProperties.ReleaseHistory = New-Object -TypeName 'System.Collections.Generic.List[PSObject]'
<#
$HistoryTableChildNodeList = ($HistoryTableList | Where-Object {($_.InnerText -imatch ".*$($OutputObjectProperties.Build).*")}).ChildNodes | Where-Object {([String]::IsNullOrEmpty($_.InnerText) -eq $False) -and ([String]::IsNullOrWhiteSpace($_.InnerText) -eq $False)} | Sort-Object -Property @('InnerText') -Unique
$HistoryTableRowList = ($HistoryTableList.ChildNodes | Where-Object {($_.ChildNodes.Count -gt 0)})
For ($HistoryTableChildNodeIndex = 0; $HistoryTableChildNodeIndex -lt $HistoryTableChildNodeList.Count; $HistoryTableChildNodeIndex++)
{
$HistoryTableChildNode = $HistoryTableChildNodeList[$HistoryTableChildNodeIndex]
$InnerTextLines = $HistoryTableChildNode.InnerText.Split("`n", [System.StringSplitOptions]::RemoveEmptyEntries).Trim()
For ($HistoryTableRowListIndex = 0; $HistoryTableRowListIndex -lt $HistoryTableRowList.Count; $HistoryTableRowListIndex++)
{
$HistoryTableRow = $HistoryTableRowList[$HistoryTableRowListIndex]
For ($InnerTextLineIndex = 0; $InnerTextLineIndex -lt $InnerTextLines.Count; $InnerTextLineIndex++)
Switch ($HistoryTableRowListIndex)
{
$InnerTextLine = $InnerTextLines[$InnerTextLineIndex]
{($_ -eq 0)}
{
$HistoryTableRowNodeList = $HistoryTableRow.ChildNodes | Where-Object {([String]::IsNullOrEmpty($_.InnerText) -eq $False) -and ([String]::IsNullOrWhiteSpace($_.InnerText) -eq $False)}
$HistoryTableRowPropertyList = ($HistoryTableRowNodeList | ForEach-Object {($TextInfo.ToTitleCase($_.InnerText) -ireplace '(\s+)', '')}) -As [System.Collections.Generic.List[String]]
}
#$InnerTextLine
Default
{
Switch ($HistoryTableRowPropertyList.Count -gt 0)
{
{($_ -eq $True)}
{
$ReleaseHistoryObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$HistoryTableRowData = $HistoryTableRow.ChildNodes | Where-Object {($_.ChildNodes.Count -gt 0)}
For ($HistoryTableRowPropertyListIndex = 0; $HistoryTableRowPropertyListIndex -lt $HistoryTableRowPropertyList.Count; $HistoryTableRowPropertyListIndex++)
{
$HistoryTableRowPropertyName = $HistoryTableRowPropertyList[$HistoryTableRowPropertyListIndex]
$HistoryTableRowPropertyValue = $HistoryTableRowData[$HistoryTableRowPropertyListIndex]
Switch ($Null -ine $HistoryTableRowPropertyValue)
{
{($_ -eq $True)}
{
$ValuesMatchingRowNodeList = $HistoryTableRowNodeList | Where-Object {($_.InnerText -imatch ".*$($HistoryTableRowPropertyValue.InnerText).*")}
$ValuesMatchingRowNodeListCount = ($ValuesMatchingRowNodeList | Measure-Object).Count
Switch ($ValuesMatchingRowNodeListCount -eq 0)
{
{($_ -eq $True)}
{
$ReleaseHistoryObjectProperties."$($HistoryTableRowPropertyName)" = $HistoryTableRowPropertyValue.InnerText
}
Default
{
$ReleaseHistoryObjectProperties."$($HistoryTableRowPropertyName)" = $Null
}
}
}
}
}
$ReleaseHistoryObject = New-Object -TypeName 'PSObject' -Property ($ReleaseHistoryObjectProperties)
$OutputObjectProperties.ReleaseHistory.Add($ReleaseHistoryObject)
}
}
}
}
}
#>
@@ -239,12 +297,13 @@ Function Get-WindowsReleaseHistory
}
}
$Null = $OutputObjectProperties.ReleaseHistory = $OutputObjectProperties.ReleaseHistory.ToArray() | Where-Object {($Null -ine $_)}
}
#Write the object to the powershell pipeline
$OutputObjectList = $OutputObjectList.ToArray()
$Global:WindowsReleaseHistory = $OutputObjectList | Sort-Object -Property @('Version')
$Global:WindowsReleaseHistory = $OutputObjectList | Sort-Object -Property @('Version') | Group-Object -Property @('Name')
}
Default
@@ -296,5 +355,5 @@ Function Get-WindowsReleaseHistory
#endregion
<#
Get-WindowsReleaseHistory -Force:$False -Verbose
Get-WindowsReleaseHistory -Verbose
#>
+63 -56
View File
@@ -11,18 +11,25 @@ Function Invoke-SQLDBQuery
The database connection will be opened, each database query will be executed, the results will be stored, and the database connection will be closed.
.PARAMETER Server
The FQDN or IP Address of a MS SQL database server.
.PARAMETER Instance
A valid instance name of the desired MS SQL database server instance. (Optional)
.PARAMETER Port
A valid port number of the MS SQL database server. (Optional)
.PARAMETER UserID
A valid SQL authentication username (If not specified, Windows authentication will be used.)
.PARAMETER Password
A valid SQL authentication password (If not specified, Windows authentication will be used.)
.PARAMETER Database
A valid database name that resides on the specified MS SQL database server.
.PARAMETER DBQueryList
One or more valid SQL queries for the specified database.
.EXAMPLE
$DBQueryResults = Invoke-SQLDBQuery -Server 'MyDBServer.mydomain.com' -UserID 'SQLAuthUser' -Password 'SQLAuthUserPassword' -Database 'YourDatabaseName' -DBQueryList @('Select * From YourTableName') -Verbose
@@ -30,7 +37,7 @@ Function Invoke-SQLDBQuery
Write-Output -InputObject ($DBQueryResults)
.EXAMPLE
$DBQueryList = [System.Collections.Generic.List[String]]@()
$DBQueryList = New-Object -TypeName 'System.Collections.Generic.List[String]'
$DBQueryList.Add(@"
Select Distinct
dbo.v_Add_Remove_Programs.DisplayName0 As 'DisplayName'
@@ -51,6 +58,26 @@ Order By
$DBQueryResults = Invoke-SQLDBQuery -Server 'MyDBServer.mydomain.com' -Port '4530' -Database 'YourDatabaseName' -DBQueryList @('Select * From YourTableName1', 'Select * From YourTableName2')
Write-Output -InputObject ($DBQueryResults)
.EXAMPLE
$InvokeSQLDBQueryParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$InvokeSQLDBQueryParameters.Server = "MyDBServer.mydomain.com"
$InvokeSQLDBQueryParameters.Instance = "MyDBInstance"
$InvokeSQLDBQueryParameters.Port = "1433"
$InvokeSQLDBQueryParameters.UserID = "sa"
$InvokeSQLDBQueryParameters.Password = "Password1"
$InvokeSQLDBQueryParameters.Database = "YourDatabaseName"
$InvokeSQLDBQueryParameters.DBQueryList = New-Object -TypeName 'System.Collections.Generic.List[String]'
$InvokeSQLDBQueryParameters.DBQueryList.Add('Select * From YourTableName1')
$InvokeSQLDBQueryParameters.DBQueryList.Add('Select * From YourTableName2')
$InvokeSQLDBQueryParameters.ExportJSON = $True
$InvokeSQLDBQueryParameters.ExportDirectory = "$($Env:Public)\Desktop\SQLDBQueryResults"
$InvokeSQLDBQueryParameters.ContinueOnError = $True
$InvokeSQLDBQueryParameters.Verbose = $True
$InvokeSQLDBQueryResult = Invoke-SQLDBQuery @InvokeSQLDBQueryParameters
Write-Output -InputObject ($InvokeSQLDBQueryResult)
.LINK
https://www.SQLshack.com/connecting-powershell-to-SQL-server/
@@ -59,7 +86,7 @@ Order By
https://stackoverflow.com/questions/64681003/fetch-a-whole-row-from-SQL-server-with-powershell
#>
[CmdletBinding(ConfirmImpact = 'Low', HelpURI = '', DefaultParameterSetName = '_AllParameterSets', SupportsShouldProcess = $True, PositionalBinding = $True)]
[CmdletBinding(ConfirmImpact = 'Low', HelpURI = '', DefaultParameterSetName = '_AllParameterSets', SupportsShouldProcess = $True)]
Param
(
[Parameter(Mandatory=$True)]
@@ -139,39 +166,7 @@ Order By
#Define Default Action Preferences
$ErrorActionPreference = 'Stop'
$LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The following parameters and values were provided to the `'$($CmdletName)`' function."
Write-Verbose -Message $LogMessage
$FunctionProperties = Get-Command -Name $CmdletName
$FunctionParameters = $FunctionProperties.Parameters.Keys | Where-Object {($_ -inotmatch '(^Password$)|(^UserID$)|(^DBQueryList$)')}
ForEach ($Parameter In $FunctionParameters)
{
If (!([String]::IsNullOrEmpty($Parameter)))
{
$ParameterProperties = Get-Variable -Name $Parameter -ErrorAction SilentlyContinue
$ParameterValueCount = $ParameterProperties.Value | Measure-Object | Select-Object -ExpandProperty Count
If ($ParameterValueCount -gt 1)
{
$ParameterValueStringFormat = ($ParameterProperties.Value | ForEach-Object {"`"$($_)`""}) -Join ", "
$LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($ParameterProperties.Name):`r`n`r`n$($ParameterValueStringFormat)"
}
Else
{
$ParameterValueStringFormat = ($ParameterProperties.Value | ForEach-Object {"`"$($_)`""}) -Join ', '
$LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($ParameterProperties.Name): $($ParameterValueStringFormat)"
}
If (!([String]::IsNullOrEmpty($ParameterProperties.Name)))
{
Write-Verbose -Message $LogMessage
}
}
}
$LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($CmdletName) began on $($FunctionStartTime.ToString($DateTimeLogFormat))"
Write-Verbose -Message $LogMessage
@@ -185,10 +180,10 @@ Order By
$LoggingDetails.Add('ErrorMessage', $Null)
#Create a database connection string builder
$DBConnectionStringBuilder = [System.Data.SQLClient.SQLConnectionStringBuilder]::New()
$DBConnectionStringBuilder = New-Object -TypeName 'System.Data.SQLClient.SQLConnectionStringBuilder'
#Create a database data source builder
$DataSourceBuilder = [System.Text.StringBuilder]::New()
$DataSourceBuilder = New-Object -TypeName 'System.Text.StringBuilder'
#Dynamically build the connection string based on parameter values
Switch ($True)
@@ -219,26 +214,34 @@ Order By
}
}
$DBConnection = [System.Data.SQLClient.SQLConnection]::New()
$DBConnection = New-Object -TypeName 'System.Data.SQLClient.SQLConnection'
Switch (([String]::IsNullOrEmpty($UserID) -eq $True) -or ([String]::IsNullOrWhiteSpace($UserID) -eq $True) -or ([String]::IsNullOrEmpty($Password) -eq $True) -or ([String]::IsNullOrWhiteSpace($Password) -eq $True))
Switch ((([String]::IsNullOrEmpty($UserID) -eq $False) -and ([String]::IsNullOrWhiteSpace($UserID) -eq $False)) -and (([String]::IsNullOrEmpty($Password) -eq $False) -or ([String]::IsNullOrWhiteSpace($Password) -eq $False)))
{
{($_ -eq $True)}
{
$DBConnectionStringBuilder.PSBase.IntegratedSecurity = $True
$DBConnectionStringBuilder.PSBase.IntegratedSecurity = $False
$CredentialParameters = New-Object -TypeName 'System.Collections.Generic.List[Object]'
$CredentialParameters.Add($UserID)
$CredentialParameters.Add((ConvertTo-SecureString -String $Password -AsPlainText -Force))
$Credential = New-Object -TypeName 'System.Management.Automation.PSCredential' -ArgumentList ($CredentialParameters.ToArray())
$Null = $Credential.Password.MakeReadOnly()
$DBConnectionCredentialParameters = New-Object -TypeName 'System.Collections.Generic.List[Object]'
$DBConnectionCredentialParameters.Add($Credential.UserName)
$DBConnectionCredentialParameters.Add($Credential.Password)
$DBConnectionCredential = New-Object -TypeName 'System.Data.SQLClient.SQLCredential' -ArgumentList ($DBConnectionCredentialParameters.ToArray())
$DBConnection.Credential = ($DBConnectionCredential)
}
Default
{
$DBConnectionStringBuilder.PSBase.IntegratedSecurity = $False
$Credential = [System.Management.Automation.PSCredential]::New($UserID, (ConvertTo-SecureString -String $Password -AsPlainText -Force))
$Null = $Credential.Password.MakeReadOnly()
$DBConnectionCredential = [System.Data.SQLClient.SQLCredential]::New($Credential.UserName, $Credential.Password)
$DBConnection.Credential = ($DBConnectionCredential)
$DBConnectionStringBuilder.PSBase.IntegratedSecurity = $True
}
}
@@ -271,7 +274,7 @@ Order By
[String]$DBQuery = $DBQueryList[$DBQueryListIndex]
[Int]$DBQueryNumber = $DBQueryListIndex + 1
$DBCommand = [System.Data.SQLClient.SQLCommand]::New()
$DBCommand = New-Object -TypeName 'System.Data.SQLClient.SQLCommand'
$DBCommand.Connection = ($DBConnection)
$DBCommand.CommandText = ($DBQuery)
@@ -280,10 +283,14 @@ Order By
$Null = $DBCommand.ExecuteScalar()
$DBQueryResults = [System.Data.DataTable]::New()
$DBQueryResults = New-Object -TypeName 'System.Data.DataTable'
$DBDataAdapterParameters = New-Object -TypeName 'System.Collections.Generic.List[Object]'
$DBDataAdapterParameters.Add($DBCommand)
$DBDataAdapter = [System.Data.SQLClient.SQLDataAdapter]::New($DBCommand)
$Null = $DBDataAdapter.Fill($DBQueryResults)
$DBDataAdapter = New-Object -TypeName 'System.Data.SQLClient.SQLDataAdapter' -ArgumentList ($DBDataAdapterParameters.ToArray())
$Null = $DBDataAdapter.Fill($DBQueryResults)
$DBQueryRowCount = $DBQueryResults.Rows.Count
@@ -305,10 +312,10 @@ Order By
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - " + "Attempting to add the result(s) from database query #$($DBQueryNumber) to property `"$($ResultSetPropertyName)`". Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$PropertyInclusionList = [System.Collections.Generic.List[Object]]@()
$PropertyInclusionList = New-Object -TypeName 'System.Collections.Generic.List[Object]'
$Null = $PropertyInclusionList.Add('*')
$PropertyExclusionList = [System.Collections.Generic.List[Object]]@()
$PropertyExclusionList = New-Object -TypeName 'System.Collections.Generic.List[Object]'
$Null = $PropertyExclusionList.AddRange(('HasErrors', 'ItemArray', 'RowError', 'RowState', 'Table'))
$DBQueryRows = $DBQueryResults.Rows | Select-Object -Property ($PropertyInclusionList) -ExcludeProperty ($PropertyExclusionList)
@@ -353,7 +360,7 @@ Order By
{($ExportJSON.IsPresent)}
{
$ExportParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$ExportParameters.Add('Compress', $False)
$ExportParameters.Add('Compress', $True)
$ExportParameters.Add('Encoding', [System.Text.Encoding]::Default)
$ExportParameters.Add('Depth', 10)
+20
View File
@@ -978,6 +978,26 @@ Else
{
{($_ -eq $True)}
{
$OperatingSystemCriteria = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
Switch ($WindowsImageDetails.BuildLabEX)
{
{($_ -imatch '.*amd64.*')}
{
$OperatingSystemCriteria.Architecture = 'X64'
}
Default
{
$OperatingSystemCriteria.Architecture = 'X86'
}
}
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Deployed Operating System - Architecture: $($OperatingSystemCriteria.Architecture)"
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
$OperatingSystemCriteria.Version = $WindowsImageDetails.Version
$GenericDriverPackageMetadataFileList = Get-ChildItem -Path ($GenericDriverPackageRootDirectory.FullName) -Filter '*.json' -Recurse -Force | Where-Object {($_ -is [System.IO.FileInfo])}
ForEach ($GenericDriverPackageMetadataFile In $GenericDriverPackageMetadataFileList)
+230 -1
View File
@@ -1 +1,230 @@
A.D.D.A.P. - Autonomous Driver Downloader and Packager
# A.D.D.A.P. Autonomous Driver Downloader And Packager
A PowerShell-based solution that automates the downloading, extraction, and WIM compression of OEM driver packs from **Dell**, **HP**, and **Lenovo**. A companion script dynamically downloads and applies the correct WIM driver pack during OS Deployment (OSD) based on the detected hardware and deployed operating system.
---
## Overview
Managing drivers across a fleet of hardware models is one of the most time-consuming parts of Windows OS deployment. ADDAP solves this by:
1. **Downloading** vendor driver pack catalogs and driver packages from Dell, HP, and Lenovo.
2. **Extracting** the downloaded driver packs.
3. **Compressing** the extracted drivers into WIM format for efficient storage and transfer.
4. **Dynamically applying** the correct WIM driver pack during OSD by matching the target device's hardware identifiers and the operating system being deployed.
All processing is driven by an **XML configuration file** that defines which manufacturers, models, and operating systems to include.
---
## How It Works
### Phase 1 — Driver Pack Creation (Infrastructure / Build Server)
`Invoke-DriverPackageCreator.ps1` is run on a build server or administrative workstation. It:
- Reads the XML settings file (`Content\Settings\Settings.xml`) to determine which manufacturers, models, and OS versions to process.
- Downloads the vendor driver pack catalogs (`.cab` / `.xml`) from Dell, HP, and Lenovo.
- Matches catalog entries to the models and operating systems defined in the XML.
- Downloads the applicable driver packs.
- Extracts driver packs using the bundled **7-Zip** tool (`Tools\X64\7z.exe` / `Tools\X86\7z.exe`).
- Compresses the extracted drivers into **WIM** images.
- Generates a metadata XML file (`DriverPackageList.xml`) that maps each WIM driver pack to its hardware product IDs and target OS.
### Phase 2 — Driver Pack Application (During OSD)
`Invoke-DriverPackageDownload.ps1` runs during an MDT or MECM task sequence. It:
- Detects the current device's manufacturer, product ID, and other hardware identifiers via WMI (`MS_SystemInformation`).
- Reads the deployed OS version and release from the offline Windows image registry hive.
- Reads the metadata XML to find the driver pack that matches both the hardware and the deployed OS.
- Supports **down-leveling** — falling back to an older OS release driver pack when an exact match is not available (can be disabled with `-DisableDownLeveling`).
- Downloads the matching WIM driver pack to the target volume.
- Applies (expands) the WIM to inject drivers into the deployed OS.
### Configuration Generator (Optional)
`Invoke-ConfigurationGenerator.ps1` automates the creation of the XML settings file. It can:
- Query a **SQL database** (e.g., the MECM database) to retrieve a list of all hardware models in the environment.
- Generate the full XML settings file with the correct manufacturer entries and model lists pre-populated.
---
## Repository Structure
```
ADDAP/
├── Invoke-DriverPackageCreator.ps1 # Downloads, extracts, and WIM-compresses driver packs
├── Invoke-DriverPackageDownload.ps1 # Runs during OSD to download and apply driver packs
├── Invoke-ConfigurationGenerator.ps1 # Generates the XML settings file (optional)
├── Content/
│ ├── Settings/
│ │ └── Template.xml # XML settings template (manufacturers, models, OS list)
│ ├── DBQueries/
│ │ └── GetProductIDList.sql # SQL query to retrieve model list from MECM database
│ └── ScheduledTasks/
│ └── Template.xml # Scheduled task template for automation
├── Functions/ # Helper PowerShell functions (dot-sourced at runtime)
│ ├── Convert-FileSize.ps1
│ ├── Copy-ItemWithProgress.ps1
│ ├── Get-WindowsReleaseHistory.ps1
│ ├── Invoke-FileDownload.ps1
│ ├── Invoke-FileDownloadWithProgress.ps1
│ ├── Invoke-RegistryHiveAction.ps1
│ ├── Invoke-SQLDBQuery.ps1
│ ├── Invoke-ScheduledTaskAction.ps1
│ ├── Start-ProcessWithOutput.ps1
│ └── Libraries/ # .NET assemblies (AlphaFS, HtmlAgilityPack, etc.)
├── Templates/
│ └── TaskSequences/
│ └── MDT/
│ └── ts.xml # Sample MDT task sequence template
├── Tools/
│ ├── X64/ # 64-bit 7-Zip binaries
│ └── X86/ # 32-bit 7-Zip binaries
└── SampleLogs/ # Example log output and DISM logs
```
---
## XML Settings Configuration
The settings XML (`Content\Settings\Template.xml`) controls all processing. Key sections:
### Parameters
| Parameter | Description |
|---|---|
| `ApplicationDataRootDirectory` | Root working directory for the script |
| `StagingDirectory` | Temporary staging area for downloads and extraction |
| `DownloadDirectory` | Where raw driver pack downloads are stored |
| `DriverPackageDirectory` | Output directory for the final WIM driver packages |
| `DisableDownload` | Skip downloading (use previously downloaded packs) |
| `Force` | Force reprocessing even if packages already exist |
| `ContinueOnError` | Continue processing remaining models on failure |
### Operating System List
Defines which Windows versions to target (e.g., Windows 10 x64, Windows 11 x64). Supports regex-based matching and a `LatestReleaseOnly` option.
### Manufacturer List
Each manufacturer entry includes:
- **Name** and **Eligibility Expression** — regex to match the device's `SystemManufacturer` WMI property.
- **Catalog URLs** — vendor-specific driver pack catalog download URLs.
- **Product ID Property** — which WMI property to use for hardware matching (`SystemSKU` for Dell, `BaseboardProduct` for HP, `SystemProductName` for Lenovo).
- **Model List** — the specific hardware models to process, each identified by `ProductID`, `BaseboardProduct`, `SystemSKU`, etc.
### Adding a New Model
Run the following PowerShell snippet on the target hardware to generate the XML node, then paste it into the appropriate manufacturer's `<ModelList>` section:
```powershell
$PropertyList = New-Object -TypeName 'System.Collections.Generic.List[Object]'
$PropertyList.Add(@{Name = 'Enabled'; Expression = {$True}})
$PropertyList.Add('SystemProductName')
$PropertyList.Add(@{Name = 'ProductID'; Expression = {$_.BaseboardProduct}})
$PropertyList.Add('BaseboardProduct')
$PropertyList.Add('SystemSKU')
$PropertyList.Add('SystemVersion')
$PropertyList.Add('SystemFamily')
$PropertyList.Add('SystemManufacturer')
$MSSystemInformation = Get-CIMInstance -Namespace "root\WMI" -Class "MS_SystemInformation" | Select-Object -Property ($PropertyList)
$XMLAttributes = $MSSystemInformation.PSObject.Properties | ForEach-Object {"$($_.Name)=`"$($_.Value)`""}
$XMLNode = "<Model $($XMLAttributes -Join ' ') />"
Write-Output -InputObject ($XMLNode)
$Null = $XMLNode | Set-Clipboard -Verbose
```
---
## Supported Vendors
| Vendor | Catalog Source | Product ID Property |
|---|---|---|
| **Dell** | [DriverPackCatalog.cab](https://dl.dell.com/catalog/DriverPackCatalog.cab) | `SystemSKU` |
| **HP** | [HPClientDriverPackCatalog.cab](https://ftp.hp.com/pub/caps-softpaq/cmit/HPClientDriverPackCatalog.cab) | `BaseboardProduct` |
| **Lenovo** | [catalogv2.xml](https://download.lenovo.com/cdrt/td/catalogv2.xml) | `SystemProductName` |
---
## Usage
### Prerequisites
- **PowerShell 3.0** or later.
- **Administrative privileges** (the scripts will self-elevate if not already running as admin).
- Network access to vendor catalog and download URLs.
- For OSD usage: an active **MDT** or **MECM** task sequence environment.
- For SQL-based configuration generation: access to a MECM SQL database.
### Creating Driver Packages
```powershell
# Run from an elevated PowerShell prompt
.\Invoke-DriverPackageCreator.ps1
```
The script will:
1. Create `Content\Settings\Settings.xml` from the template if it does not already exist.
2. Download vendor catalogs.
3. Download, extract, and WIM-compress driver packs for all enabled models and OS versions.
To add the current machine's model to the XML automatically:
```powershell
.\Invoke-DriverPackageCreator.ps1 -AdditionalXMLNodes '<Model Enabled="True" SystemProductName="Latitude 5430" ProductID="0B04" ... />'
```
### Generating Configuration from MECM Database
```powershell
.\Invoke-ConfigurationGenerator.ps1 -QuerySQLDatabase -SQLDatabaseFQDN "sqlserver.domain.com" -SQLDatabaseBName "CM_ABC"
```
### Downloading and Applying Drivers During OSD
Add `Invoke-DriverPackageDownload.ps1` as a **Run PowerShell Script** step in your MDT or MECM task sequence:
```powershell
.\Invoke-DriverPackageDownload.ps1 -DriverPackageRootDirectory "\\server\share\Out-Of-Box-Driver-Packages" -DriverPackageMetadataPath "\\server\share\Out-Of-Box-Driver-Packages\Metadata\DriverPackageList.xml"
```
Key parameters:
| Parameter | Description |
|---|---|
| `-DriverPackageRootDirectory` | UNC path to the root of the driver package share |
| `-DriverPackageMetadataPath` | Path to the metadata XML generated by the creator script |
| `-DisableDownLeveling` | Require an exact OS release match (no fallback) |
| `-Stage` | Stage (copy) the driver content locally before applying |
| `-RandomDelay` | Add a random delay before downloading (load balancing) |
| `-ContinueOnError` | Do not fail the task sequence on error |
---
## Logging
All scripts produce detailed transcript logs:
- **Creator script**: `%WINDIR%\Logs\Software\Invoke-DriverPackageCreator\`
- **Download script (full OS)**: `%WINDIR%\Logs\Software\Invoke-DriverPackageDownload\`
- **Download script (task sequence)**: The task sequence log directory (e.g., `_SMSTSLogPath`)
Log history is automatically maintained with a maximum of **3** log files per script.
---
## Requirements
- Windows PowerShell 3.0+
- Windows 10 / Windows 11 / Windows Server 2016+
- 7-Zip (bundled in `Tools\`)
- .NET Framework (for bundled libraries: AlphaFS, HtmlAgilityPack, NLog, NFluent, Registry)
+73
View File
@@ -0,0 +1,73 @@
<?xml version="1.0"?>
<sequence version="3.00" name="Custom Task Sequence" description="Sample Custom Task Sequence">
<group expand="true" name="Driver Package Actions" description="" disable="false" continueOnError="false">
<action />
<group expand="true" name="Variables" description="" disable="false" continueOnError="false">
<action />
<step type="SMS_TaskSequence_SetVariableAction" name="CustomContentPath" description="Set this location to the path where " disable="false" continueOnError="false" successCodeList="0 3010">
<defaultVarList>
<variable name="VariableName" property="VariableName">CustomContentPath</variable>
<variable name="VariableValue" property="VariableValue">%ScriptRoot%\Custom</variable>
</defaultVarList>
<action>cscript.exe "%SCRIPTROOT%\ZTISetVariable.wsf"</action>
<condition>
<operator type="not">
<expression type="SMS_TaskSequence_VariableConditionExpression">
<variable name="Variable">CustomContentPath</variable>
<variable name="Operator">exists</variable>
<variable name="Value"></variable>
</expression>
</operator>
</condition>
</step>
<step type="SMS_TaskSequence_SetVariableAction" name="DownloadSegmentSize" description="Controls the download buffer for the script that performs the downloading of the driver package(s)." disable="false" continueOnError="false" successCodeList="0 3010">
<defaultVarList>
<variable name="VariableName" property="VariableName">DownloadSegmentSize</variable>
<variable name="VariableValue" property="VariableValue">102400</variable>
</defaultVarList>
<action>cscript.exe "%SCRIPTROOT%\ZTISetVariable.wsf"</action>
<condition>
<operator type="not">
<expression type="SMS_TaskSequence_VariableConditionExpression">
<variable name="Variable">DownloadSegmentSize</variable>
<variable name="Operator">exists</variable>
<variable name="Value"></variable>
</expression>
</operator>
</condition>
</step>
<step type="SMS_TaskSequence_SetVariableAction" name="DriverPackageRootDirectory" description="This is the root directory where driver package(s) will be retrieved for download." disable="false" continueOnError="false" successCodeList="0 3010">
<defaultVarList>
<variable name="VariableName" property="VariableName">DriverPackageRootDirectory</variable>
<variable name="VariableValue" property="VariableValue">%DEPLOYROOT%\Out-Of-Box-Driver-Packages</variable>
</defaultVarList>
<action>cscript.exe "%SCRIPTROOT%\ZTISetVariable.wsf"</action>
</step>
<step type="SMS_TaskSequence_SetVariableAction" name="DriverPackageMetadataPath" description="This is the path to the XML that will be referenced to determine which of the downloaded driver package(s) are applicable to the device and operating system being deployed." disable="false" continueOnError="false" successCodeList="0 3010">
<defaultVarList>
<variable name="VariableName" property="VariableName">DriverPackageMetadataPath</variable>
<variable name="VariableValue" property="VariableValue">%DriverPackageRootDirectory%\Metadata\DriverPackageList.xml</variable>
</defaultVarList>
<action>cscript.exe "%SCRIPTROOT%\ZTISetVariable.wsf"</action>
</step>
<step type="SMS_TaskSequence_SetVariableAction" name="StagingRootDirectory" description="After the drivers have been downloaded and installed, the driver(s) can be optionally staged on the local disk for recovery/reinstallation situations." disable="false" continueOnError="false" successCodeList="0 3010">
<defaultVarList>
<variable name="VariableName" property="VariableName">StagingRootDirectory</variable>
<variable name="VariableValue" property="VariableValue">%OSDisk%\DriverCache</variable>
</defaultVarList>
<action>cscript.exe "%SCRIPTROOT%\ZTISetVariable.wsf"</action>
</step>
</group>
<group expand="true" name="Scripts" description="" disable="false" continueOnError="false">
<action />
<step type="BDD_RunPowerShellAction" name="Download and apply driver package(s)" description="Using the XML metadata file, an attempt to identify, download, mount, and apply any and all relevant driver package(s) for the platform." disable="false" continueOnError="false" successCodeList="0 3010">
<defaultVarList>
<variable name="ScriptName" property="ScriptName">%CustomContentPath%\Invoke-DriverPackageAction\Invoke-DriverPackageDownload.ps1</variable>
<variable name="Parameters" property="Parameters">-SegmentSize %DownloadSegmentSize% -DPRD '%DriverPackageRootDirectory%' -DPMDP '%DriverPackageMetadataPath%' -StageDriversLocally -SRD '%StagingRootDirectory%'</variable>
<variable name="PackageID" property="PackageID" />
</defaultVarList>
<action>cscript.exe "%SCRIPTROOT%\ZTIPowerShell.wsf</action>
</step>
</group>
</group>
</sequence>