forked from MSEndpointMgr/ModernDriverManagement
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Invoke-CMApplyDriverPackage_Legacy.ps1
1877 lines (1602 loc) · 96.3 KB
/
Invoke-CMApplyDriverPackage_Legacy.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<#
.SYNOPSIS
Download driver package (regular package) matching computer model, manufacturer and operating system.
.DESCRIPTION
This script will determine the model of the computer, manufacturer and operating system being deployed and then query
the specified endpoint for ConfigMgr WebService for a list of Packages. It then sets the OSDDownloadDownloadPackages variable
to include the PackageID property of a package matching the computer model. If multiple packages are detect, it will select
most current one by the creation date of the packages.
.PARAMETER URI
Set the URI for the ConfigMgr WebService.
.PARAMETER SecretKey
Specify the known secret key for the ConfigMgr WebService.
.PARAMETER DeploymentType
Define a different deployment scenario other than the default behavior. Choose between BareMetal (default), OSUpgrade, DriverUpdate or PreCache (Same as OSUpgrade but only downloads the package content).
.PARAMETER Filter
Define a filter used when calling ConfigMgr WebService to only return objects matching the filter.
.PARAMETER OperationalMode
Define the operational mode, either Production or Pilot, for when calling ConfigMgr WebService to only return objects matching the selected operational mode.
.PARAMETER UseDriverFallback
Specify if the script is to be used with a driver fallback package when a driver package for SystemSKU or computer model could not be detected.
.PARAMETER DriverInstallMode
Specify whether to install drivers using DISM.exe with recurse option or spawn a new process for each driver.
.PARAMETER DebugMode
Use this switch when running script outside of a Task Sequence.
.PARAMETER TSPackageID
Specify the Task Sequence PackageID when running in debug mode.
.PARAMETER Manufacturer
Override the automatically detected computer manufacturer when running in debug mode.
.PARAMETER ComputerModel
Override the automatically detected computer model when running in debug mode.
.PARAMETER SystemSKU
Override the automatically detected SystemSKU when running in debug mode.
.PARAMETER OSImageTSVariableName
Specify a Task Sequence variable name that should contain a value for an OS Image package ID that will be used to override automatic detection.
.PARAMETER TargetOSVersion
Define the value that will be used as the target operating system version e.g. 18363.
.PARAMETER OSVersionFallback
Use this switch to check for drivers packages that matches earlier versions of Windows than what's detected from web service call.
.EXAMPLE
# Detect, download and apply drivers during OS deployment with ConfigMgr:
.\Invoke-CMApplyDriverPackage.ps1 -URI "http://CM01.domain.com/ConfigMgrWebService/ConfigMgr.asmx" -SecretKey "12345" -Filter "Drivers"
# Detect, download and apply drivers during OS deployment with ConfigMgr and use a driver fallback package:
.\Invoke-CMApplyDriverPackage.ps1 -URI "http://CM01.domain.com/ConfigMgrWebService/ConfigMgr.asmx" -SecretKey "12345" -Filter "Drivers" -UseDriverFallback
# Detect and download drivers during OS upgrade with ConfigMgr:
.\Invoke-CMApplyDriverPackage.ps1 -URI "http://CM01.domain.com/ConfigMgrWebService/ConfigMgr.asmx" -SecretKey "12345" -Filter "Drivers" -DeploymentType OSUpgrade
# Detect, download and update with latest drivers for an existing operating system using ConfigMgr:
.\Invoke-CMApplyDriverPackage.ps1 -URI "http://CM01.domain.com/ConfigMgrWebService/ConfigMgr.asmx" -SecretKey "12345" -Filter "Drivers" -DeploymentType DriverUpdate
# Detect, download and apply drivers during OS deployment with ConfigMgr when using multiple Apply Operating System steps in the task sequence:
.\Invoke-CMApplyDriverPackage.ps1 -URI "http://CM01.domain.com/ConfigMgrWebService/ConfigMgr.asmx" -SecretKey "12345" -Filter "Drivers" -OSImageTSVariableName "OSImageVariable"
# Detect and download (pre-caching content) during OS upgrade with ConfigMgr:
.\Invoke-CMApplyDriverPackage.ps1 -URI "http://CM01.domain.com/ConfigMgrWebService/ConfigMgr.asmx" -SecretKey "12345" -Filter "Drivers" -DeploymentType "PreCache"
# Run in a debug mode for testing purposes (to be used locally on the computer model):
.\Invoke-CMApplyDriverPackage.ps1 -URI "http://CM01.domain.com/ConfigMgrWebService/ConfigMgr.asmx" -SecretKey "12345" -Filter "Drivers" -DebugMode -TSPackageID "P0100001"
# Run in a debug mode for testing purposes and overriding the automatically detected computer details (could be executed basically anywhere):
.\Invoke-CMApplyDriverPackage.ps1 -URI "http://CM01.domain.com/ConfigMgrWebService/ConfigMgr.asmx" -SecretKey "12345" -Filter "Drivers" -DebugMode -TSPackageID "P0100001" -Manufacturer "Hewlett-Packard" -ComputerModel "HP EliteBook 820 G5" -SystemSKU "1234"
.NOTES
FileName: Invoke-CMApplyDriverPackage.ps1
Author: Nickolaj Andersen / Maurice Daly
Contact: @NickolajA / @MoDaly_IT
Created: 2017-03-27
Updated: 2020-08-07
Minimum required version of ConfigMgr WebService: 1.6.0
Contributors: @CodyMathis123, @JamesMcwatty
Version history:
1.0.0 - (2017-03-27) Script created
1.0.1 - (2017-04-18) Updated script with better support for multiple vendor entries
1.0.2 - (2017-04-22) Updated script with support for multiple operating systems driver packages, e.g. Windows 8.1 and Windows 10
1.0.3 - (2017-05-03) Updated script with support for manufacturer specific Windows 10 versions for HP and Microsoft
1.0.4 - (2017-05-04) Updated script to trim any white spaces trailing the computer model detection from WMI
1.0.5 - (2017-05-05) Updated script to pull the model for Lenovo systems from the correct WMI class
1.0.6 - (2017-05-22) Updated script to detect the proper package based upon OS Image version referenced in task sequence when multiple packages are detected
1.0.7 - (2017-05-26) Updated script to filter OS when multiple model matches are found for different OS platforms
1.0.8 - (2017-06-26) Updated script with improved computer name matching when filtering out packages returned from the web service
1.0.9 - (2017-08-25) Updated script to read package description for Microsoft models in order to match the WMI value contained within
1.1.0 - (2017-08-29) Updated script to only check for the OS build version instead of major, minor, build and revision for HP systems. $OSImageVersion will now only contain the most recent version if multiple OS images is referenced in the Task Sequence
1.1.1 - (2017-09-12) Updated script to match the system SKU for Dell, Lenovo and HP models. Added architecture check for matching packages
1.1.2 - (2017-09-15) Replaced computer model matching with SystemSKU. Added script with support for different exit codes
1.1.3 - (2017-09-18) Added support for downloading package content instead of setting OSDDownloadDownloadPackages variable
1.1.4 - (2017-09-19) Added support for installing driver package directly from this script instead of running a seperate DISM command line step
1.1.5 - (2017-10-12) Added support for in full OS driver maintenance updates
1.1.6 - (2017-10-29) Fixed an issue when detecting Microsoft manufacturer information
1.1.7 - (2017-10-29) Changed the OSMaintenance parameter from a string to a switch object, make sure that your implementation of this is amended in any task sequence steps
1.1.8 - (2017-11-07) Added support for driver fallback packages when the UseDriverFallback param is used
1.1.9 - (2017-12-12) Added additional output for failure to detect system SKU value from WMI
1.2.0 - (2017-12-14) Fixed an issue where the HP packages would not properly be matched against the OS image version returned by the web service
1.2.1 - (2018-01-03) IMPORTANT - OSMaintenance switch has been replaced by the DeploymentType parameter. In order to support the default behavior (BareMetal), OSUpgrade and DriverUpdate operational
modes for the script, this change was required. Update your task sequence configuration before you use this update.
2.0.0 - (2018-01-10) Updates include support for machines with blank system SKU values and the ability to run BIOS & driver updates in the FULL OS
2.0.1 - (2018-01-18) Fixed a regex issue when attempting to fallback to computer model instead of SystemSKU
2.0.2 - (2018-01-24) Re-constructed the logic for matching driver package to begin with computer model or SystemSKU (SystemSKU takes precedence before computer model) and improved the logging when matching for driver packages
2.0.3 - (2018-01-25) Added a fix for multiple manufacturer package matches not working for Windows 7. Fixed an issue where SystemSKU was used and multiple driver packages matched. Added script line logging when the script cought an exception.
2.0.4 - (2018-01-26) Changed from using a foreach loop to a for loop in reverse to remove driver packages that was matched by SystemSKU but does not match the computer model
2.0.5 - (2018-01-29) Replaced Add-Content with Out-File for issue with file lock causing not all log entries to be written to the ApplyDriverPackage.log file
2.0.6 - (2018-02-21) Updated to cater for the presence of underscores in Microsoft Surface models
2.0.7 - (2018-02-25) Added support for a DebugMode switch for running script outside of a task sequence for driver package detection
2.0.8 - (2018-02-25) Added a check to bail out the script if computer model and SystemSKU are null or an empty string
2.0.9 - (2018-05-07) Removed exit code 34 event. DISM will now continue to process drivers if a single or multiple failures occur in order to proceed with the task sequence
2.1.0 - (2018-06-01) IMPORTANT: From this version, ConfigMgr WebService 1.6 is required. Added a new parameter named OSImageTSVariableName that accepts input of a task sequence variable. This task sequence variable should contain the OS Image package ID of
the desired Operating System Image selected in an Apply Operating System step. This new functionality allows for using multiple Apply Operating System steps in a single task sequence. Added Panasonic for manufacturer detection.
Improved logic with fallback from SystemSKU to computer model. Script will now fall back to computer model if there was no match to the SystemSKU. This still requires that the SystemSKU contains a value and is not null or empty, otherwise
the logic will directly fall back to computer model. A new parameter named DriverInstallMode has been added to control how drivers are installed for BareMetal deployment. Valid inputs are Single or Recurse.
2.1.1 - (2018-08-28) Code tweaks and changes for Windows build to version switch in the Driver Automation Tool. Improvements to the SystemSKU reverse section for HP models and multiple SystemSKU values from WMI
2.1.2 - (2018-08-29) Added code to handle Windows 10 version specific matching and also support matching for the name only
2.1.3 - (2018-09-03) Code tweak to Windows 10 version matching process
2.1.4 - (2018-09-18) Added support to override the task sequence package ID retrieved from _SMSTSPackageID when the Apply Operating System step is in a child task sequence
2.1.5 - (2018-09-18) Updated the computer model detection logic that replaces parts of the string from the PackageName property to retrieve the computer model only
2.1.6 - (2019-01-28) Fixed an issue with the recurse injection of drivers for a single detected driver package that was using an unassigned variable
2.1.7 - (2019-02-13) Added support for Windows 10 version 1809 in the Get-OSDetails function
2.1.8 - (2019-02-13) Added trimming of manufacturer and models data gathering from WMI
2.1.9 - (2019-03-06) Added support for non-terminating error when no matching driver packages where detected for OSUpgrade and DriverUpdate deployment types
2.2.0 - (2019-03-08) Fixed an issue when attempting to run the script with -DebugMode switch that would cause it to break when it couldn't load the TS environment
2.2.1 - (2019-03-29) New deployment type named 'PreCache' that allows the script to run in a pre-caching mode in a content pre-cache task sequence. When this deployment type is used, content will only be downloaded if it doesn't already
exist in the CCMCache. New parameter OperationalMode (defaults to Production) for better handling driver packages set for Pilot or Production deployment.
2.2.2 - (2019-05-14) Improved the Surface model detection from WMI
2.2.3 - (2019-05-14) Fixed an issue when multiple matching driver packages for a given model would only attempt to format the computer model name correctly for HP computers
2.2.4 - (2019-08-09) Fixed an issue on OperationalMode Production to filter out pilot and retired packages
2.2.5 - (2019-12-02) Added support for Windows 10 1903, 1909 and additional matching for Microsoft Surface devices (DAT 6.4.0 or neweer)
2.2.6 - (2020-02-06) Fixed an issue where the single driver injection mode for BareMetal deployments would fail if there was a space in the driver inf name
2.2.7 - (2020-02-10) Added a new parameter named TargetOSVersion. Use this parameter when DeploymentType is OSUpgrade and you don't want to rely on the OS version detected from the imported Operating System Upgrade Package or Operating System Image objects.
This parameter should mainly be used as an override and was implemented due to drivers for Windows 10 1903 were incorrectly detected when deploying or upgrading to Windows 10 1909 using imported source files, not for a
reference image for Windows 10 1909 as the Enablement Package would have flipped the build change to 18363 in such an image.
3.0.0 - (2020-03-14) A complete re-written version of the script. Includes a much improved logging functionality. Script is now divided into phases, which are represented in the ApplyDriverPackage.log that will provide a better troubleshooting experience.
Added support for AZW and Fujitsu computer manufacturer by request from the community. Extended DebugMode to allow for overriding computer details, which allows the script to be tested against any model and it doesn't require to be tested
directly on the model itself.
3.0.1 - (2020-03-25) Added TargetOSVersion parameter to be allowed to used in DebugMode. Fixed an issue where DebugMode would not be allowed to run on virtual machines. Fixed an issue where ComputerDetectionMethod script variable would be set to ComputerModel from
SystemSKU in case it couldn't match on the first driver package, leading to HP driver packages would always fail since they barely never match on the ComputerModel (they include 'Base Model', 'Notebook PC' etc.)
3.0.2 - (2020-03-29) Fixed a spelling mistake in the Manufacturer parameter.
3.0.3 - (2020-03-31) Small update to the Filter parameter's default value, it's now 'Drivers' instead of 'Driver'. Also added '64 bits' and '32 bits' to the translation function for the OS architecture of the current running task sequence.
3.0.4 - (2020-04-09) Changed the translation function for the OS architecture of the current running task sequence into using wildcard support instead of adding language specified values
3.0.5 - (2020-04-30) Added 7-Zip self extracting exe support for compressed driver packages
3.0.6 - (2020-07-24) Added support for Windows 10 version 2004 and additional logging for when constructing custom driver package objects for matching process
3.0.7 - (2020-08-05) Fixed a bug that would cause the script to crash in case the SKU input string from the driver package properties would contain a space character instead of a comma
3.0.8 - (2020-08-07) Fixed an issue where the Confirm-SystemSKU function would cause the script to crash if the SystemSKU data was improperly conformed, for instance with duplicate entries
#>
[CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = "Execute")]
param (
[parameter(Mandatory = $true, ParameterSetName = "Execute", HelpMessage = "Set the URI for the ConfigMgr WebService.")]
[parameter(Mandatory = $true, ParameterSetName = "Debug")]
[ValidateNotNullOrEmpty()]
[string]$URI,
[parameter(Mandatory = $true, ParameterSetName = "Execute", HelpMessage = "Specify the known secret key for the ConfigMgr WebService.")]
[parameter(Mandatory = $true, ParameterSetName = "Debug")]
[ValidateNotNullOrEmpty()]
[string]$SecretKey,
[parameter(Mandatory = $false, ParameterSetName = "Execute", HelpMessage = "Define a different deployment scenario other than the default behavior. Choose between BareMetal (default), OSUpgrade, DriverUpdate or PreCache (Same as OSUpgrade but only downloads the package content).")]
[parameter(Mandatory = $false, ParameterSetName = "Debug")]
[ValidateSet("BareMetal", "OSUpgrade", "DriverUpdate", "PreCache")]
[string]$DeploymentType = "BareMetal",
[parameter(Mandatory = $false, ParameterSetName = "Execute", HelpMessage = "Define a filter used when calling ConfigMgr WebService to only return objects matching the filter.")]
[parameter(Mandatory = $false, ParameterSetName = "Debug")]
[ValidateNotNullOrEmpty()]
[string]$Filter = "Drivers",
[parameter(Mandatory = $false, ParameterSetName = "Execute", HelpMessage = "Define the operational mode, either Production or Pilot, for when calling ConfigMgr WebService to only return objects matching the selected operational mode.")]
[parameter(Mandatory = $false, ParameterSetName = "Debug")]
[ValidateNotNullOrEmpty()]
[ValidateSet("Production", "Pilot")]
[string]$OperationalMode = "Production",
[parameter(Mandatory = $false, ParameterSetName = "Execute", HelpMessage = "Specify if the script is to be used with a driver fallback package when a driver package for SystemSKU or computer model could not be detected.")]
[parameter(Mandatory = $false, ParameterSetName = "Debug")]
[switch]$UseDriverFallback,
[parameter(Mandatory = $false, ParameterSetName = "Execute", HelpMessage = "Specify whether to install drivers using DISM.exe with recurse option or spawn a new process for each driver.")]
[ValidateNotNullOrEmpty()]
[ValidateSet("Single", "Recurse")]
[string]$DriverInstallMode = "Recurse",
[parameter(Mandatory = $true, ParameterSetName = "Debug", HelpMessage = "Use this switch when running script outside of a Task Sequence.")]
[switch]$DebugMode,
[parameter(Mandatory = $true, ParameterSetName = "Debug", HelpMessage = "Specify the Task Sequence PackageID when running in debug mode.")]
[ValidateNotNullOrEmpty()]
[string]$TSPackageID,
[parameter(Mandatory = $false, ParameterSetName = "Debug", HelpMessage = "Override the automatically detected computer manufacturer when running in debug mode.")]
[ValidateNotNullOrEmpty()]
[ValidateSet("Hewlett-Packard", "HP", "Dell", "Lenovo", "Microsoft", "Fujitsu", "Panasonic", "Viglen", "AZW")]
[string]$Manufacturer,
[parameter(Mandatory = $false, ParameterSetName = "Debug", HelpMessage = "Override the automatically detected computer model when running in debug mode.")]
[ValidateNotNullOrEmpty()]
[string]$ComputerModel,
[parameter(Mandatory = $false, ParameterSetName = "Debug", HelpMessage = "Override the automatically detected SystemSKU when running in debug mode.")]
[ValidateNotNullOrEmpty()]
[string]$SystemSKU,
[parameter(Mandatory = $false, ParameterSetName = "Execute", HelpMessage = "Specify a Task Sequence variable name that should contain a value for an OS Image package ID that will be used to override automatic detection.")]
[ValidateNotNullOrEmpty()]
[string]$OSImageTSVariableName,
[parameter(Mandatory = $false, ParameterSetName = "Execute", HelpMessage = "Specify a task sequence package ID for a child task sequence. Should only be used when the Apply Operating System step is in a child task sequence.")]
[ValidateNotNullOrEmpty()]
[string]$OverrideTSPackageID,
[parameter(Mandatory = $false, ParameterSetName = "Execute", HelpMessage = "Define the value that will be used as the target operating system version e.g. 18363.")]
[parameter(Mandatory = $false, ParameterSetName = "Debug")]
[ValidateNotNullOrEmpty()]
[string]$TargetOSVersion,
[parameter(Mandatory = $false, ParameterSetName = "Execute", HelpMessage = "Use this switch to check for drivers packages that matches earlier versions of Windows than what's detected from web service call.")]
[parameter(Mandatory = $false, ParameterSetName = "Debug")]
[switch]$OSVersionFallback
)
Begin {
# Load Microsoft.SMS.TSEnvironment COM object
if ($PSCmdLet.ParameterSetName -like "Execute") {
try {
$TSEnvironment = New-Object -ComObject Microsoft.SMS.TSEnvironment -ErrorAction Continue
}
catch [System.Exception] {
Write-Warning -Message "Unable to construct Microsoft.SMS.TSEnvironment object"
}
}
}
Process {
# Set Log Path
switch ($DeploymentType) {
"OSUpgrade" {
$LogsDirectory = Join-Path -Path $env:SystemRoot -ChildPath "Temp"
}
"DriverUpdate" {
$LogsDirectory = Join-Path -Path $env:SystemRoot -ChildPath "Temp"
}
Default {
if (-not($PSCmdLet.ParameterSetName -like "Execute")) {
$LogsDirectory = Join-Path -Path $env:SystemRoot -ChildPath "Temp"
}
else {
$LogsDirectory = $Script:TSEnvironment.Value("_SMSTSLogPath")
}
}
}
# Functions
function Write-CMLogEntry {
param (
[parameter(Mandatory = $true, HelpMessage = "Value added to the log file.")]
[ValidateNotNullOrEmpty()]
[string]$Value,
[parameter(Mandatory = $true, HelpMessage = "Severity for the log entry. 1 for Informational, 2 for Warning and 3 for Error.")]
[ValidateNotNullOrEmpty()]
[ValidateSet("1", "2", "3")]
[string]$Severity,
[parameter(Mandatory = $false, HelpMessage = "Name of the log file that the entry will written to.")]
[ValidateNotNullOrEmpty()]
[string]$FileName = "ApplyDriverPackage.log"
)
# Determine log file location
$LogFilePath = Join-Path -Path $LogsDirectory -ChildPath $FileName
# Construct time stamp for log entry
if (-not(Test-Path -Path 'variable:global:TimezoneBias')) {
[string]$global:TimezoneBias = [System.TimeZoneInfo]::Local.GetUtcOffset((Get-Date)).TotalMinutes
if ($TimezoneBias -match "^-") {
$TimezoneBias = $TimezoneBias.Replace('-', '+')
}
else {
$TimezoneBias = '-' + $TimezoneBias
}
}
$Time = -join @((Get-Date -Format "HH:mm:ss.fff"), $TimezoneBias)
# Construct date for log entry
$Date = (Get-Date -Format "MM-dd-yyyy")
# Construct context for log entry
$Context = $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)
# Construct final log entry
$LogText = "<![LOG[$($Value)]LOG]!><time=""$($Time)"" date=""$($Date)"" component=""ApplyDriverPackage"" context=""$($Context)"" type=""$($Severity)"" thread=""$($PID)"" file="""">"
# Add value to log file
try {
Out-File -InputObject $LogText -Append -NoClobber -Encoding Default -FilePath $LogFilePath -ErrorAction Stop
}
catch [System.Exception] {
Write-Warning -Message "Unable to append log entry to ApplyDriverPackage.log file. Error message at line $($_.InvocationInfo.ScriptLineNumber): $($_.Exception.Message)"
}
}
function Invoke-Executable {
param (
[parameter(Mandatory = $true, HelpMessage = "Specify the file name or path of the executable to be invoked, including the extension")]
[ValidateNotNullOrEmpty()]
[string]$FilePath,
[parameter(Mandatory = $false, HelpMessage = "Specify arguments that will be passed to the executable")]
[ValidateNotNull()]
[string]$Arguments
)
# Construct a hash-table for default parameter splatting
$SplatArgs = @{
FilePath = $FilePath
NoNewWindow = $true
Passthru = $true
ErrorAction = "Stop"
}
# Add ArgumentList param if present
if (-not ([System.String]::IsNullOrEmpty($Arguments))) {
$SplatArgs.Add("ArgumentList", $Arguments)
}
# Invoke executable and wait for process to exit
try {
$Invocation = Start-Process @SplatArgs
$Handle = $Invocation.Handle
$Invocation.WaitForExit()
}
catch [System.Exception] {
Write-Warning -Message $_.Exception.Message; break
}
return $Invocation.ExitCode
}
function Invoke-CMDownloadContent {
param (
[parameter(Mandatory = $true, ParameterSetName = "NoPath", HelpMessage = "Specify a PackageID that will be downloaded.")]
[Parameter(ParameterSetName = "CustomPath")]
[ValidateNotNullOrEmpty()]
[ValidatePattern("^[A-Z0-9]{3}[A-F0-9]{5}$")]
[string]$PackageID,
[parameter(Mandatory = $true, ParameterSetName = "NoPath", HelpMessage = "Specify the download location type.")]
[Parameter(ParameterSetName = "CustomPath")]
[ValidateNotNullOrEmpty()]
[ValidateSet("Custom", "TSCache", "CCMCache")]
[string]$DestinationLocationType,
[parameter(Mandatory = $true, ParameterSetName = "NoPath", HelpMessage = "Save the download location to the specified variable name.")]
[Parameter(ParameterSetName = "CustomPath")]
[ValidateNotNullOrEmpty()]
[string]$DestinationVariableName,
[parameter(Mandatory = $true, ParameterSetName = "CustomPath", HelpMessage = "When location type is specified as Custom, specify the custom path.")]
[ValidateNotNullOrEmpty()]
[string]$CustomLocationPath
)
# Set OSDDownloadDownloadPackages
Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDownloadPackages to: $($PackageID)" -Severity 1
$TSEnvironment.Value("OSDDownloadDownloadPackages") = "$($PackageID)"
# Set OSDDownloadDestinationLocationType
Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDestinationLocationType to: $($DestinationLocationType)" -Severity 1
$TSEnvironment.Value("OSDDownloadDestinationLocationType") = "$($DestinationLocationType)"
# Set OSDDownloadDestinationVariable
Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDestinationVariable to: $($DestinationVariableName)" -Severity 1
$TSEnvironment.Value("OSDDownloadDestinationVariable") = "$($DestinationVariableName)"
# Set OSDDownloadDestinationPath
if ($DestinationLocationType -like "Custom") {
Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDestinationPath to: $($CustomLocationPath)" -Severity 1
$TSEnvironment.Value("OSDDownloadDestinationPath") = "$($CustomLocationPath)"
}
# Invoke download of package content
try {
if ($TSEnvironment.Value("_SMSTSInWinPE") -eq $false) {
Write-CMLogEntry -Value " - Starting package content download process (FullOS), this might take some time" -Severity 1
$ReturnCode = Invoke-Executable -FilePath (Join-Path -Path $env:windir -ChildPath "CCM\OSDDownloadContent.exe")
}
else {
Write-CMLogEntry -Value " - Starting package content download process (WinPE), this might take some time" -Severity 1
$ReturnCode = Invoke-Executable -FilePath "OSDDownloadContent.exe"
}
# Match on return code
if ($ReturnCode -eq 0) {
Write-CMLogEntry -Value " - Successfully downloaded package content with PackageID: $($PackageID)" -Severity 1
}
}
catch [System.Exception] {
Write-CMLogEntry -Value " - An error occurred while attempting to download package content. Error message: $($_.Exception.Message)" -Severity 3
# Throw terminating error
$ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty)
$PSCmdlet.ThrowTerminatingError($ErrorRecord)
}
return $ReturnCode
}
function Invoke-CMResetDownloadContentVariables {
# Set OSDDownloadDownloadPackages
Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDownloadPackages to a blank value" -Severity 1
$TSEnvironment.Value("OSDDownloadDownloadPackages") = [System.String]::Empty
# Set OSDDownloadDestinationLocationType
Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDestinationLocationType to a blank value" -Severity 1
$TSEnvironment.Value("OSDDownloadDestinationLocationType") = [System.String]::Empty
# Set OSDDownloadDestinationVariable
Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDestinationVariable to a blank value" -Severity 1
$TSEnvironment.Value("OSDDownloadDestinationVariable") = [System.String]::Empty
# Set OSDDownloadDestinationPath
Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDestinationPath to a blank value" -Severity 1
$TSEnvironment.Value("OSDDownloadDestinationPath") = [System.String]::Empty
}
function Get-OSImageData {
# Determine how to get the SMSTSPackageID value
if ($PSCmdLet.ParameterSetName -eq "Execute") {
if ($Script:PSBoundParameters["OverrideTSPackageID"]) {
$SMSTSPackageID = $OverrideTSPackageID
}
else {
$SMSTSPackageID = $TSEnvironment.Value("_SMSTSPackageID")
}
}
else {
$SMSTSPackageID = $TSPackageID
}
try {
# Determine OS Image information for running task sequence from web service
Write-CMLogEntry -Value " - Attempting to detect OS Image data from task sequence with PackageID: $($SMSTSPackageID)" -Severity 1
$OSImages = $WebService.GetCMOSImageForTaskSequence($SecretKey, $SMSTSPackageID)
if ($OSImages -ne $null) {
if (($OSImages | Measure-Object).Count -ge 2) {
# Determine behavior when detecting OS Image data
if ($Script:PSBoundParameters["OSImageTSVariableName"]) {
# Select OS Image object matching the value from the task sequence variable passed to the OSImageTSVariableName parameter
Write-CMLogEntry -Value " - Multiple OS Image objects detected. Objects will be matched against provided task sequence variable name '$($OSImageTSVariableName)' to determine the correct object" -Severity 1
$OSImageTSVariableValue = $TSEnvironment.Value("$($OSImageTSVariableName)")
foreach ($OSImage in $OSImages) {
if ($OSImage.PackageID -like $OSImageTSVariableValue) {
# Handle support for target OS version override from parameter input
if ($Script:PSBoundParameters["TargetOSVersion"]) {
$OSBuild = "10.0.$($TargetOSVersion).1"
}
else {
$OSBuild = $OSImage.Version
}
# Create custom object for return value
$PSObject = [PSCustomObject]@{
OSVersion = $OSBuild
OSArchitecture = $OSImage.Architecture
}
# Handle return value
return $PSObject
}
}
}
else {
# Select the first object returned from web service call
Write-CMLogEntry -Value " - Multiple OS Image objects detected and OSImageTSVariableName was not specified. Selecting the first OS Image object from web service call" -Severity 1
$OSImage = $OSImages | Sort-Object -Descending | Select-Object -First 1
# Handle support for target OS version override from parameter input
if ($Script:PSBoundParameters["TargetOSVersion"]) {
$OSBuild = "10.0.$($TargetOSVersion).1"
}
else {
$OSBuild = $OSImage.Version
}
# Create custom object for return value
$PSObject = [PSCustomObject]@{
OSVersion = $OSBuild
OSArchitecture = $OSImage.Architecture
}
# Handle return value
return $PSObject
}
}
else {
# Handle support for target OS version override from parameter input
if ($Script:PSBoundParameters["TargetOSVersion"]) {
$OSBuild = "10.0.$($TargetOSVersion).1"
}
else {
$OSBuild = $OSImages.Version
}
# Create custom object for return value
$PSObject = [PSCustomObject]@{
OSVersion = $OSBuild
OSArchitecture = $OSImages.Architecture
}
# Handle return value
return $PSObject
}
}
else {
Write-CMLogEntry -Value " - Call to ConfigMgr WebService returned empty OS Image data. Error message: $($_.Exception.Message)" -Severity 3
# Throw terminating error
$ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty)
$PSCmdlet.ThrowTerminatingError($ErrorRecord)
}
}
catch [System.Exception] {
Write-CMLogEntry -Value " - An error occured while calling ConfigMgr WebService to get OS Image data. Error message: $($_.Exception.Message)" -Severity 3
# Throw terminating error
$ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty)
$PSCmdlet.ThrowTerminatingError($ErrorRecord)
}
}
function Get-OSArchitecture {
param (
[parameter(Mandatory = $true, HelpMessage = "OS architecture data to be translated.")]
[ValidateNotNullOrEmpty()]
[string]$InputObject
)
switch -Wildcard ($InputObject) {
"9" {
$OSImageArchitecture = "x64"
}
"0" {
$OSImageArchitecture = "x86"
}
"64*" {
$OSImageArchitecture = "x64"
}
"32*" {
$OSImageArchitecture = "x86"
}
default {
Write-CMLogEntry -Value " - Unable to translate OS architecture using input object: $($InputObject)" -Severity 3
# Throw terminating error
$ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty)
$PSCmdlet.ThrowTerminatingError($ErrorRecord)
}
}
# Handle return value from function
return $OSImageArchitecture
}
function Get-OSDetails {
param (
[parameter(Mandatory = $true, HelpMessage = "Windows build number must be provided")]
[ValidateNotNullOrEmpty()]
[string]$InputObject
)
# Get operating system name and from build number
switch -Wildcard ($InputObject) {
"10.0*" {
$OSName = "Windows 10"
switch (([System.Version]$InputObject).Build) {
"19041" {
$OSVersion = 2004
}
"18363" {
$OSVersion = 1909
}
"18362" {
$OSVersion = 1903
}
"17763" {
$OSVersion = 1809
}
"17134" {
$OSVersion = 1803
}
"16299" {
$OSVersion = 1709
}
"15063" {
$OSVersion = 1703
}
"14393" {
$OSVersion = 1607
}
}
}
default {
Write-CMLogEntry -Value " - Unable to translate OS name and version using input object: $($InputObject)" -Severity 3
# Throw terminating error
$ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty)
$PSCmdlet.ThrowTerminatingError($ErrorRecord)
}
}
# Handle return value from function
if (($OSName -ne $null) -and ($OSVersion -ne $null)) {
$PSObject = [PSCustomObject]@{
OSName = $OSName
OSVersion = $OSVersion
}
return $PSObject
}
else {
Write-CMLogEntry -Value " - Unable to translate OS name and version. Both properties did not contain any values" -Severity 3
# Throw terminating error
$ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty)
$PSCmdlet.ThrowTerminatingError($ErrorRecord)
}
}
function New-TerminatingErrorRecord {
param(
[parameter(Mandatory=$true, HelpMessage="Specify the exception message details.")]
[ValidateNotNullOrEmpty()]
[string]$Message,
[parameter(Mandatory=$false, HelpMessage="Specify the violation exception causing the error.")]
[ValidateNotNullOrEmpty()]
[string]$Exception = "System.Management.Automation.RuntimeException",
[parameter(Mandatory=$false, HelpMessage="Specify the error category of the exception causing the error.")]
[ValidateNotNullOrEmpty()]
[System.Management.Automation.ErrorCategory]$ErrorCategory = [System.Management.Automation.ErrorCategory]::NotImplemented,
[parameter(Mandatory=$false, HelpMessage="Specify the target object causing the error.")]
[ValidateNotNullOrEmpty()]
[string]$TargetObject = ([string]::Empty)
)
# Construct new error record to be returned from function based on parameter inputs
$SystemException = New-Object -TypeName $Exception -ArgumentList $Message
$ErrorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord -ArgumentList @($SystemException, $ErrorID, $ErrorCategory, $TargetObject)
# Handle return value
return $ErrorRecord
}
function Connect-WebService {
# Construct new web service proxy
try {
$WebService = New-WebServiceProxy -Uri $URI -ErrorAction Stop
Write-CMLogEntry -Value " - Successfully connected to ConfigMgr WebService at URI: $($URI)" -Severity 1
# Handle return value
return $WebService
}
catch [System.Exception] {
Write-CMLogEntry -Value " - Unable to establish a connection to ConfigMgr WebService. Error message: $($_.Exception.Message)" -Severity 3
# Throw terminating error
$ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty)
$PSCmdlet.ThrowTerminatingError($ErrorRecord)
}
}
function Get-OSImageDetails {
$OSImageDetails = [PSCustomObject]@{
Architecture = $null
Name = $null
Version = $null
}
switch ($DeploymentType) {
"BareMetal" {
# Get OS Image data
$OSImageData = Get-OSImageData
# Get OS data
$OSImageVersion = $OSImageData.OSVersion
$OSArchitecture = $OSImageData.OSArchitecture
# Translate operating system name from version
$OSDetails = Get-OSDetails -InputObject $OSImageVersion
$OSImageDetails.Name = $OSDetails.OSName
$OSImageDetails.Version = $OSDetails.OSVersion
# Translate operating system architecture from web service response
$OSImageDetails.Architecture = Get-OSArchitecture -InputObject $OSArchitecture
}
"OSUpgrade" {
# Get OS Image data
$OSImageData = Get-OSImageData
# Get OS data
$OSImageVersion = $OSImageData.OSVersion
$OSArchitecture = $OSImageData.OSArchitecture
# Translate operating system name from version
$OSDetails = Get-OSDetails -InputObject $OSImageVersion
$OSImageDetails.Name = $OSDetails.OSName
$OSImageDetails.Version = $OSDetails.OSVersion
# Translate operating system architecture from web service response
$OSImageDetails.Architecture = Get-OSArchitecture -InputObject $OSArchitecture
}
"DriverUpdate" {
# Get OS data
$OSImageVersion = Get-WmiObject -Class Win32_OperatingSystem | Select-Object -ExpandProperty Version
$OSArchitecture = Get-WmiObject -Class Win32_OperatingSystem | Select-Object -ExpandProperty OSArchitecture
# Translate operating system name from version
$OSDetails = Get-OSDetails -InputObject $OSImageVersion
$OSImageDetails.Name = $OSDetails.OSName
$OSImageDetails.Version = $OSDetails.OSVersion
# Translate operating system architecture from running operating system
$OSImageDetails.Architecture = Get-OSArchitecture -InputObject $OSArchitecture
}
"PreCache" {
# Get OS Image data
$OSImageData = Get-OSImageData
# Get OS data
$OSImageVersion = $OSImageData.OSVersion
$OSArchitecture = $OSImageData.OSArchitecture
# Translate operating system name from version
$OSDetails = Get-OSDetails -InputObject $OSImageVersion
$OSImageDetails.Name = $OSDetails.OSName
$OSImageDetails.Version = $OSDetails.OSVersion
# Translate operating system architecture from web service response
$OSImageDetails.Architecture = Get-OSArchitecture -InputObject $OSArchitecture
}
}
# Handle output to log file for OS image details
Write-CMLogEntry -Value " - Target operating system name detected as: $($OSImageDetails.Name)" -Severity 1
Write-CMLogEntry -Value " - Target operating system architecture detected as: $($OSImageDetails.Architecture)" -Severity 1
Write-CMLogEntry -Value " - Target operating system build version detected as: $($OSImageVersion)" -Severity 1
Write-CMLogEntry -Value " - Target operating system translated version detected as: $($OSImageDetails.Version)" -Severity 1
# Handle return value
return $OSImageDetails
}
function Get-DriverPackages {
param(
[parameter(Mandatory = $true, HelpMessage = "Specify the web service object returned from Connect-WebService function.")]
[ValidateNotNullOrEmpty()]
[PSCustomObject]$WebService
)
try {
# Retrieve driver packages but filter out matches depending on script operational mode
switch ($OperationalMode) {
"Production" {
$Packages = $WebService.GetCMPackage($SecretKey, $Filter) | Where-Object { $_.PackageName -notmatch "Pilot" -and $_.PackageName -notmatch "Retired" }
}
"Pilot" {
$Packages = $WebService.GetCMPackage($SecretKey, $Filter) | Where-Object { $_.PackageName -match "Pilot" }
}
}
# Handle return value
if ($Packages -ne $null) {
Write-CMLogEntry -Value " - Retrieved a total of '$(($Packages | Measure-Object).Count)' driver packages from web service matching operational mode: $($OperationalMode)" -Severity 1
return $Packages
}
else {
Write-CMLogEntry -Value " - Retrieved a total of '0' driver packages from web service matching operational mode: $($OperationalMode)" -Severity 3
# Throw terminating error
$ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty)
$PSCmdlet.ThrowTerminatingError($ErrorRecord)
}
}
catch [System.Exception] {
Write-CMLogEntry -Value " - An error occurred while calling ConfigMgr WebService for a list of available driver packages. Error message: $($_.Exception.Message)" -Severity 3
# Throw terminating error
$ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty)
$PSCmdlet.ThrowTerminatingError($ErrorRecord)
}
}
function Get-ComputerData {
# Create a custom object for computer details gathered from local WMI
$ComputerDetails = [PSCustomObject]@{
Manufacturer = $null
Model = $null
SystemSKU = $null
FallbackSKU = $null
}
# Gather computer details based upon specific computer manufacturer
$ComputerManufacturer = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Manufacturer).Trim()
switch -Wildcard ($ComputerManufacturer) {
"*Microsoft*" {
$ComputerDetails.Manufacturer = "Microsoft"
$ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim()
$ComputerDetails.SystemSKU = Get-WmiObject -Namespace "root\wmi" -Class "MS_SystemInformation" | Select-Object -ExpandProperty SystemSKU
}
"*HP*" {
$ComputerDetails.Manufacturer = "Hewlett-Packard"
$ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim()
$ComputerDetails.SystemSKU = (Get-CIMInstance -ClassName "MS_SystemInformation" -NameSpace "root\WMI").BaseBoardProduct.Trim()
}
"*Hewlett-Packard*" {
$ComputerDetails.Manufacturer = "Hewlett-Packard"
$ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim()
$ComputerDetails.SystemSKU = (Get-CIMInstance -ClassName "MS_SystemInformation" -NameSpace "root\WMI").BaseBoardProduct.Trim()
}
"*Dell*" {
$ComputerDetails.Manufacturer = "Dell"
$ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim()
$ComputerDetails.SystemSKU = (Get-CIMInstance -ClassName "MS_SystemInformation" -NameSpace "root\WMI").SystemSku.Trim()
[string]$OEMString = Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty OEMStringArray
$ComputerDetails.FallbackSKU = [regex]::Matches($OEMString, '\[\S*]')[0].Value.TrimStart("[").TrimEnd("]")
}
"*Lenovo*" {
$ComputerDetails.Manufacturer = "Lenovo"
$ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystemProduct" | Select-Object -ExpandProperty Version).Trim()
$ComputerDetails.SystemSKU = ((Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).SubString(0, 4)).Trim()
}
"*Panasonic*" {
$ComputerDetails.Manufacturer = "Panasonic Corporation"
$ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim()
$ComputerDetails.SystemSKU = (Get-CIMInstance -ClassName "MS_SystemInformation" -NameSpace "root\WMI").BaseBoardProduct.Trim()
}
"*Viglen*" {
$ComputerDetails.Manufacturer = "Viglen"
$ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim()
$ComputerDetails.SystemSKU = (Get-WmiObject -Class "Win32_BaseBoard" | Select-Object -ExpandProperty SKU).Trim()
}
"*AZW*" {
$ComputerDetails.Manufacturer = "AZW"
$ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim()
$ComputerDetails.SystemSKU = (Get-CIMInstance -ClassName "MS_SystemInformation" -NameSpace root\WMI).BaseBoardProduct.Trim()
}
"*Fujitsu*" {
$ComputerDetails.Manufacturer = "Fujitsu"
$ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim()
$ComputerDetails.SystemSKU = (Get-WmiObject -Class "Win32_BaseBoard" | Select-Object -ExpandProperty SKU).Trim()
}
}
# Handle overriding computer details if debug mode and additional parameters was specified
if ($Script:PSCmdlet.ParameterSetName -like "Debug") {
if (-not([string]::IsNullOrEmpty($Manufacturer))) {
$ComputerDetails.Manufacturer = $Manufacturer
}
if (-not([string]::IsNullOrEmpty($ComputerModel))) {
$ComputerDetails.Model = $ComputerModel
}
if (-not([string]::IsNullOrEmpty($SystemSKU))) {
$ComputerDetails.SystemSKU = $SystemSKU
}
}
# Handle output to log file for computer details
Write-CMLogEntry -Value " - Computer manufacturer determined as: $($ComputerDetails.Manufacturer)" -Severity 1
Write-CMLogEntry -Value " - Computer model determined as: $($ComputerDetails.Model)" -Severity 1
# Handle output to log file for computer SystemSKU
if (-not([string]::IsNullOrEmpty($ComputerDetails.SystemSKU))) {
Write-CMLogEntry -Value " - Computer SystemSKU determined as: $($ComputerDetails.SystemSKU)" -Severity 1
}
else {
Write-CMLogEntry -Value " - Computer SystemSKU determined as: <null>" -Severity 2
}
# Handle output to log file for Fallback SKU
if (-not([string]::IsNullOrEmpty($ComputerDetails.FallBackSKU))) {
Write-CMLogEntry -Value " - Computer Fallback SystemSKU determined as: $($ComputerDetails.FallBackSKU)" -Severity 1
}
# Handle return value from function
return $ComputerDetails
}
function Get-ComputerSystemType {
$ComputerSystemType = Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty "Model"
if ($ComputerSystemType -notin @("Virtual Machine", "VMware Virtual Platform", "VirtualBox", "HVM domU", "KVM")) {
Write-CMLogEntry -Value " - Supported computer platform detected, script execution allowed to continue" -Severity 1
}
else {
if ($Script:PSBoundParameters["DebugMode"]) {
Write-CMLogEntry -Value " - Unsupported computer platform detected, virtual machines are not supported but will be allowed in DebugMode" -Severity 2
}
else {
Write-CMLogEntry -Value " - Unsupported computer platform detected, virtual machines are not supported" -Severity 3
# Throw terminating error
$ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty)
$PSCmdlet.ThrowTerminatingError($ErrorRecord)
}
}
}
function Get-OperatingSystemVersion {
if ($DeploymentType -like "DriverUpdate") {
$OperatingSystemVersion = Get-WmiObject -Class "Win32_OperatingSystem" | Select-Object -ExpandProperty "Version"
if ($OperatingSystemVersion -like "10.0.*") {
Write-CMLogEntry -Value " - Supported operating system version currently running detected, script execution allowed to continue" -Severity 1
}
else {
Write-CMLogEntry -Value " - Unsupported operating system version detected, this script is only supported on Windows 10 and above" -Severity 3
# Throw terminating error
$ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty)
$PSCmdlet.ThrowTerminatingError($ErrorRecord)
}
}
}
function Test-ComputerDetails {
param(
[parameter(Mandatory = $true, HelpMessage = "Specify the computer details object from Get-ComputerDetails function.")]
[ValidateNotNullOrEmpty()]
[PSCustomObject]$InputObject
)
# Construct custom object for computer details validation
$Script:ComputerDetection = [PSCustomObject]@{
"ModelDetected" = $false
"SystemSKUDetected" = $false
}
if (($InputObject.Model -ne $null) -and (-not([System.String]::IsNullOrEmpty($InputObject.Model)))) {
Write-CMLogEntry -Value " - Computer model detection was successful" -Severity 1
$ComputerDetection.ModelDetected = $true
}
if (($InputObject.SystemSKU -ne $null) -and (-not([System.String]::IsNullOrEmpty($InputObject.SystemSKU)))) {
Write-CMLogEntry -Value " - Computer SystemSKU detection was successful" -Severity 1
$ComputerDetection.SystemSKUDetected = $true
}
if (($ComputerDetection.ModelDetected -eq $false) -and ($ComputerDetection.SystemSKUDetected -eq $false)) {
Write-CMLogEntry -Value " - Computer model and SystemSKU values are missing, script execution is not allowed since required values to continue could not be gathered" -Severity 3
# Throw terminating error
$ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty)
$PSCmdlet.ThrowTerminatingError($ErrorRecord)
}
else {
Write-CMLogEntry -Value " - Computer details successfully verified" -Severity 1
}
}
function Set-ComputerDetectionMethod {
if ($ComputerDetection.SystemSKUDetected -eq $true) {
Write-CMLogEntry -Value " - Determined primary computer detection method: SystemSKU" -Severity 1
return "SystemSKU"
}
else {
Write-CMLogEntry -Value " - Determined fallback computer detection method: ComputerModel" -Severity 1
return "ComputerModel"
}
}
function Confirm-DriverPackage {
param(
[parameter(Mandatory = $true, HelpMessage = "Specify the computer details object from Get-ComputerDetails function.")]
[ValidateNotNullOrEmpty()]
[PSCustomObject]$ComputerData,
[parameter(Mandatory = $true, HelpMessage = "Specify the OS Image details object from Get-OSImageDetails function.")]
[ValidateNotNullOrEmpty()]
[PSCustomObject]$OSImageData,
[parameter(Mandatory = $true, HelpMessage = "Specify the driver package object to be validated.")]
[ValidateNotNullOrEmpty()]
[System.Object[]]$DriverPackage,
[parameter(Mandatory = $false, HelpMessage = "Set to True to check for drivers packages that matches earlier versions of Windows than what's detected from web service call.")]
[ValidateNotNullOrEmpty()]
[bool]$OSVersionFallback = $false
)
# Sort all driver package objects by package name property
$DriverPackages = $DriverPackage | Sort-Object -Property PackageName
$DriverPackagesCount = ($DriverPackages | Measure-Object).Count
Write-CMLogEntry -Value " - Initial count of driver packages before starting filtering process: $($DriverPackagesCount)" -Severity 1