Public/OSD.WinPE.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
if ($env:SystemDrive -eq 'X:') {
    <#
    .SYNOPSIS
    Common WinPE Commands using wpeutil and Microsoft DaRT RemoteRecovery
 
    .DESCRIPTION
    Common WinPE Commands using wpeutil and Microsoft DaRT RemoteRecovery
 
    .LINK
    https://osd.osdeploy.com/module/functions/winpe/get-osdwinpe
 
    .NOTES
    19.10.1 David Segura @SeguraOSD
    #>

    function Get-OSDWinPE {
        [CmdletBinding()]
        param (
            #Find and Copy PowerShell Modules to WinPE
            #Searches all PSDrives for <drive>:\Modules directory
            #Searches all PSDrives for <drive>:\Content\Modules directory
            #Copies Modules to X:\Program Files\WindowsPowerShell\Modules
            [Alias('Modules','AddModules')]
            [System.Management.Automation.SwitchParameter]$GetModules,

            #Find and Run PowerShell Scripts
            #Searches all PSDrives for <drive>:\<$GetScript>
            #Searches all PSDrives for <drive>:\Content\Scripts\<$GetScript>
            #Calls found scripts in the current PS Session
            [Alias('Script','CallScript')]
            [string[]]$GetScripts,

            #wpeutil InitializeNetwork
            #Initializes network components and drivers and sets the computer name to a randomly-chosen value
            [Alias('Network')]
            [System.Management.Automation.SwitchParameter]$InitializeNetwork,

            #wpeutil InitializeNetwork /NoWait
            #Initializes network components and drivers and sets the computer name to a randomly-chosen value
            #The /NoWait option will skip the time where your PC would otherwise wait to acquire an IP address
            #If you don't use /NoWait, Windows PE will wait to acquire an address before it finishes loading your WinPE session
            #/NoWait is helpful for environments that don't use DHCP
            [Alias('NetworkNoWait')]
            [System.Management.Automation.SwitchParameter]$InitializeNetworkNoWait,

            #wpeutil WaitForNetwork
            #Waits for the network card to be initialized
            #Use this command when creating scripts to make sure that the network card has been fully initialized before continuing
            [Alias('WaitNetwork')]
            [System.Management.Automation.SwitchParameter]$WaitForNetwork,

            #wpeutil WaitForRemovableStorage
            #During the Windows PE startup sequence, this command will block startup until the removable storage devices, such as USB hard drives, are initialized
            [Alias('WaitUSB')]
            [System.Management.Automation.SwitchParameter]$WaitForRemovableStorage,

            #wpeutil DisableFirewall
            #Disables the Firewall
            [Alias('Disable')]
            [System.Management.Automation.SwitchParameter]$DisableFirewall,

            #wpeutil UpdateBootInfo
            #Populates the registry with information about how Windows PE boots
            #After you run this command, query the registry. For example:
            #reg query HKLM\System\CurrentControlSet\Control /v PEBootType
            #The results of this operation might change after loading additional driver support.
            #To determine where Windows PE is booted from, examine the following:
            # PEBootType: Error, Flat, Remote, Ramdisk:SourceIdentified Ramdisk:SourceUnidentified, Ramdisk:OpticalDrive
            # PEBootTypeErrorCode: HRESULT code
            # PEBootServerName: Windows Deployment Services server name
            # PEBootServerAddr: Windows Deployment Services server IP address
            # PEBootRamdiskSourceDrive: Source drive letter, if available.
            # PEFirmwareType: Firmware boot mode: 0x1 for BIOS, 0x2 for UEFI.
            #If you are not booting Windows Deployment Services, the best way to determine where Windows PE booted from is to first check for PEBootRamdiskSourceDrive registry key
            #If it is not present, scan the drives of the correct PEBootType and look for some kind of tag file that identifies the boot drive
            [Alias('Update')]
            [System.Management.Automation.SwitchParameter]$UpdateBootInfo,

            #RemoteRecovery.exe -nomessage
            #Microsoft Diagnostic and Recovery Toolset Remote Recovery
            [Alias('Remote')]
            [System.Management.Automation.SwitchParameter]$RemoteRecovery,

            #wpeutil Reboot
            #Reboots the computer
            [System.Management.Automation.SwitchParameter]$Reboot,
            
            #wpeutil Shutdown
            #Shutdown the computer
            [System.Management.Automation.SwitchParameter]$Shutdown
        )
        #=================================================
        # Blocks
        #=================================================
        Block-WinOS
        #=================================================
        # Increase the Console Screen Buffer size
        #=================================================
        if (!(Test-Path "HKCU:\Console")) {
            Write-Verbose "OSDWinPE: Increase Console Screen Buffer"
            New-Item -Path "HKCU:\Console" -Force | Out-Null
            New-ItemProperty -Path HKCU:\Console ScreenBufferSize -Value 589889656 -PropertyType DWORD -Force | Out-Null
        }
        #=================================================
        # GetModules
        #=================================================
        if ($GetModules.IsPresent) {
            $GetPSDrive = Get-PSDrive -PSProvider 'FileSystem'
            foreach ($PSDrive in $GetPSDrive) {
                $OSDSearchPath = @("$($PSDrive.Root)Modules","$($PSDrive.Root)Content\Modules")
                foreach ($Item in $OSDSearchPath) {
                    if (Test-Path "$Item") {
                        Get-ChildItem "$Item" | `
                        Where-Object {$_.PSIsContainer} | `
                        ForEach-Object {
                            Write-Verbose "Copying Module at $($_.FullName) to X:\Program Files\WindowsPowerShell\Modules"
                            Copy-Item -Path "$($_.FullName)" -Destination "X:\Program Files\WindowsPowerShell\Modules" -Recurse -Force -ErrorAction SilentlyContinue
                            Import-Module -Name "$($_.Name)" -Force -ErrorAction SilentlyContinue
                        }
                    }
                }
            }
        }
        #=================================================
        # GetScripts
        #=================================================
        if ($GetScripts) {
            $GetPSDrive = Get-PSDrive -PSProvider 'FileSystem'

            foreach ($Item in $GetScripts) {
                foreach ($PSDrive in $GetPSDrive) {
                    $ScriptFullName = @("$($PSDrive.Root)$Item","$($PSDrive.Root)Content\Scripts\$Item")

                    foreach ($ScriptName in $ScriptFullName) {
                        if (Test-Path $ScriptName) {
                            $FoundScript = Get-Item $ScriptName | Select-Object -Property FullName
                            Write-Verbose "Executing PowerShell Script $($FoundScript.FullName)"
                            & "$($FoundScript.FullName)" -ErrorAction SilentlyContinue
                        }
                    }
                }
            }
        }
        #=================================================
        # wpeutil
        #=================================================
        if ($InitializeNetwork.IsPresent) {
            Write-Verbose 'OSDWinPE: wpeutil InitializeNetwork'
            Start-Process -WindowStyle Hidden -FilePath wpeutil -ArgumentList 'InitializeNetwork' -Wait
            Start-Sleep -Seconds 10
        }
        if ($InitializeNetworkNoWait.IsPresent) {
            Write-Verbose 'OSDWinPE: wpeutil InitializeNetwork /NoWait'
            Start-Process -WindowStyle Hidden -FilePath wpeutil -ArgumentList ('InitializeNetwork','/NoWait')
        }
        if ($WaitForNetwork.IsPresent) {
            Write-Verbose 'OSDWinPE: wpeutil WaitForNetwork'
            Start-Process -WindowStyle Hidden -FilePath wpeutil -ArgumentList 'WaitForNetwork' -Wait
        }
        if ($WaitForRemovableStorage.IsPresent) {
            Write-Verbose 'OSDWinPE: wpeutil WaitForRemovableStorage'
            Start-Process -WindowStyle Hidden -FilePath wpeutil -ArgumentList 'WaitForRemovableStorage' -Wait
        }
        if ($DisableFirewall.IsPresent) {
            Write-Verbose 'OSDWinPE: wpeutil DisableFirewall'
            Start-Process -WindowStyle Hidden -FilePath wpeutil -ArgumentList 'DisableFirewall' -Wait
        }
        if ($UpdateBootInfo.IsPresent) {
            Write-Verbose 'OSDWinPE: wpeutil UpdateBootInfo'
            Start-Process -WindowStyle Hidden -FilePath wpeutil -ArgumentList 'UpdateBootInfo'
        }
        #=================================================
        # Microsoft DaRT
        #=================================================
        if (($RemoteRecovery.IsPresent) -and (Test-Path "$env:windir\System32\RemoteRecovery.exe")) {
            Write-Verbose 'OSDWinPE: Microsoft DaRT Remote Recovery'
            Start-Process -WindowStyle Minimized -FilePath RemoteRecovery.exe -ArgumentList '-nomessage'
        }
        #=================================================
        # Reboot Shutdown
        #=================================================
        if ($Reboot.IsPresent) {
            Write-Verbose 'OSDWinPE: wpeutil Reboot'
            Start-Process -WindowStyle Hidden -FilePath wpeutil -ArgumentList 'Reboot'
        }
        if ($Shutdown.IsPresent) {
            Write-Verbose 'OSDWinPE: wpeutil Shutdown'
            Start-Process -WindowStyle Hidden -FilePath wpeutil -ArgumentList 'Shutdown'
        }
    }
    function Add-OfflineServicingWindowsDriver {
        [CmdletBinding()]
        param (
            [string]$Path = 'C:\Drivers'
        )
$UnattendXml = @"
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
    <settings pass="offlineServicing">
        <component name="Microsoft-Windows-PnpCustomizationsNonWinPE" processorArchitecture="x86" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <DriverPaths>
                <PathAndCredentials wcm:keyValue="1" wcm:action="add">
                    <Path>$Path</Path>
                </PathAndCredentials>
            </DriverPaths>
        </component>
        <component name="Microsoft-Windows-PnpCustomizationsNonWinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <DriverPaths>
                <PathAndCredentials wcm:keyValue="1" wcm:action="add">
                    <Path>$Path</Path>
                </PathAndCredentials>
            </DriverPaths>
        </component>
    </settings>
</unattend>
"@

        #=================================================
        # Block
        #=================================================
        Block-WinOS
        Block-WindowsVersionNe10
        Block-PowerShellVersionLt5    
        #=================================================
        # Use-WindowsUnattend
        #=================================================
        $Random = Get-Random
        $UnattendXml | Out-File -FilePath "$env:TEMP\$Random.xml" -Encoding utf8 -Width 2000 -Force
        Use-WindowsUnattend -Path 'C:\' -UnattendPath "$env:TEMP\$Random.xml"
        #=================================================
    }
    function Use-WinPEContent {
        [CmdletBinding()]
        param (
            [ValidateSet('*','Drivers','Files','Modules','Registry','Scripts')]
            [string[]]$Content = '*'
        )
        #=================================================
        # Blocks
        #=================================================
        Block-WinOS
        #=================================================
        # PSDrive
        #=================================================
        $GetPSDrive = Get-PSDrive -PSProvider 'FileSystem'
    
        foreach ($Item in $Content) {
            #=================================================
            # Drivers
            #=================================================
            if ($Item -eq '*' -or $Item -eq 'Drivers') {
                foreach ($PSDrive in $GetPSDrive) {
                    $ContentPath = @("$($PSDrive.Root)Content\Drivers","$($PSDrive.Root)WinPE\Drivers")
                    foreach ($ContentItem in $ContentPath) {
                        if (Test-Path "$ContentItem") {
                            Get-ChildItem "$ContentItem" *.inf -Recurse | `
                            ForEach-Object {
                                Write-Verbose "Importing Driver $($_.FullName)"
                                PNPUtil.exe /add-driver "$($_.FullName)" /install
                            }
                        }
                    }
                }
            }
            #=================================================
            # Files
            #=================================================
            if ($Item -eq '*' -or $Item -eq 'Files') {
                foreach ($PSDrive in $GetPSDrive) {
                    $ContentPath = @("$($PSDrive.Root)Content\Files","$($PSDrive.Root)WinPE\Files")
                    foreach ($ContentItem in $ContentPath) {
                        if (Test-Path "$ContentItem") {
                            Write-Verbose "Copying Files at $ContentItem to X:\"
                            robocopy "$ContentItem" X:\ *.* /e /ndl /b
                        }
                    }
                }
            }
            #=================================================
            # Modules
            #=================================================
            if ($Item -eq '*' -or $Item -eq 'Modules') {
                foreach ($PSDrive in $GetPSDrive) {
                    $ContentPath = @("$($PSDrive.Root)Content\Modules","$($PSDrive.Root)WinPE\Modules")
                    foreach ($ContentItem in $ContentPath) {
                        if (Test-Path "$ContentItem") {
                            Get-ChildItem "$ContentItem" | `
                            Where-Object {$_.PSIsContainer} | `
                            ForEach-Object {
                                Write-Verbose "Copying Module at $($_.FullName) to X:\Program Files\WindowsPowerShell\Modules"
                                Copy-Item -Path "$($_.FullName)" -Destination "X:\Program Files\WindowsPowerShell\Modules" -Recurse -Force -ErrorAction SilentlyContinue
                                Import-Module -Name "$($_.Name)" -Force -ErrorAction SilentlyContinue
                            }
                        }
                    }
                }
            }
            #=================================================
            # Registry
            #=================================================
            if ($Item -eq '*' -or $Item -eq 'Registry') {
                foreach ($PSDrive in $GetPSDrive) {
                    $ContentPath = @("$($PSDrive.Root)Content\Registry","$($PSDrive.Root)WinPE\Registry")
                    foreach ($ContentItem in $ContentPath) {
                        if (Test-Path "$ContentItem") {
                            Get-ChildItem "$ContentItem" *.reg -Recurse | `
                            ForEach-Object {
                                Write-Verbose "Importing Registry File $($_.FullName)"
                                reg import "$($_.FullName)"
                            }
                        }
                    }
                }
            }
            #=================================================
            # Scripts
            #=================================================
            if ($Item -eq '*' -or $Item -eq 'Scripts') {
                foreach ($PSDrive in $GetPSDrive) {
                    $ContentPath = @("$($PSDrive.Root)Content\Scripts","$($PSDrive.Root)WinPE\Scripts")
                    foreach ($ContentItem in $ContentPath) {
                        if (Test-Path "$ContentItem") {
                            Get-ChildItem "$ContentItem" *.ps1 -Recurse | `
                            ForEach-Object {
                                Write-Verbose "Executing PowerShell Script $($_.FullName)"
                                & "$($_.FullName)" -ErrorAction SilentlyContinue
                            }
                        }
                    }
                }
            }
        }
    }
}