├── .gitattributes ├── LICENSE ├── OSD.png ├── OSDUpdate.psd1 ├── OSDUpdate.psm1 ├── Private ├── New-OSDUpdateRepository.ps1 └── OSD-UpdateFunctions.ps1 ├── Public ├── Get-DownDefender.ps1 ├── Get-DownMcAfee.ps1 ├── Get-DownOSDUpdate.ps1 ├── Get-DownOffice.ps1 ├── Get-OSDUpdate.ps1 ├── Get-OSDUpdate.txt ├── New-OSDUpdatePackage.ps1 └── Update-ModuleOSDUpdate.ps1 ├── README.md └── Scripts ├── Install-OSDUpdateDefender.ps1 ├── Install-OSDUpdateMcAfee.ps1 ├── Install-OSDUpdatePackage.ps1 ├── Install-OSDUpdatePackageOffice.ps1 ├── Install-OSDUpdatePackageWindows.ps1 ├── Install-OSDUpdatePackages.ps1 └── Update-OSDUpdatePackages.ps1 /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 David Segura 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /OSD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OSDeploy/OSDUpdate/16ce6ec682ec7819c2779c93627ec0287ff42319/OSD.png -------------------------------------------------------------------------------- /OSDUpdate.psd1: -------------------------------------------------------------------------------- 1 | # Module Manifest 2 | # 3 | 4 | @{ 5 | 6 | # Script module or binary module file associated with this manifest. 7 | RootModule = 'OSDUpdate.psm1' 8 | 9 | # Version number of his module. 10 | ModuleVersion = '23.4.25.1' 11 | 12 | # Supported PSEditions 13 | # CompatiblePSEditions = @() 14 | 15 | # ID used to uniquely identify this module 16 | GUID = '593e8730-b646-4a16-abaf-f3eae38c57b0' 17 | 18 | # Author of this module 19 | Author = 'David Segura' 20 | 21 | # Company or vendor of this module 22 | CompanyName = 'osdeploy.com' 23 | 24 | # Copyright statement for this module 25 | Copyright = '(c) 2021 David Segura osdeploy.com. All rights reserved.' 26 | 27 | # Description of the functionality provided by this module 28 | Description = @' 29 | Requires OSDSUS 21.10.14.1 or newer 30 | 31 | OSDUpdate https://osdupdate.osdeploy.com/ 32 | 33 | Latest Microsoft Updates: 34 | https://raw.githubusercontent.com/OSDeploy/OSDUpdate/master/UPDATES.md 35 | 36 | WSUS Update Catalogs: 37 | These are contained within this PowerShell Module, so regular Module updating is needed to 38 | ensure you receive the latest Microsoft Updates. Updates published in WSUS will be different 39 | from Microsoft Update Catalog website due to Preview Releases 40 | '@ 41 | 42 | # Minimum version of the Windows PowerShell engine required by this module 43 | PowerShellVersion = '5.0' 44 | 45 | # Name of the Windows PowerShell host required by this module 46 | # PowerShellHostName = 'Windows PowerShell ISE Host' 47 | 48 | # Minimum version of the Windows PowerShell host required by this module 49 | # PowerShellHostVersion = '' 50 | 51 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 52 | # DotNetFrameworkVersion = '' 53 | 54 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 55 | # CLRVersion = '' 56 | 57 | # Processor architecture (None, X86, Amd64) required by this module 58 | # ProcessorArchitecture = '' 59 | 60 | # Modules that must be imported into the global environment prior to importing this module 61 | RequiredModules = @( 62 | @{ModuleName='OSDSUS'; ModuleVersion = '21.10.14.1'; Guid="065cf035-da73-4d17-8745-f55116b82fb5"} 63 | ) 64 | 65 | # Assemblies that must be loaded prior to importing this module 66 | # RequiredAssemblies = @() 67 | 68 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 69 | # ScriptsToProcess = @() 70 | 71 | # Type files (.ps1xml) to be loaded when importing this module 72 | # TypesToProcess = @() 73 | 74 | # Format files (.ps1xml) to be loaded when importing this module 75 | # FormatsToProcess = @() 76 | 77 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 78 | #NestedModules = @( 79 | # @{ModuleName="OSDSUS"; ModuleVersion = '19.9.10.0'; Guid="065cf035-da73-4d17-8745-f55116b82fb5"} 80 | #) 81 | 82 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. 83 | FunctionsToExport = 'Get-OSDUpdate', 84 | 'Get-DownDefender', 85 | 'Get-DownMcAfee', 86 | 'Get-DownOSDUpdate', 87 | 'Get-DownOffice', 88 | 'New-OSDUpdatePackage', 89 | #'New-OSDUpdateRepository', 90 | 'Update-ModuleOSDUpdate' 91 | 92 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. 93 | CmdletsToExport = @() 94 | 95 | # Variables to export from this module 96 | VariablesToExport = @() 97 | 98 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. 99 | AliasesToExport = @() 100 | 101 | # DSC resources to export from this module 102 | # DscResourcesToExport = @() 103 | 104 | # List of all modules packaged with this module 105 | # ModuleList = @() 106 | 107 | # List of all files packaged with this module 108 | # FileList = @() 109 | 110 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 111 | PrivateData = @{ 112 | 113 | PSData = @{ 114 | 115 | # Tags applied to this module. These help with module discovery in online galleries. 116 | Tags = @('OSDeploy','OSDUpdate','OSDSUS','OSD','Update','Windows10','Office365','Office2019','Office2016','Office2013','Office2010') 117 | 118 | # A URL to the license for this module. 119 | LicenseUri = 'https://github.com/OSDeploy/OSDUpdate/blob/master/LICENSE' 120 | 121 | # A URL to the main website for this project. 122 | ProjectUri = 'https://osdupdate.osdeploy.com/' 123 | 124 | # A URL to an icon representing this module. 125 | IconUri = 'https://raw.githubusercontent.com/OSDeploy/OSDUpdate/master/OSD.png' 126 | 127 | # ReleaseNotes of this module 128 | ReleaseNotes = 'https://osdupdate.osdeploy.com/release' 129 | 130 | #ExternalModuleDependencies = @('OSDSUS') 131 | 132 | } # End of PSData hashtable 133 | 134 | } # End of PrivateData hashtable 135 | 136 | # HelpInfo URI of this module 137 | # HelpInfoURI = '' 138 | 139 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 140 | # DefaultCommandPrefix = '' 141 | 142 | } 143 | -------------------------------------------------------------------------------- /OSDUpdate.psm1: -------------------------------------------------------------------------------- 1 | <# if (!$(Get-Module -ListAvailable OSDSUS)) { 2 | try { 3 | Install-Module OSDSUS -ErrorAction Stop 4 | } 5 | catch { 6 | Write-Error $_ 7 | Write-Error "Problem installing Module A dependency Module OSDSUS! Module A will NOT be loaded. Halting!" 8 | $global:FunctionResult = "1" 9 | return 10 | } 11 | } 12 | try { 13 | Import-Module OSDSUS -ErrorAction Stop 14 | } 15 | catch { 16 | Write-Error $_ 17 | Write-Error "Problem importing Module A dependency Module OSDSUS! Module A will NOT be loaded. Halting!" 18 | $global:FunctionResult = "1" 19 | return 20 | } #> 21 | 22 | #=================================================================================================== 23 | # Import Functions 24 | # https://github.com/RamblingCookieMonster/PSStackExchange/blob/master/PSStackExchange/PSStackExchange.psm1 25 | #=================================================================================================== 26 | $OSDPublicFunctions = @( Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -ErrorAction SilentlyContinue ) 27 | $OSDPrivateFunctions = @( Get-ChildItem -Path $PSScriptRoot\Private\*.ps1 -ErrorAction SilentlyContinue ) 28 | 29 | foreach ($Import in @($OSDPublicFunctions + $OSDPrivateFunctions)) { 30 | Try {. $Import.FullName} 31 | Catch {Write-Error -Message "Failed to import function $($Import.FullName): $_"} 32 | } 33 | 34 | Export-ModuleMember -Function $OSDPublicFunctions.BaseName 35 | #=================================================================================================== -------------------------------------------------------------------------------- /Private/New-OSDUpdateRepository.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Creates an OSDUpdate Repository 4 | 5 | .DESCRIPTION 6 | Creates an OSDUpdate Repository to store downloaded updates 7 | 8 | .LINK 9 | https://www.osdeploy.com/osdupdate/docs/functions/new-osdupdaterepository 10 | 11 | .PARAMETER Catalog 12 | The Microsoft Office or Windows Update Catalog to store 13 | 14 | .PARAMETER RepositoryRootPath 15 | Full Path of the OSDUpdate Repository 16 | 17 | .EXAMPLE 18 | New-OSDUpdateRepository -Catalog 'Windows 10 x64' -RepositoryRootPath "C:\OSDUpdate" 19 | Creates an OSDUpdate Repository in C:\OSDUpdate 20 | Creates a directory C:\OSDUpdate\Windows 10 x64 with an initial Update Catalog 21 | #> 22 | function New-OSDUpdateRepository { 23 | [CmdletBinding()] 24 | PARAM ( 25 | [Parameter(Mandatory = $True)] 26 | [ValidateSet( 27 | 'Office 2010 32-Bit', 28 | 'Office 2010 64-Bit', 29 | 'Office 2013 32-Bit', 30 | 'Office 2013 64-Bit', 31 | 'Office 2016 32-Bit', 32 | 'Office 2016 64-Bit', 33 | 'Windows 7', 34 | #'Windows 8.1', 35 | #'Windows 8.1 Dynamic Update', 36 | 'Windows 10', 37 | 'Windows 10 Dynamic Update', 38 | 'Windows 10 Feature On Demand', 39 | 'Windows 10 Language Packs', 40 | 'Windows 10 Language Interface Packs', 41 | #'Windows Server 2012 R2', 42 | 'Windows Server 2016', 43 | 'Windows Server 2019')] 44 | [string]$Catalog, 45 | 46 | [Parameter(Mandatory = $True)] 47 | [string]$RepositoryRootPath 48 | 49 | ) 50 | if (!(Test-Path "$RepositoryRootPath")) {New-Item -Path "$RepositoryRootPath" -ItemType Directory -Force | Out-Null} 51 | if (!(Test-Path "$RepositoryRootPath\$Catalog")) {New-Item -Path "$RepositoryRootPath\$Catalog" -ItemType Directory -Force | Out-Null} 52 | Copy-Item -Path "$($MyInvocation.MyCommand.Module.ModuleBase)\Catalogs\$Catalog.xml" -Destination "$RepositoryRootPath\$Catalog" -Force | Out-Null 53 | } -------------------------------------------------------------------------------- /Private/OSD-UpdateFunctions.ps1: -------------------------------------------------------------------------------- 1 | function Convert-GuidToCompressedGuid { 2 | <# 3 | .SYNOPSIS 4 | This converts a GUID to a compressed GUID also known as a product code. 5 | .DESCRIPTION 6 | This function will typically be used to figure out the product code 7 | that matches up with the product code stored in the 'SOFTWARE\Classes\Installer\Products' 8 | registry path to a MSI installer GUID. 9 | .EXAMPLE 10 | Convert-GuidToCompressedGuid -Guid '{7C6F0282-3DCD-4A80-95AC-BB298E821C44}' 11 | 12 | This example would output the compressed GUID '2820F6C7DCD308A459CABB92E828C144' 13 | .PARAMETER Guid 14 | The GUID you'd like to convert. 15 | .LINK 16 | https://www.adamtheautomator.com/compressed-guid-with-powershell/ 17 | #> 18 | [CmdletBinding()] 19 | [OutputType()] 20 | param ( 21 | [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Mandatory)] 22 | [string]$Guid 23 | ) 24 | begin { 25 | $Guid = $Guid.Replace('-', '').Replace('{', '').Replace('}', '') 26 | } 27 | process { 28 | try { 29 | $Groups = @( 30 | $Guid.Substring(0, 8).ToCharArray(), 31 | $Guid.Substring(8, 4).ToCharArray(), 32 | $Guid.Substring(12, 4).ToCharArray(), 33 | $Guid.Substring(16, 16).ToCharArray() 34 | ) 35 | $Groups[0..2] | foreach { 36 | [array]::Reverse($_) 37 | } 38 | $CompressedGuid = ($Groups[0..2] | foreach { $_ -join '' }) -join '' 39 | 40 | $chararr = $Groups[3] 41 | for ($i = 0; $i -lt $chararr.count; $i++) { 42 | if (($i % 2) -eq 0) { 43 | $CompressedGuid += ($chararr[$i+1] + $chararr[$i]) -join '' 44 | } 45 | } 46 | $CompressedGuid 47 | } catch { 48 | Write-Error $_.Exception.Message 49 | } 50 | } 51 | } 52 | 53 | function Convert-CompressedGuidToGuid { 54 | <# 55 | .SYNOPSIS 56 | This converts a compressed GUID also known as a product code into a GUID. 57 | .DESCRIPTION 58 | This function will typically be used to figure out the MSI installer GUID 59 | that matches up with the product code stored in the 'SOFTWARE\Classes\Installer\Products' 60 | registry path. 61 | .EXAMPLE 62 | Convert-CompressedGuidToGuid -CompressedGuid '2820F6C7DCD308A459CABB92E828C144' 63 | 64 | This example would output the GUID '{7C6F0282-3DCD-4A80-95AC-BB298E821C44}' 65 | .PARAMETER CompressedGuid 66 | The compressed GUID you'd like to convert. 67 | .LINK 68 | https://www.adamtheautomator.com/convert-compressed-guid-to-guid/ 69 | #> 70 | [CmdletBinding()] 71 | [OutputType([System.String])] 72 | param ( 73 | [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Mandatory)] 74 | [ValidatePattern('^[0-9a-fA-F]{32}$')] 75 | [string]$CompressedGuid 76 | ) 77 | process { 78 | $Indexes = [ordered]@{ 79 | 0 = 8; 80 | 8 = 4; 81 | 12 = 4; 82 | 16 = 2; 83 | 18 = 2; 84 | 20 = 2; 85 | 22 = 2; 86 | 24 = 2; 87 | 26 = 2; 88 | 28 = 2; 89 | 30 = 2 90 | } 91 | #$Guid = '{' 92 | $Guid = '' 93 | foreach ($index in $Indexes.GetEnumerator()) { 94 | $part = $CompressedGuid.Substring($index.Key, $index.Value).ToCharArray() 95 | [array]::Reverse($part) 96 | $Guid += $part -join '' 97 | } 98 | $Guid = $Guid.Insert(9,'-').Insert(14, '-').Insert(19, '-').Insert(24, '-') 99 | #$Guid + '}' 100 | $Guid + '' 101 | } 102 | } 103 | 104 | function Get-MSPFileInfo { 105 | param 106 | ( 107 | [Parameter(Mandatory = $true)][IO.FileInfo]$Path, 108 | [Parameter(Mandatory = $true)][ValidateSet('Classification', 'Description', 'DisplayName', 'KBArticle Number', 'ManufacturerName', 'ReleaseVersion', 'TargetProductName', 'Release', 'MoreInfoURL', 'OptimizedInstallMode', 'CreationTimeUTC', 'AllowRemoval', 'OptimizeCA', 'BuildNumber', 'StdPackageName', 'PatchType', 'IsMinorUpgrade')][string]$Property 109 | ) 110 | 111 | try { 112 | #Creating windows installer object 113 | $WindowsInstaller = New-Object -ComObject WindowsInstaller.Installer 114 | 115 | #Loads the MSI database and specifies the mode to open it in by the last number on the line 116 | $MSIDatabase = $WindowsInstaller.GetType().InvokeMember("OpenDatabase", "InvokeMethod", $Null, $WindowsInstaller, @($Path.FullName, 32)) 117 | 118 | #Specifies to query the MSIPatchMetadata table and get the value associated with the designated property 119 | $Query = "SELECT Value FROM MsiPatchMetadata WHERE Property = '$($Property)'" 120 | 121 | #Open up the property view 122 | $View = $MSIDatabase.GetType().InvokeMember("OpenView", "InvokeMethod", $null, $MSIDatabase, ($Query)) 123 | $View.GetType().InvokeMember("Execute", "InvokeMethod", $null, $View, $null) 124 | 125 | #Retrieve the associate Property 126 | $Record = $View.GetType().InvokeMember("Fetch", "InvokeMethod", $null, $View, $null) 127 | 128 | #Retrieve the associated value of the retrieved property 129 | $Value = $Record.GetType().InvokeMember("StringData", "GetProperty", $null, $Record, 1) 130 | return $Value 131 | 132 | } catch { 133 | Write-Output $_.Exception.Message 134 | } 135 | } -------------------------------------------------------------------------------- /Public/Get-DownDefender.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Downloads the latest Microsoft Defender Definition Updates 4 | 5 | .DESCRIPTION 6 | Downloads the latest Microsoft Defender Definition Updates 7 | 8 | .LINK 9 | https://osdupdate.osdeploy.com/module/functions/get-downdefender 10 | 11 | .PARAMETER OS 12 | Self Explanatory 13 | 14 | .PARAMETER OSArch 15 | Windows OS Architecture 16 | 17 | .PARAMETER DownloadPath 18 | This is the path to download the updates. If this is not specified, the Desktop is used 19 | #> 20 | function Get-DownDefender { 21 | [CmdletBinding()] 22 | PARAM ( 23 | [string]$DownloadPath, 24 | 25 | [Parameter(Mandatory)] 26 | [ValidateSet('Windows 8-10','Windows V-7')] 27 | [string]$OS, 28 | 29 | [Parameter(Mandatory)] 30 | [ValidateSet('32-Bit','64-Bit')] 31 | [string]$OSArch, 32 | 33 | [switch]$Curl 34 | ) 35 | #=================================================================================================== 36 | # Paths 37 | #=================================================================================================== 38 | if (!($DownloadPath)) {$DownloadPath = [Environment]::GetFolderPath("Desktop")} 39 | if (!(Test-Path "$DownloadPath")) {New-Item -Path "$DownloadPath" -ItemType Directory -Force | Out-Null} 40 | 41 | Write-Host "DownloadPath: $DownloadPath" -ForegroundColor Cyan 42 | Write-Host "OS: $OS" -ForegroundColor Cyan 43 | Write-Host "Arch: $OSArch" -ForegroundColor Cyan 44 | 45 | if ($OS -eq 'Windows V-7' -and $OSArch -eq '32-Bit') { 46 | $DownloadUrl = 'https://go.microsoft.com/fwlink/?LinkID=121721&clcid=0x409&arch=x86&eng=0.0.0.0&avdelta=0.0.0.0&asdelta=0.0.0.0&prod=925A3ACA-C353-458A-AC8D-A7E5EB378092' 47 | } 48 | 49 | if ($OS -eq 'Windows V-7' -and $OSArch -eq '64-Bit') { 50 | $DownloadUrl = 'https://go.microsoft.com/fwlink/?LinkID=121721&clcid=0x409&arch=x86&eng=0.0.0.0&avdelta=0.0.0.0&asdelta=0.0.0.0&prod=925A3ACA-C353-458A-AC8D-A7E5EB378092' 51 | } 52 | 53 | if ($OS -eq 'Windows 8-10' -and $OSArch -eq '32-Bit') { 54 | $DownloadUrl = 'https://go.microsoft.com/fwlink/?LinkID=121721&arch=x86' 55 | } 56 | 57 | if ($OS -eq 'Windows 8-10' -and $OSArch -eq '64-Bit') { 58 | $DownloadUrl = 'https://go.microsoft.com/fwlink/?LinkID=121721&arch=x64' 59 | } 60 | #=================================================================================================== 61 | # Download 62 | #=================================================================================================== 63 | Write-Host "DownloadUrl: $DownloadUrl" -ForegroundColor Cyan 64 | Write-Host "DownloadPath: $DownloadPath" -ForegroundColor Cyan 65 | if ($Curl) { 66 | Save-WebFile -SourceUrl "$DownloadUrl" -DestinationDirectory $DownloadPath -DestinationName "mpam-fe $OS $OSArch.exe" -Overwrite 67 | } 68 | else { 69 | Invoke-WebRequest -Uri $DownloadUrl -OutFile "$DownloadPath\mpam-fe $OS $OSArch.exe" 70 | } 71 | } -------------------------------------------------------------------------------- /Public/Get-DownMcAfee.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Downloads McAfee SuperDATs and Tools 4 | 5 | .DESCRIPTION 6 | Downloads McAfee SuperDATs and Tools 7 | 8 | .LINK 9 | https://osdupdate.osdeploy.com/module/functions/get-downmcafee 10 | 11 | .PARAMETER Product 12 | The type of update to download 13 | 14 | .PARAMETER DownloadPath 15 | This is the path to download the updates. If this is not specified, the Desktop is used 16 | 17 | .PARAMETER EPO 18 | Downloads the ZIP version for use in McAfee EPO 19 | 20 | .PARAMETER RenameDAT 21 | Renames the DAT without the Version information. Useful for static installation scripts 22 | #> 23 | function Get-DownMcAfee { 24 | [CmdletBinding()] 25 | PARAM ( 26 | [Parameter(Mandatory)] 27 | [ValidateSet('SuperDAT v2','SuperDAT v3','GetSusp32','GetSusp64','Stinger32','Stinger64')] 28 | [string]$Download, 29 | [string]$DownloadPath, 30 | [switch]$EPO, 31 | #[switch]$AddInstallScript, 32 | [switch]$RenameDAT 33 | ) 34 | #=================================================================================================== 35 | # Paths 36 | #=================================================================================================== 37 | if (!($DownloadPath)) {$DownloadPath = [Environment]::GetFolderPath("Desktop")} 38 | if (!(Test-Path "$DownloadPath")) {New-Item -Path "$DownloadPath" -ItemType Directory -Force | Out-Null} 39 | 40 | if ($Download -eq 'GetSusp32') { 41 | if ($EPO.IsPresent) { 42 | $DownloadUrl = 'http://downloadcenter.mcafee.com/products/mcafee-avert/getsusp/getsusp-epo.zip' 43 | } else { 44 | $DownloadUrl = 'http://downloadcenter.mcafee.com/products/mcafee-avert/getsusp/getsusp.exe' 45 | } 46 | } 47 | 48 | if ($Download -eq 'GetSusp64') { 49 | if ($EPO.IsPresent) { 50 | $DownloadUrl = 'http://downloadcenter.mcafee.com/products/mcafee-avert/getsusp/getsusp64-epo.zip' 51 | } else { 52 | $DownloadUrl = 'http://downloadcenter.mcafee.com/products/mcafee-avert/getsusp/getsusp64.exe' 53 | } 54 | } 55 | 56 | if ($Download -eq 'Stinger32') { 57 | if ($EPO.IsPresent) { 58 | $DownloadUrl = 'http://downloadcenter.mcafee.com/products/mcafee-avert/Stinger/stinger32-epo.zip' 59 | } else { 60 | $DownloadUrl = 'http://downloadcenter.mcafee.com/products/mcafee-avert/Stinger/stinger32.exe' 61 | } 62 | } 63 | 64 | if ($Download -eq 'Stinger64') { 65 | if ($EPO.IsPresent) { 66 | $DownloadUrl = 'http://downloadcenter.mcafee.com/products/mcafee-avert/Stinger/stinger64-epo.zip' 67 | } else { 68 | $DownloadUrl = 'http://downloadcenter.mcafee.com/products/mcafee-avert/Stinger/stinger64.exe' 69 | } 70 | } 71 | 72 | if ($Download -eq 'SuperDAT v2') { 73 | if ($EPO.IsPresent) { 74 | Write-Host "Verifying SuperDAT v2 EPO Download URL ..." -ForegroundColor Cyan 75 | $DownloadString = 'download.nai.com/products/DatFiles/4.x/NAI/avvepo' 76 | $link = (Invoke-WebRequest -Uri 'https://www.mcafee.com/enterprise/en-us/downloads/security-updates.html').Links | Where-Object {$_.href -like "*$DownloadString*"} 77 | $DownloadUrl = $link.href 78 | } else { 79 | Write-Host "Verifying SuperDAT v2 Download URL ..." -ForegroundColor Cyan 80 | $DownloadString = 'download.nai.com/products/licensed/superdat/english/intel' 81 | $link = (Invoke-WebRequest -Uri 'https://www.mcafee.com/enterprise/en-us/downloads/security-updates.html').Links | Where-Object {$_.href -like "*$DownloadString*"} 82 | $DownloadUrl = $link.href 83 | } 84 | } 85 | 86 | if ($Download -eq 'SuperDAT v3') { 87 | if ($EPO.IsPresent) { 88 | Write-Host "Verifying SuperDAT v3 EPO Download URL ..." -ForegroundColor Cyan 89 | $DownloadString = 'download.nai.com/products/datfiles/V3DAT/epoV3' 90 | $link = (Invoke-WebRequest -Uri 'https://www.mcafee.com/enterprise/en-us/downloads/security-updates.html').Links | Where-Object {$_.href -like "*$DownloadString*"} 91 | $DownloadUrl = $link.href 92 | } else { 93 | Write-Host "Verifying SuperDAT v3 EPO Download URL ..." -ForegroundColor Cyan 94 | $DownloadString = 'download.nai.com/products/datfiles/V3DAT/V3' 95 | $link = (Invoke-WebRequest -Uri 'https://www.mcafee.com/enterprise/en-us/downloads/security-updates.html').Links | Where-Object {$_.href -like "*$DownloadString*"} 96 | $DownloadUrl = $link.href 97 | } 98 | } 99 | #=================================================================================================== 100 | # Download 101 | #=================================================================================================== 102 | if ($null -eq $DownloadUrl) { 103 | Write-Warning "Could not locate a valid link ... Exiting" 104 | Break 105 | } else { 106 | Write-Host "DownloadUrl: $DownloadUrl" -ForegroundColor Cyan 107 | Write-Host "DownloadPath: $DownloadPath" -ForegroundColor Cyan 108 | Write-Host "Product: $Download" -ForegroundColor Cyan 109 | 110 | if ($Download -eq 'SuperDAT v2' -and $RenameDAT.IsPresent -and (!($EPO.IsPresent)) ) { 111 | Write-Host "RenameDAT: $DownloadPath\xdat.exe" -ForegroundColor Cyan 112 | Start-BitsTransfer -Source $DownloadUrl -Destination "$DownloadPath\xdat.exe" 113 | } elseif ($Download -eq 'SuperDAT v3' -and $RenameDAT.IsPresent -and (!($EPO.IsPresent)) ) { 114 | Write-Host "RenameDAT: $DownloadPath\DATv3.exe" -ForegroundColor Cyan 115 | Start-BitsTransfer -Source $DownloadUrl -Destination "$DownloadPath\V3_xdat.exe" 116 | } else { 117 | Start-BitsTransfer -Source $DownloadUrl -Destination "$DownloadPath" 118 | } 119 | } 120 | #=================================================================================================== 121 | # AddInstallScript 122 | #=================================================================================================== 123 | #if ($AddInstallScript.IsPresent) { 124 | # Write-Verbose "Adding $DownloadPath\OSDUpdate-McAfee.ps1" -Verbose 125 | # Copy-Item "$($MyInvocation.MyCommand.Module.ModuleBase)\Scripts\OSDUpdate-McAfee.ps1" "$DownloadPath" -Force | Out-Null 126 | #} 127 | #=================================================================================================== 128 | } -------------------------------------------------------------------------------- /Public/Get-DownOSDUpdate.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Downloads Current Microsoft Updates 4 | 5 | .DESCRIPTION 6 | Downloads Current Microsoft Updates 7 | Requires BITS for downloading the updates 8 | Requires Internet access for downloading the updates 9 | 10 | .LINK 11 | https://osdupdate.osdeploy.com/module/functions/get-downosdupdate 12 | 13 | .PARAMETER DownloadPath 14 | Directory of the Downloads 15 | 16 | .PARAMETER InputObject 17 | Paired with Get-OSDUpdate 18 | Get-OSDUpdate | Get-DownOSDUpdate 19 | 20 | .PARAMETER Catalog 21 | Get-OSDUpdate.Catalog Property 22 | 23 | .PARAMETER UpdateArch 24 | Architecture of the Update 25 | Get-OSDUpdate.UpdateArch Property 26 | 27 | .PARAMETER UpdateBuild 28 | Windows Build for the Update 29 | Get-OSDUpdate.UpdateBuild Property 30 | 31 | .PARAMETER OfficeProfile 32 | Microsoft Office Update Type 33 | 34 | .PARAMETER GridView 35 | Displays the results in GridView with -PassThru 36 | #> 37 | 38 | function Get-DownOSDUpdate { 39 | [CmdletBinding()] 40 | PARAM ( 41 | [Parameter(Mandatory = $true)] 42 | [string]$DownloadPath, 43 | 44 | [Parameter(ValueFromPipeline = $true)] 45 | [Object[]]$InputObject, 46 | 47 | [ValidateSet( 48 | 'Office 2010 32-Bit', 49 | 'Office 2010 64-Bit', 50 | 'Office 2013 32-Bit', 51 | 'Office 2013 64-Bit', 52 | 'Office 2016 32-Bit', 53 | 'Office 2016 64-Bit', 54 | 'Windows 10', 55 | 'Windows 11', 56 | 'Windows Server', 57 | 'Windows Server 2016', 58 | 'Windows Server 2019')] 59 | [Alias('CatalogOffice','CatalogWindows')] 60 | [string]$Catalog, 61 | 62 | [ValidateSet ('x64','x86')] 63 | [string]$UpdateArch, 64 | 65 | [ValidateSet ('22H2','21H2','21H1','20H2',2009,2004,1909,1903,1809,1803,1709,1703,1607,1511,1507)] 66 | [string]$UpdateBuild, 67 | 68 | [ValidateSet ('AdobeSU','LCU','SSU','DotNet','DotNetCU','Optional')] 69 | [string]$UpdateGroup, 70 | 71 | [switch]$GridView 72 | ) 73 | 74 | BEGIN { 75 | #=================================================================================================== 76 | # DownloadPath 77 | #=================================================================================================== 78 | if (!(Test-Path "$DownloadPath")) {New-Item -Path "$DownloadPath" -ItemType Directory -Force | Out-Null} 79 | #=================================================================================================== 80 | } 81 | 82 | PROCESS { 83 | #=================================================================================================== 84 | # Get-OSDUpdate 85 | #=================================================================================================== 86 | $OSDUpdate = @() 87 | if ($InputObject) { 88 | $OSDUpdate = $InputObject 89 | } else { 90 | $OSDUpdate = Get-OSDUpdate 91 | } 92 | #=================================================================================================== 93 | # Filter Catalog 94 | #=================================================================================================== 95 | switch ($Catalog) { 96 | 'Office 2010 32-Bit' {$OSDUpdate = $OSDUpdate | Where-Object {$_.Catalog -eq $Catalog}} 97 | 'Office 2010 64-Bit' {$OSDUpdate = $OSDUpdate | Where-Object {$_.Catalog -eq $Catalog}} 98 | 'Office 2013 32-Bit' {$OSDUpdate = $OSDUpdate | Where-Object {$_.Catalog -eq $Catalog}} 99 | 'Office 2013 64-Bit' {$OSDUpdate = $OSDUpdate | Where-Object {$_.Catalog -eq $Catalog}} 100 | 'Office 2016 32-Bit' {$OSDUpdate = $OSDUpdate | Where-Object {$_.Catalog -eq $Catalog}} 101 | 'Office 2016 64-Bit' {$OSDUpdate = $OSDUpdate | Where-Object {$_.Catalog -eq $Catalog}} 102 | 'Windows 10' {$OSDUpdate = $OSDUpdate | Where-Object {$_.Catalog -match $Catalog}} 103 | 'Windows 11' {$OSDUpdate = $OSDUpdate | Where-Object {$_.Catalog -match $Catalog}} 104 | 'Windows Server' {$OSDUpdate = $OSDUpdate | Where-Object {$_.Catalog -match $Catalog}} 105 | 'Windows Server 2016' {$OSDUpdate = $OSDUpdate | Where-Object {$_.Catalog -eq $Catalog}} 106 | 'Windows Server 2019' {$OSDUpdate = $OSDUpdate | Where-Object {$_.Catalog -eq $Catalog}} 107 | } 108 | #=================================================================================================== 109 | # UpdateArch 110 | #=================================================================================================== 111 | if ($UpdateArch -eq 'x64') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateArch -eq 'x64'}} 112 | if ($UpdateArch -eq 'x86') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateArch -eq 'x86'}} 113 | #=================================================================================================== 114 | # UpdateBuild 115 | #=================================================================================================== 116 | if ($UpdateBuild -eq '1507') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '1507'}} 117 | if ($UpdateBuild -eq '1511') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '1511'}} 118 | if ($UpdateBuild -eq '1607') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '1607'}} 119 | if ($UpdateBuild -eq '1703') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '1703'}} 120 | if ($UpdateBuild -eq '1709') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '1709'}} 121 | if ($UpdateBuild -eq '1803') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '1803'}} 122 | if ($UpdateBuild -eq '1809') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '1809'}} 123 | if ($UpdateBuild -eq '1903') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '1903'}} 124 | if ($UpdateBuild -eq '1909') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '1909'}} 125 | if ($UpdateBuild -eq '2004') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '2004'}} 126 | if ($UpdateBuild -eq '20H2') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '20H2'}} 127 | if ($UpdateBuild -eq '21H1') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '21H1'}} 128 | if ($UpdateBuild -eq '21H2') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '21H2'}} 129 | if ($UpdateBuild -eq '22H2') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '22H2'}} 130 | #=================================================================================================== 131 | # UpdateGroup 132 | #=================================================================================================== 133 | if ($UpdateGroup) {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateGroup -eq $UpdateGroup}} 134 | #=================================================================================================== 135 | # GridView 136 | #=================================================================================================== 137 | $OSDUpdate = $OSDUpdate | Sort-Object DateCreated -Descending 138 | if ($GridView.IsPresent) {$OSDUpdate = $OSDUpdate | Out-GridView -PassThru -Title "Select OSDUpdate Downloads"} 139 | #=================================================================================================== 140 | # Download 141 | #=================================================================================================== 142 | foreach ($Update in $OSDUpdate) { 143 | $UpdateFile = $($Update.FileName) 144 | $MspFile = $UpdateFile -replace '.cab', '.msp' 145 | $DownloadDirectory = "$DownloadPath\$($Update.Title)" 146 | if (!(Test-Path "$DownloadDirectory")) {New-Item -Path "$DownloadDirectory" -ItemType Directory -Force | Out-Null} 147 | 148 | if ($Update.Catalog -like "*Office*") { 149 | Write-Host "$DownloadDirectory\$MspFile" -ForegroundColor Cyan 150 | 151 | if (!(Test-Path "$DownloadDirectory\$MspFile")) { 152 | Write-Host "Download: $($Update.OriginUri)" -ForegroundColor Gray 153 | Start-BitsTransfer -Source $($Update.OriginUri) -Destination "$DownloadDirectory\$UpdateFile" 154 | } 155 | 156 | if ((Test-Path "$DownloadDirectory\$UpdateFile") -and (!(Test-Path "$DownloadDirectory\$MspFile"))) { 157 | Write-Host "Expand: $DownloadDirectory\$MspFile" -ForegroundColor Gray 158 | expand "$DownloadDirectory\$UpdateFile" -F:* "$DownloadDirectory" | Out-Null 159 | } 160 | 161 | if ((Test-Path "$DownloadDirectory\$UpdateFile") -and (Test-Path "$DownloadDirectory\$MspFile")) { 162 | Write-Host "Remove: $DownloadDirectory\$UpdateFile" -ForegroundColor Gray 163 | Remove-Item "$DownloadDirectory\$UpdateFile" -Force | Out-Null 164 | } 165 | } 166 | 167 | if ($Update.Catalog -like "*Windows*") { 168 | Write-Host "$($Update.Title)" -ForegroundColor Cyan 169 | Write-Host "$DownloadDirectory\$UpdateFile" -ForegroundColor Gray 170 | 171 | if (!(Test-Path "$DownloadDirectory\$UpdateFile")) { 172 | Write-Host "$($Update.OriginUri)" -ForegroundColor Gray 173 | Start-BitsTransfer -Source $($Update.OriginUri) -Destination "$DownloadDirectory\$UpdateFile" 174 | } 175 | } 176 | } 177 | } 178 | 179 | END {} 180 | } -------------------------------------------------------------------------------- /Public/Get-DownOffice.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Downloads Microsoft Office 365 and Office 2019 4 | 5 | .DESCRIPTION 6 | Downloads Microsoft Office 365 and Office 2019 7 | Requires Internet access for downloading the updates 8 | 9 | .LINK 10 | https://osdupdate.osdeploy.com/module/functions/get-downoffice 11 | 12 | .PARAMETER RepositoryRootPath 13 | Full Path of the OSDUpdate Repository 14 | 15 | .PARAMETER OfficeProduct 16 | 'Office 365 ProPlus','Office 365 Business','Office 2019 ProPlus','Office 2019 Standard' 17 | Defaults to Office 365 ProPlus 18 | 19 | .PARAMETER UpdateChannel 20 | Insiders, Monthly, SAC, SACT 21 | Defaults to SAC 22 | 23 | .PARAMETER OfficeArch 24 | 32 or 64 25 | Defaults to 64 26 | 27 | .PARAMETER LanguageId 28 | Defaults to en-us 29 | 30 | .PARAMETER ProofingTools 31 | Defaults to en-us 32 | 33 | .PARAMETER XmlOnly 34 | Creates an XML for use with ODT to manually download later 35 | #> 36 | 37 | function Get-DownOffice { 38 | [CmdletBinding()] 39 | PARAM ( 40 | [Parameter(Mandatory = $True)] 41 | [string]$RepositoryRootPath, 42 | #=================================================================================================== 43 | # Office Download 44 | #=================================================================================================== 45 | [ValidateSet( 46 | 'Office 365 ProPlus', 47 | 'Office 365 Business', 48 | 'Office 2019 ProPlus', 49 | 'Office 2019 Standard')] 50 | [string]$OfficeProduct = 'Office 365 ProPlus', 51 | 52 | [ValidateSet( 53 | 'Insiders', 54 | 'Monthly', 55 | 'SAC', 56 | 'SACT' 57 | )] 58 | [string]$UpdateChannel = 'SAC', 59 | 60 | [ValidateSet('64','32')] 61 | [string]$OfficeArch = '64', 62 | #=================================================================================================== 63 | # LanguageId 64 | # https://docs.microsoft.com/en-us/DeployOffice/overview-of-deploying-languages-in-office-365-proplus 65 | #=================================================================================================== 66 | [ValidateSet( 67 | 'af-za', 68 | 'ar-sa', 69 | 'as-in', 70 | 'az-Latn-az', 71 | 'bg-bg', 72 | 'bn-bd', 73 | 'bn-in', 74 | 'bs-latn-ba', 75 | 'ca-es', 76 | 'ca-es-valencia', 77 | 'cs-cz', 78 | 'Culture (ll-cc)', 79 | 'cy-gb', 80 | 'da-dk', 81 | 'de-de', 82 | 'el-gr', 83 | 'en-us', 84 | 'es-es', 85 | 'et-ee', 86 | 'eu-es', 87 | 'fa-ir', 88 | 'fi-fi', 89 | 'fr-fr', 90 | 'ga-ie', 91 | 'gd-gb', 92 | 'gl-es', 93 | 'gu-in', 94 | 'ha-Latn-ng', 95 | 'he-il', 96 | 'hi-in', 97 | 'hr-hr', 98 | 'hu-hu', 99 | 'hy-am', 100 | 'id-id', 101 | 'ig-ng', 102 | 'is-is', 103 | 'it-it', 104 | 'ja-jp', 105 | 'ka-ge', 106 | 'kk-kz', 107 | 'kn-in', 108 | 'kok-in', 109 | 'ko-kr', 110 | 'ky-kg', 111 | 'lb-lu', 112 | 'lt-lt', 113 | 'lv-lv', 114 | 'mi-nz', 115 | 'mk-mk', 116 | 'ml-in', 117 | 'mr-in', 118 | 'ms-my', 119 | 'mt-mt', 120 | 'nb-no', 121 | 'ne-np', 122 | 'nl-nl', 123 | 'nn-no', 124 | 'nso-za', 125 | 'or-in', 126 | 'pa-in', 127 | 'pl-pl', 128 | 'ps-af', 129 | 'pt-br', 130 | 'pt-pt', 131 | 'rm-ch', 132 | 'ro-ro', 133 | 'ru-ru', 134 | 'rw-rw', 135 | 'si-lk', 136 | 'sk-sk', 137 | 'sl-si', 138 | 'sq-al', 139 | 'sr-cyrl-ba', 140 | 'sr-cyrl-rs', 141 | 'sr-latn-rs', 142 | 'sv-se', 143 | 'sw-ke', 144 | 'ta-in', 145 | 'te-in', 146 | 'th-th', 147 | 'tn-za', 148 | 'tr-tr', 149 | 'tt-ru', 150 | 'uk-ua', 151 | 'ur-pk', 152 | 'uz-Latn-uz', 153 | 'vi-vn', 154 | 'wo-sn', 155 | 'xh-za', 156 | 'yo-ng', 157 | 'zh-cn', 158 | 'zh-tw', 159 | 'zu-za')] 160 | [string]$LanguageId = 'en-US', 161 | [ValidateSet( 162 | 'af-za', 163 | 'ar-sa', 164 | 'as-in', 165 | 'az-Latn-az', 166 | 'bg-bg', 167 | 'bn-bd', 168 | 'bn-in', 169 | 'bs-latn-ba', 170 | 'ca-es', 171 | 'ca-es-valencia', 172 | 'cs-cz', 173 | 'Culture (ll-cc)', 174 | 'cy-gb', 175 | 'da-dk', 176 | 'de-de', 177 | 'el-gr', 178 | 'en-us', 179 | 'es-es', 180 | 'et-ee', 181 | 'eu-es', 182 | 'fa-ir', 183 | 'fi-fi', 184 | 'fr-fr', 185 | 'ga-ie', 186 | 'gd-gb', 187 | 'gl-es', 188 | 'gu-in', 189 | 'ha-Latn-ng', 190 | 'he-il', 191 | 'hi-in', 192 | 'hr-hr', 193 | 'hu-hu', 194 | 'hy-am', 195 | 'id-id', 196 | 'ig-ng', 197 | 'is-is', 198 | 'it-it', 199 | 'ja-jp', 200 | 'ka-ge', 201 | 'kk-kz', 202 | 'kn-in', 203 | 'kok-in', 204 | 'ko-kr', 205 | 'ky-kg', 206 | 'lb-lu', 207 | 'lt-lt', 208 | 'lv-lv', 209 | 'mi-nz', 210 | 'mk-mk', 211 | 'ml-in', 212 | 'mr-in', 213 | 'ms-my', 214 | 'mt-mt', 215 | 'nb-no', 216 | 'ne-np', 217 | 'nl-nl', 218 | 'nn-no', 219 | 'nso-za', 220 | 'or-in', 221 | 'pa-in', 222 | 'pl-pl', 223 | 'ps-af', 224 | 'pt-br', 225 | 'pt-pt', 226 | 'rm-ch', 227 | 'ro-ro', 228 | 'ru-ru', 229 | 'rw-rw', 230 | 'si-lk', 231 | 'sk-sk', 232 | 'sl-si', 233 | 'sq-al', 234 | 'sr-cyrl-ba', 235 | 'sr-cyrl-rs', 236 | 'sr-latn-rs', 237 | 'sv-se', 238 | 'sw-ke', 239 | 'ta-in', 240 | 'te-in', 241 | 'th-th', 242 | 'tn-za', 243 | 'tr-tr', 244 | 'tt-ru', 245 | 'uk-ua', 246 | 'ur-pk', 247 | 'uz-Latn-uz', 248 | 'vi-vn', 249 | 'wo-sn', 250 | 'xh-za', 251 | 'yo-ng', 252 | 'zh-cn', 253 | 'zh-tw', 254 | 'zu-za')] 255 | [string]$ProofingTools = 'en-US', 256 | [switch]$XmlOnly 257 | ) 258 | 259 | #=================================================================================================== 260 | # OfficeODT 261 | #=================================================================================================== 262 | Write-Host '========================================================================================' -ForegroundColor DarkGray 263 | Write-Verbose 'Office Deployment Tool: https://www.microsoft.com/en-us/download/details.aspx?id=49117' -Verbose 264 | #$OfficeODTUrl = 'https://download.microsoft.com/download/2/7/A/27AF1BE6-DD20-4CB4-B154-EBAB8A7D4A7E/officedeploymenttool_11509-33604.exe' 265 | $OfficeODTUrl = 'https://download.microsoft.com/download/2/7/A/27AF1BE6-DD20-4CB4-B154-EBAB8A7D4A7E/officedeploymenttool_11617-33601.exe' 266 | $OfficeODTDir = "$RepositoryRootPath\OfficeODT" 267 | $OfficeODTDownloadFile = "officedeploymenttool_11617-33601.exe" 268 | $OfficeODT = 'setup.exe' 269 | $OfficeODTFullName = "$OfficeODTDir\$OfficeODT" 270 | if (!(Test-Path "$OfficeODTFullName")) { 271 | Write-Warning "Office ODT must be downloaded and extracted to $OfficeODTFullName" 272 | Write-Verbose "Office ODT Url: $OfficeODTUrl" -Verbose 273 | Write-Verbose "Office ODT Download File: $OfficeODTDownloadFile" -Verbose 274 | Write-Verbose "Office ODT Directory: $OfficeODTDir" -Verbose 275 | Write-Verbose "Office ODT: $OfficeODTFullName" -Verbose 276 | if (!(Test-Path "$OfficeODTDir")) {New-Item "$OfficeODTDir" -ItemType Directory -Force | Out-Null} 277 | Invoke-WebRequest -Uri $OfficeODTUrl -OutFile "$OfficeODTDir\$OfficeODTDownloadFile" 278 | Start-Process "$OfficeODTDir\$OfficeODTDownloadFile" -ArgumentList "/extract:`"$OfficeODTDir`"" -Wait 279 | } 280 | if (!(Test-Path "$OfficeODTFullName")) { 281 | Write-Warning "You will need to download and extract the Office Deployment Tool to $OfficeODTFullName before using OSDUpdate OfficeDownload" 282 | Break 283 | } 284 | 285 | if ($OfficeProduct -eq 'Office 365 ProPlus') {$ODTOfficeProduct = 'O365ProPlusRetail'} 286 | if ($OfficeProduct -eq 'Office 365 Business') {$ODTOfficeProduct = 'O365BusinessRetail'} 287 | if ($OfficeProduct -eq 'Office 2019 ProPlus') { 288 | $ODTOfficeProduct = 'Standard2019Volume' 289 | $ODTChannel = 'PerpetualVL2019' 290 | } 291 | if ($OfficeProduct -eq 'Office 2019 Standard') { 292 | $ODTOfficeProduct = 'Standard2019Volume' 293 | $ODTChannel = 'PerpetualVL2019' 294 | } 295 | if ($OfficeProduct -eq 'Project 2019 Pro') { 296 | $ODTOfficeProduct = 'ProjectPro2019Volume ' 297 | $ODTChannel = 'PerpetualVL2019' 298 | } 299 | if ($OfficeProduct -eq 'Project 2019 Standard') { 300 | $ODTOfficeProduct = 'ProjectStd2019Volume' 301 | $ODTChannel = 'PerpetualVL2019' 302 | } 303 | if ($OfficeProduct -eq 'Visio 2019 Pro') { 304 | $ODTOfficeProduct = 'VisioPro2019Volume' 305 | $ODTChannel = 'PerpetualVL2019' 306 | } 307 | if ($OfficeProduct -eq 'Visio 2019 Standard') { 308 | $ODTOfficeProduct = 'VisioStd2019Volume' 309 | $ODTChannel = 'PerpetualVL2019' 310 | } 311 | 312 | if (($ODTOfficeProduct -eq 'O365ProPlusRetail') -or ($ODTOfficeProduct -eq 'O365BusinessRetail')) { 313 | if ($UpdateChannel -eq 'Insiders') {$ODTChannel = 'Insiders'} 314 | if ($UpdateChannel -eq 'Monthly') {$ODTChannel = 'Monthly'} 315 | if ($UpdateChannel -eq 'SAC') {$ODTChannel = 'Broad'} 316 | if ($UpdateChannel -eq 'SACT') {$ODTChannel = 'Targeted'} 317 | } 318 | #=================================================================================================== 319 | # OfficeDownload 320 | #=================================================================================================== 321 | if ($UpdateChannel -eq 'Monthly') { 322 | $OfficeDownload = "$OfficeProduct $OfficeArch-Bit" 323 | } else { 324 | $OfficeDownload = "$OfficeProduct $OfficeArch-Bit $UpdateChannel" 325 | } 326 | $DownloadsPath = "$RepositoryRootPath\$OfficeDownload" 327 | 328 | $ODTXml = @" 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | "@ 340 | 341 | if (!(Test-Path $DownloadsPath)) {New-Item $DownloadsPath -ItemType Directory -Force | Out-Null} 342 | $ODTXml | Out-File "$DownloadsPath\OSDUpdate.xml" -Encoding utf8 -Force 343 | Write-Host '========================================================================================' -ForegroundColor DarkGray 344 | Write-Verbose "Office Deployment Tool Download XML saved to $DownloadsPath\OSDUpdate.xml" -Verbose 345 | Write-Verbose "You can download $OfficeProduct manually with the following command line:" -Verbose 346 | Write-Verbose "`"$OfficeODTFullName`" /download `"$DownloadsPath\OSDUpdate.xml`"" -Verbose 347 | Write-Host '========================================================================================' -ForegroundColor DarkGray 348 | Write-Verbose "ODT SourcePath: $DownloadsPath" -Verbose 349 | Write-Verbose "ODT OfficeClientEdition: $OfficeArch" -Verbose 350 | Write-Verbose "ODT Channel: $ODTChannel" -Verbose 351 | Write-Verbose "ODT Product Id: $ODTOfficeProduct" -Verbose 352 | Write-Verbose "ODT Language Primary: $LanguageId" -Verbose 353 | Write-Verbose "ODT Proofing Tools: $ProofingTools" -Verbose 354 | Write-Verbose "Download Full Path: $DownloadsPath" -Verbose 355 | Write-Host '========================================================================================' -ForegroundColor DarkGray 356 | if (!($XmlOnly)) { 357 | Write-Verbose "Downloading ... This may take a while ..." -Verbose 358 | Start-Process -FilePath "$OfficeODTFullName" -ArgumentList "/download","`"$DownloadsPath\OSDUpdate.xml`"" -Wait 359 | Write-Host '========================================================================================' -ForegroundColor DarkGray 360 | } 361 | Write-Verbose "Complete!" -Verbose 362 | } -------------------------------------------------------------------------------- /Public/Get-OSDUpdate.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Returns an Array of Microsoft Updates 4 | 5 | .DESCRIPTION 6 | Returns an Array of Microsoft Updates contained in the local WSUS Catalogs 7 | 8 | .LINK 9 | https://osdupdate.osdeploy.com/module/functions/get-osdupdate 10 | 11 | .PARAMETER GridView 12 | Displays the results in GridView with -PassThru 13 | 14 | .PARAMETER Silent 15 | Hide the Current Update Date information 16 | #> 17 | 18 | function Get-OSDUpdate { 19 | [CmdletBinding()] 20 | PARAM ( 21 | [switch]$GridView, 22 | [switch]$Silent 23 | ) 24 | #=================================================================================================== 25 | # Variables 26 | #=================================================================================================== 27 | $OSDUpdate = @() 28 | $OSDUpdate = Get-OSDSUS OSDUpdate 29 | #=================================================================================================== 30 | # GridView 31 | #=================================================================================================== 32 | if ($GridView.IsPresent) { 33 | $OSDUpdate = $OSDUpdate | Out-GridView -PassThru -Title 'Select OSDUpdates to Return' 34 | } 35 | #=================================================================================================== 36 | # Return 37 | #=================================================================================================== 38 | Return $OSDUpdate 39 | } 40 | -------------------------------------------------------------------------------- /Public/Get-OSDUpdate.txt: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Returns an Array of Microsoft Updates 4 | 5 | .DESCRIPTION 6 | Returns an Array of Microsoft Updates contained in the local WSUS Catalogs 7 | 8 | .LINK 9 | https://osdupdate.osdeploy.com/module/functions/get-osdupdate 10 | 11 | .PARAMETER GridView 12 | Displays the results in GridView with -PassThru 13 | 14 | .PARAMETER Silent 15 | Hide the Current Update Date information 16 | #> 17 | 18 | function Get-OSDUpdate { 19 | [CmdletBinding()] 20 | PARAM ( 21 | [switch]$GridView, 22 | [switch]$Silent 23 | ) 24 | #=================================================================================================== 25 | # Update Information 26 | #=================================================================================================== 27 | $OSDSUSCatalogs = "$((Get-Module -ListAvailable -Name OSDSUS).ModuleBase)\Catalogs" 28 | #Write-Verbose "$OSDSUSCatalogs" -Verbose 29 | 30 | $OSDSUSVersion = $((Get-Module -ListAvailable -Name OSDSUS | Sort-Object Version | Select-Object Version -Last 1).Version) 31 | #Write-Verbose "$OSDSUSVersion" -Verbose 32 | 33 | if (!($Silent.IsPresent)) { 34 | Write-Verbose "OSDSUS $OSDSUSVersion" -Verbose 35 | Write-Verbose "http://osdsus.osdeploy.com/release" -Verbose 36 | Write-Verbose 'Gathering Updates ...' -Verbose 37 | } 38 | #=================================================================================================== 39 | # Variables 40 | #=================================================================================================== 41 | $OSDUpdate = @() 42 | #=================================================================================================== 43 | # UpdateCatalogs 44 | #=================================================================================================== 45 | $OSDUpdateCatalogs = Get-ChildItem -Path "$OSDSUSCatalogs\*" -Include "*.xml" -Recurse 46 | #=================================================================================================== 47 | # Import Catalog XML Files 48 | #=================================================================================================== 49 | foreach ($OSDUpdateCatalog in $OSDUpdateCatalogs) { 50 | <# #Write-Verbose "Importing $($OSDUpdateCatalog.Name)" -Verbose 51 | if ($OSDUpdateCatalog.Name -match 'Office') { 52 | 53 | $OfficeUpdates = @() 54 | $OfficeUpdates = Import-Clixml -Path "$($OSDUpdateCatalog.FullName)" 55 | 56 | $OfficeUpdates = $OfficeUpdates | Sort-Object OriginUri -Unique 57 | $OfficeUpdates = $OfficeUpdates | Sort-Object CreationDate -Descending 58 | 59 | #$OfficeUpdates | Out-GridView 60 | 61 | $CurrentUpdates = @() 62 | $SupersededUpdates = @() 63 | 64 | foreach ($OfficeUpdate in $OfficeUpdates) { 65 | $SkipUpdate = $false 66 | 67 | foreach ($CurrentUpdate in $CurrentUpdates) { 68 | if ($($OfficeUpdate.FileName) -eq $($CurrentUpdate.FileName)) {$SkipUpdate = $true} 69 | } 70 | 71 | if ($SkipUpdate) { 72 | $SupersededUpdates += $OfficeUpdate 73 | } else { 74 | $CurrentUpdates += $OfficeUpdate 75 | } 76 | } 77 | $OSDUpdate += $CurrentUpdates 78 | } else { 79 | $OSDUpdate += Import-Clixml -Path "$($OSDUpdateCatalog.FullName)" 80 | } #> 81 | $OSDUpdate += Import-Clixml -Path "$($OSDUpdateCatalog.FullName)" 82 | } 83 | #=================================================================================================== 84 | # Standard Filters 85 | #=================================================================================================== 86 | $OSDUpdate = $OSDUpdate | Where-Object {$_.FileName -notlike "*.exe"} 87 | $OSDUpdate = $OSDUpdate | Where-Object {$_.FileName -notlike "*.psf"} 88 | $OSDUpdate = $OSDUpdate | Where-Object {$_.FileName -notlike "*.txt"} 89 | $OSDUpdate = $OSDUpdate | Where-Object {$_.FileName -notlike "*delta.exe"} 90 | $OSDUpdate = $OSDUpdate | Where-Object {$_.FileName -notlike "*express.cab"} 91 | #=================================================================================================== 92 | # Sorting 93 | #=================================================================================================== 94 | #$OSDUpdate = $OSDUpdate | Sort-Object -Property @{Expression = {$_.CreationDate}; Ascending = $false}, Size -Descending 95 | $OSDUpdate = $OSDUpdate | Sort-Object -Property CreationDate -Descending 96 | #=================================================================================================== 97 | # GridView 98 | #=================================================================================================== 99 | if ($GridView.IsPresent) { 100 | $OSDUpdate = $OSDUpdate | Out-GridView -PassThru -Title 'Select OSDUpdates to Return' 101 | } 102 | #=================================================================================================== 103 | # Return 104 | #=================================================================================================== 105 | Return $OSDUpdate 106 | } 107 | -------------------------------------------------------------------------------- /Public/New-OSDUpdatePackage.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Creates Package Bundles of Microsoft Updates 4 | 5 | .DESCRIPTION 6 | Creates Package Bundles of Microsoft Updates 7 | Requires BITS for downloading the updates 8 | Requires Internet access for downloading the updates 9 | 10 | .LINK 11 | https://osdupdate.osdeploy.com/module/functions/new-osdupdatepackage 12 | 13 | .PARAMETER PackagePath 14 | Package Content will be downloaded into the PackagePath 15 | 16 | .PARAMETER PackageName 17 | The name of the OSDUpdate Package. These values are predefined 18 | 19 | .PARAMETER AppendPackageName 20 | Downloads Updates in the PackagePath in a PackageName subdirectory 21 | 22 | .PARAMETER GridView 23 | Displays the results in GridView with -PassThru. Updates selected in GridView can be selected 24 | 25 | .PARAMETER HideDownloaded 26 | Hides downloaded updates from the results 27 | 28 | .PARAMETER OfficeProfile 29 | Downloads Office Updates with the selected Profile 30 | 31 | .PARAMETER OfficeSetupUpdatesPath 32 | Updates Directory for Office Setup 33 | 34 | .PARAMETER RemoveSuperseded 35 | Remove Superseded Updates 36 | 37 | .PARAMETER SkipInstallScript 38 | Skips adding $PackagePath\Install-OSDUpdatePackage.ps1 39 | 40 | .PARAMETER SkipUpdateScript 41 | Skips adding $PackagePath\Update-OSDUpdatePackage.ps1 42 | 43 | #> 44 | function New-OSDUpdatePackage { 45 | [CmdletBinding()] 46 | PARAM ( 47 | [Parameter(Mandatory = $True)] 48 | [string]$PackagePath, 49 | 50 | [Parameter(Mandatory = $True)] 51 | [ValidateSet( 52 | #================================ 53 | # Office 54 | #================================ 55 | 'Office 2010 32-Bit', 56 | 'Office 2010 64-Bit', 57 | 'Office 2013 32-Bit', 58 | 'Office 2013 64-Bit', 59 | 'Office 2016 32-Bit', 60 | 'Office 2016 64-Bit', 61 | #================================ 62 | # Windows 63 | #================================ 64 | 'Windows 10 x64 1803', 65 | 'Windows 10 x64 1809', 66 | 'Windows 10 x64 1903', 67 | 'Windows 10 x64 1909', 68 | 'Windows 10 x64 2004', 69 | 'Windows 10 x64 2009', 70 | 'Windows 10 x64 20H2', 71 | 'Windows 10 x64 21H1', 72 | 'Windows 10 x64 21H2', 73 | 'Windows 10 x64 22H2', 74 | 'Windows 11 x64 21H2', 75 | 'Windows 11 x64 22H2', 76 | 'Windows 10 x86 1803', 77 | 'Windows 10 x86 1809', 78 | 'Windows 10 x86 1903', 79 | 'Windows 10 x86 1909', 80 | 'Windows 10 x86 2004', 81 | 'Windows 10 x86 2009', 82 | 'Windows 10 x86 20H2', 83 | 'Windows 10 x86 21H1', 84 | 'Windows 10 x86 21H2', 85 | 'Windows 10 x86 22H2', 86 | 'Windows Server 1607', 87 | 'Windows Server 1709', 88 | 'Windows Server 1803', 89 | 'Windows Server 1809', 90 | 'Windows Server 1903', 91 | 'Windows Server 1909', 92 | 'Windows Server 2004', 93 | 'Windows Server 20H2', 94 | 'Windows Server 21H2', 95 | #================================ 96 | # Other 97 | #================================ 98 | 'McAfee SuperDAT v2', 99 | 'McAfee SuperDAT v3', 100 | 'Windows Defender 8-10 32-Bit', 101 | 'Windows Defender 8-10 64-Bit', 102 | 'Servicing Stacks')] 103 | [string]$PackageName, 104 | 105 | [switch]$AppendPackageName, 106 | [switch]$GridView, 107 | [switch]$HideDownloaded, 108 | 109 | [ValidateSet('Default','Proofing','Language','All')] 110 | [string]$OfficeProfile = 'Default', 111 | 112 | [string]$OfficeSetupUpdatesPath, 113 | 114 | [switch]$RemoveSuperseded, 115 | [switch]$SkipInstallScript, 116 | [switch]$SkipUpdateScript 117 | 118 | ) 119 | #=================================================================================================== 120 | # AppendPackageName 121 | #=================================================================================================== 122 | if ($AppendPackageName) { 123 | #=================================================================================================== 124 | # Copy Script 125 | #=================================================================================================== 126 | if (!($SkipInstallScript)) { 127 | Write-Host "Copying Install Packages Script to $PackagePath\Install-OSDUpdatePackages.ps1" -ForegroundColor Green 128 | Copy-Item "$($MyInvocation.MyCommand.Module.ModuleBase)\Scripts\Install-OSDUpdatePackages.ps1" "$PackagePath" -Force | Out-Null 129 | 130 | Write-Host "Copying Update Packages Script to $PackagePath\Update-OSDUpdatePackages.ps1" -ForegroundColor Green 131 | Copy-Item "$($MyInvocation.MyCommand.Module.ModuleBase)\Scripts\Update-OSDUpdatePackages.ps1" "$PackagePath" -Force | Out-Null 132 | } 133 | #=================================================================================================== 134 | # Append Package Name 135 | #=================================================================================================== 136 | $PackagePath = "$PackagePath\$PackageName" 137 | } 138 | #=================================================================================================== 139 | # PackagePath 140 | #=================================================================================================== 141 | if (!(Test-Path "$PackagePath")) {New-Item -Path "$PackagePath" -ItemType Directory -Force | Out-Null} 142 | Write-Host $PackageName -ForegroundColor Green 143 | #=================================================================================================== 144 | # Get-OSDUpdate 145 | #=================================================================================================== 146 | $OSDUpdate = @() 147 | #=================================================================================================== 148 | # McAfee SuperDAT v2 149 | #=================================================================================================== 150 | if ($PackageName -eq 'McAfee SuperDAT v2') { 151 | #=================================================================================================== 152 | # Install Script 153 | #=================================================================================================== 154 | if (!($SkipInstallScript)) { 155 | Write-Host "Install Script: $PackagePath\Install-OSDUpdatePackage.ps1" -ForegroundColor Green 156 | Copy-Item "$($MyInvocation.MyCommand.Module.ModuleBase)\Scripts\Install-OSDUpdateMcAfee.ps1" "$PackagePath\Install-OSDUpdatePackage.ps1" -Force | Out-Null 157 | } 158 | #=================================================================================================== 159 | # Update Script 160 | #=================================================================================================== 161 | if (!($SkipUpdateScript)) { 162 | Write-Host "Update Script: $PackagePath\Update-OSDUpdatePackage.ps1" -ForegroundColor Green 163 | $ExportLine = "New-OSDUpdatePackage -PackageName '$PackageName' -PackagePath ""`$PSScriptRoot""" 164 | $ExportLine | Out-File -FilePath "$PackagePath\Update-OSDUpdatePackage.ps1" 165 | } 166 | #=================================================================================================== 167 | # Download 168 | #=================================================================================================== 169 | Get-DownMcAfee -Download "SuperDAT v2" -DownloadPath $PackagePath -RenameDAT 170 | #=================================================================================================== 171 | # McAfee SuperDAT v3 172 | #=================================================================================================== 173 | } elseif ($PackageName -eq 'McAfee SuperDAT v3') { 174 | #=================================================================================================== 175 | # Install Script 176 | #=================================================================================================== 177 | if (!($SkipInstallScript)) { 178 | Write-Host "Install Script: $PackagePath\Install-OSDUpdatePackage.ps1" -ForegroundColor Green 179 | Copy-Item "$($MyInvocation.MyCommand.Module.ModuleBase)\Scripts\Install-OSDUpdateMcAfee.ps1" "$PackagePath\Install-OSDUpdatePackage.ps1" -Force | Out-Null 180 | } 181 | #=================================================================================================== 182 | # Update Script 183 | #=================================================================================================== 184 | if (!($SkipUpdateScript)) { 185 | Write-Host "Update Script: $PackagePath\Update-OSDUpdatePackage.ps1" -ForegroundColor Green 186 | $ExportLine = "New-OSDUpdatePackage -PackageName '$PackageName' -PackagePath ""`$PSScriptRoot""" 187 | $ExportLine | Out-File -FilePath "$PackagePath\Update-OSDUpdatePackage.ps1" 188 | } 189 | #=================================================================================================== 190 | # Download 191 | #=================================================================================================== 192 | Get-DownMcAfee -Download "SuperDAT v3" -DownloadPath $PackagePath -RenameDAT 193 | #=================================================================================================== 194 | # Windows Defender 195 | #=================================================================================================== 196 | } elseif ($PackageName -eq 'Windows Defender 8-10 64-Bit') { 197 | #=================================================================================================== 198 | # Install Script 199 | #=================================================================================================== 200 | if (!($SkipInstallScript)) { 201 | Write-Host "Install Script: $PackagePath\Install-OSDUpdatePackage.ps1" -ForegroundColor Green 202 | Copy-Item "$($MyInvocation.MyCommand.Module.ModuleBase)\Scripts\Install-OSDUpdateDefender.ps1" "$PackagePath\Install-OSDUpdatePackage.ps1" -Force | Out-Null 203 | } 204 | #=================================================================================================== 205 | # Update Script 206 | #=================================================================================================== 207 | if (!($SkipUpdateScript)) { 208 | Write-Host "Update Script: $PackagePath\Update-OSDUpdatePackage.ps1" -ForegroundColor Green 209 | $ExportLine = "New-OSDUpdatePackage -PackageName '$PackageName' -PackagePath ""`$PSScriptRoot""" 210 | $ExportLine | Out-File -FilePath "$PackagePath\Update-OSDUpdatePackage.ps1" 211 | } 212 | #=================================================================================================== 213 | # Download 214 | #=================================================================================================== 215 | Get-DownDefender -OS "Windows 8-10" -OSArch '64-Bit' -DownloadPath $PackagePath 216 | } elseif ($PackageName -eq 'Windows Defender 8-10 32-Bit') { 217 | #=================================================================================================== 218 | # Install Script 219 | #=================================================================================================== 220 | if (!($SkipInstallScript)) { 221 | Write-Host "Install Script: $PackagePath\Install-OSDUpdatePackage.ps1" -ForegroundColor Green 222 | Copy-Item "$($MyInvocation.MyCommand.Module.ModuleBase)\Scripts\Install-OSDUpdateDefender.ps1" "$PackagePath\Install-OSDUpdatePackage.ps1" -Force | Out-Null 223 | } 224 | #=================================================================================================== 225 | # Update Script 226 | #=================================================================================================== 227 | if (!($SkipUpdateScript)) { 228 | Write-Host "Update Script: $PackagePath\Update-OSDUpdatePackage.ps1" -ForegroundColor Green 229 | $ExportLine = "New-OSDUpdatePackage -PackageName '$PackageName' -PackagePath ""`$PSScriptRoot""" 230 | $ExportLine | Out-File -FilePath "$PackagePath\Update-OSDUpdatePackage.ps1" 231 | } 232 | #=================================================================================================== 233 | # Download 234 | #=================================================================================================== 235 | Get-DownDefender -OS "Windows 8-10" -OSArch '32-Bit' -DownloadPath $PackagePath 236 | } else { 237 | $OSDUpdate = Get-OSDUpdate 238 | #=================================================================================================== 239 | # Filter Catalog 240 | #=================================================================================================== 241 | if ($PackageName -match 'Office') { 242 | $OSDUpdate = $OSDUpdate | Where-Object {$_.Catalog -eq $PackageName} 243 | } 244 | 245 | if ($PackageName -match 'Windows 10') { 246 | $OSDUpdate = $OSDUpdate | Where-Object {$_.Catalog -match 'Windows 10'} 247 | $OSDUpdate = $OSDUpdate | Where-Object {$_.Catalog -notmatch 'Dynamic'} 248 | } 249 | if ($PackageName -match 'Windows 11') { 250 | $OSDUpdate = $OSDUpdate | Where-Object {$_.Catalog -match 'Windows 11'} 251 | $OSDUpdate = $OSDUpdate | Where-Object {$_.Catalog -notmatch 'Dynamic'} 252 | } 253 | if ($PackageName -match 'Windows Server') { 254 | $OSDUpdate = $OSDUpdate | Where-Object {$_.Catalog -match 'Windows Server'} 255 | $OSDUpdate = $OSDUpdate | Where-Object {$_.Catalog -notmatch 'Dynamic'} 256 | } 257 | #=================================================================================================== 258 | # AllOSDUpdates 259 | #=================================================================================================== 260 | $AllOSDUpdates = $OSDUpdate 261 | #=================================================================================================== 262 | # Superseded Updates 263 | #=================================================================================================== 264 | $CurrentUpdates = @() 265 | if ($PackageName -match 'Office') { 266 | $OSDUpdate = $OSDUpdate | Sort-Object OriginUri -Unique 267 | $OSDUpdate = $OSDUpdate | Sort-Object CreationDate -Descending 268 | 269 | $SupersededUpdates = @() 270 | 271 | foreach ($OfficeUpdate in $OSDUpdate) { 272 | $SkipUpdate = $false 273 | 274 | foreach ($CurrentUpdate in $CurrentUpdates) { 275 | if ($($OfficeUpdate.FileName) -eq $($CurrentUpdate.FileName)) {$SkipUpdate = $true} 276 | } 277 | 278 | if ($SkipUpdate) { 279 | $SupersededUpdates += $OfficeUpdate 280 | } else { 281 | $CurrentUpdates += $OfficeUpdate 282 | } 283 | } 284 | $OSDUpdate = $CurrentUpdates 285 | } else { 286 | $CurrentUpdates = $OSDUpdate 287 | } 288 | #=================================================================================================== 289 | # Find Existing Updates 290 | #=================================================================================================== 291 | $LocalUpdates = @() 292 | $LocalSuperseded = @() 293 | 294 | $LocalUpdates = Get-ChildItem -Path "$PackagePath\*" -Directory -Recurse | Select-Object -Property * 295 | $LocalUpdatesMsp = Get-ChildItem -Path "$PackagePath\*" *.msp -File -Recurse | Select-Object -Property * | Sort-Object CreationDate -Descending 296 | $LocalUpdatesXml = Get-ChildItem -Path "$PackagePath\*" *.xml -File -Recurse | Select-Object -Property * | Sort-Object CreationDate -Descending 297 | 298 | foreach ($Update in $LocalUpdates) { 299 | if ($CurrentUpdates.Title -NotContains $Update.Name) {$LocalSuperseded += $Update.FullName} 300 | } 301 | #=================================================================================================== 302 | # Remove Superseded Update Directories 303 | #=================================================================================================== 304 | foreach ($Update in $LocalSuperseded) { 305 | if ($RemoveSuperseded.IsPresent) { 306 | Write-Warning "Removing Superseded: $Update" 307 | Remove-Item $Update -Recurse -Force | Out-Null 308 | } else { 309 | Write-Warning "Superseded: $Update" 310 | } 311 | } 312 | #=================================================================================================== 313 | # Remove Superseded Update Files 314 | #=================================================================================================== 315 | if ($PackageName -match 'Office') { 316 | foreach ($Update in $SupersededUpdates) { 317 | $SupersededMsp = "$PackagePath\$($Update.Title)\$([IO.Path]::GetFileNameWithoutExtension($Update.FileName)).msp" 318 | $SupersededXml = "$PackagePath\$($Update.Title)\$([IO.Path]::GetFileNameWithoutExtension($Update.FileName)).xml" 319 | if (Test-Path "$SupersededMsp") { 320 | if ($RemoveSuperseded.IsPresent) { 321 | Write-Warning "Removing Superseded: $SupersededMsp" 322 | Remove-Item $SupersededMsp -Force | Out-Null 323 | } else { 324 | Write-Warning "Superseded: $SupersededMsp" 325 | } 326 | } 327 | if (Test-Path "$SupersededXml") { 328 | if ($RemoveSuperseded.IsPresent) { 329 | Write-Warning "Removing Superseded: $SupersededXml" 330 | Remove-Item $SupersededXml -Force | Out-Null 331 | } else { 332 | Write-Warning "Superseded: $SupersededXml" 333 | } 334 | } 335 | } 336 | } 337 | #=================================================================================================== 338 | # Get Downloaded Updates 339 | #=================================================================================================== 340 | foreach ($Update in $OSDUpdate) { 341 | if ($PackageName -like "Windows*" -or $PackageName -eq 'Servicing Stacks') { 342 | $FullUpdatePath = "$PackagePath\$($Update.Title)\$($Update.FileName)" 343 | if (Test-Path $FullUpdatePath) { 344 | $Update.OSDStatus = 'Downloaded' 345 | } 346 | } 347 | if ($PackageName -match 'Office') { 348 | $FullUpdatePath = "$PackagePath\$($Update.Title)\$([IO.Path]::GetFileNameWithoutExtension($Update.FileName)).msp" 349 | if (Test-Path $FullUpdatePath) { 350 | $Update.OSDStatus = 'Downloaded' 351 | } 352 | } 353 | } 354 | #=================================================================================================== 355 | # Filter Other 356 | #=================================================================================================== 357 | if ($PackageName -eq 'Servicing Stacks') { 358 | $OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateGroup -eq 'SSU'} 359 | } 360 | 361 | if ($PackageName -like "Windows*") { 362 | if ($PackageName -match 'x64') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateArch -eq 'x64'}} 363 | if ($PackageName -match 'x86') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateArch -eq 'x86'}} 364 | 365 | if ($PackageName -match '1507') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '1507'}} 366 | if ($PackageName -match '1511') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '1511'}} 367 | if ($PackageName -match '1607') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '1607'}} 368 | if ($PackageName -match '1703') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '1703'}} 369 | if ($PackageName -match '1709') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '1709'}} 370 | if ($PackageName -match '1803') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '1803'}} 371 | if ($PackageName -match '1809') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '1809'}} 372 | if ($PackageName -match '1903') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '1903'}} 373 | if ($PackageName -match '1909') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '1909'}} 374 | if ($PackageName -match '2004') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '2004'}} 375 | if ($PackageName -match '20H2') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '20H2'}} 376 | if ($PackageName -match '21H1') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '21H1'}} 377 | if ($PackageName -match '21H2') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '21H2'}} 378 | if ($PackageName -match '22H2') {$OSDUpdate = $OSDUpdate | Where-Object {$_.UpdateBuild -eq '22H2'}} 379 | } 380 | $OSDUpdate | Export-Clixml -Path "$PackagePath\OSDUpdatePackage.xml" -Force | Out-Null 381 | 382 | if ($PackageName -like "Office*") { 383 | if ($OfficeProfile -eq 'Default') { 384 | $OSDUpdate = $OSDUpdate | Where-Object {$_.FileName -like "*none*" -or $_.FileName -like "*en-us*"} 385 | $OSDUpdate = $OSDUpdate | Where-Object {$_.Title -notlike "*Language Pack*"} 386 | } 387 | if ($OfficeProfile -eq 'Language') { 388 | $OSDUpdate = $OSDUpdate | Where-Object {$_.FileName -notlike "*none*" -and $_.FileName -notlike "*en-us*"} 389 | } 390 | if ($OfficeProfile -eq 'Proofing') { 391 | $OSDUpdate = $OSDUpdate | Where-Object {$_.FileName -like "*Proof*"} 392 | } 393 | } 394 | #=================================================================================================== 395 | # HideDownloaded 396 | #=================================================================================================== 397 | if ($HideDownloaded.IsPresent) { 398 | $OSDUpdate = $OSDUpdate | Where-Object {$_.OSDStatus -ne 'Downloaded'} 399 | } 400 | #=================================================================================================== 401 | # GridView 402 | #=================================================================================================== 403 | if ($PackageName -like "Office*") { 404 | $OSDUpdate = $OSDUpdate | Select-Object -Property OSDStatus,Catalog,CreationDate,KBNumber,Title,FileName,Size,FileUri,OriginUri,OSDGuid 405 | } else { 406 | $OSDUpdate = $OSDUpdate | Select-Object -Property OSDStatus,Catalog,UpdateOS,UpdateGroup,UpdateArch,UpdateBuild,CreationDate,KBNumber,Title,FileName,Size,FileUri,OriginUri,OSDGuid 407 | } 408 | if ($GridView.IsPresent) {$OSDUpdate = $OSDUpdate | Out-GridView -PassThru -Title "Select OSDUpdate Downloads to include in the Package"} 409 | #=================================================================================================== 410 | # Sort 411 | #=================================================================================================== 412 | $OSDUpdate = $OSDUpdate | Sort-Object DateCreated 413 | #=================================================================================================== 414 | # Download 415 | #=================================================================================================== 416 | foreach ($Update in $OSDUpdate) { 417 | $UpdateFile = ($Update).FileName 418 | $UpdateGroup = ($Update).UpdateGroup 419 | $UpdateTitle = ($Update).Title 420 | 421 | $DownloadDirectory = Join-Path $PackagePath $UpdateTitle 422 | if (-NOT (Test-Path $DownloadDirectory)) { 423 | New-Item -Path $DownloadDirectory -ItemType Directory -Force | Out-Null 424 | } 425 | 426 | $DownloadUrl = ($Update).OriginUri 427 | $DownloadFile = Join-Path $DownloadDirectory $UpdateFile 428 | 429 | if ($PackageName -like "Office*") { 430 | #=================================================================================================== 431 | # MspFile 432 | #=================================================================================================== 433 | $MspFile = $UpdateFile -replace '.cab', '.msp' 434 | $MspFilePath = Join-Path $DownloadDirectory $MspFile 435 | 436 | Write-Host $MspFilePath -ForegroundColor Cyan 437 | 438 | if (-NOT (Test-Path $MspFilePath)) { 439 | Write-Host "Download: $DownloadUrl" -ForegroundColor Gray 440 | Start-BitsTransfer -Source $DownloadUrl -Destination $DownloadFile 441 | } 442 | 443 | if ((Test-Path $DownloadFile) -and (-NOT (Test-Path $MspFilePath))) { 444 | Write-Host "Expand: $MspFilePath" -ForegroundColor Gray 445 | expand "$DownloadFile" -F:* "$DownloadDirectory" | Out-Null 446 | } 447 | 448 | if ((Test-Path $DownloadFile) -and (Test-Path $MspFilePath)) { 449 | Write-Host "Remove: $DownloadFile" -ForegroundColor Gray 450 | Remove-Item $DownloadFile -Force | Out-Null 451 | } 452 | #=================================================================================================== 453 | # Office Setup Updates 454 | #=================================================================================================== 455 | if ($OfficeSetupUpdatesPath) { 456 | if (-NOT (Test-Path "$OfficeSetupUpdatesPath")) { 457 | New-Item -Path "$OfficeSetupUpdatesPath" -ItemType Directory -Force | Out-Null 458 | } 459 | 460 | Write-Host "Date Created: $($Update.CreationDate)" -ForegroundColor Gray 461 | Write-Host "Source: $MspFilePath" -ForegroundColor Gray 462 | Write-Host "Destination: $OfficeSetupUpdatesPath\$MspFile" -ForegroundColor Gray 463 | Copy-Item -Path $MspFilePath "$OfficeSetupUpdatesPath\$MspFile" -Force 464 | } 465 | } 466 | else { 467 | if (Test-Path $DownloadFile) { 468 | Write-Host -ForegroundColor Cyan $UpdateTitle 469 | Write-Host -ForegroundColor Gray $DownloadFile 470 | } else { 471 | Write-Host -ForegroundColor Cyan $UpdateTitle 472 | Write-Host -ForegroundColor Gray $DownloadUrl 473 | Write-Host -ForegroundColor Gray $DownloadFile 474 | Start-BitsTransfer -Source $DownloadUrl -Destination $DownloadFile 475 | } 476 | } 477 | } 478 | #=================================================================================================== 479 | # Install Script 480 | #=================================================================================================== 481 | if (!($SkipInstallScript)) { 482 | Write-Host "Install Script: $PackagePath\Install-OSDUpdatePackage.ps1" -ForegroundColor Green 483 | Copy-Item "$($MyInvocation.MyCommand.Module.ModuleBase)\Scripts\Install-OSDUpdatePackage.ps1" "$PackagePath" -Force | Out-Null 484 | } 485 | #=================================================================================================== 486 | # Update Script 487 | #=================================================================================================== 488 | if (!($SkipUpdateScript)) { 489 | Write-Host "Update Script: $PackagePath\Update-OSDUpdatePackage.ps1" -ForegroundColor Green 490 | $ExportLine = "New-OSDUpdatePackage -PackageName '$PackageName' -PackagePath ""`$PSScriptRoot"" -RemoveSuperseded" 491 | $ExportLine | Out-File -FilePath "$PackagePath\Update-OSDUpdatePackage.ps1" 492 | } 493 | } 494 | } -------------------------------------------------------------------------------- /Public/Update-ModuleOSDUpdate.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Updates the OSDUpdate PowerShell Module to the latest version 4 | 5 | .DESCRIPTION 6 | Updates the OSDUpdate PowerShell Module to the latest version from the PowerShell Gallery 7 | 8 | .LINK 9 | https://osdupdate.osdeploy.com/module/functions/update-moduleosdupdate 10 | 11 | .Example 12 | Update-ModuleOSDUpdate 13 | #> 14 | 15 | function Update-ModuleOSDUpdate { 16 | [CmdletBinding()] 17 | PARAM () 18 | try { 19 | Write-Warning "Uninstall-Module -Name OSDUpdate -AllVersions -Force" 20 | Uninstall-Module -Name OSDUpdate -AllVersions -Force 21 | } 22 | catch {} 23 | 24 | try { 25 | Write-Warning "Install-Module -Name OSDUpdate -Force" 26 | Install-Module -Name OSDUpdate -Force 27 | } 28 | catch {} 29 | 30 | try { 31 | Write-Warning "Import-Module -Name OSDUpdate -Force" 32 | Import-Module -Name OSDUpdate -Force 33 | } 34 | catch {} 35 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OSDUpdate 2 | PowerShell Module 3 | https://osdupdate.osdeploy.com -------------------------------------------------------------------------------- /Scripts/Install-OSDUpdateDefender.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 5 2 | 3 | <# 4 | .SYNOPSIS 5 | Installs Windows Defender Updates 6 | 7 | .DESCRIPTION 8 | Installs Windows Defender Updates 9 | 10 | .NOTES 11 | Author: David Segura 12 | Website: osdeploy.com 13 | Twitter: @SeguraOSD 14 | Version: 21.1.7.2 15 | #> 16 | #====================================================================================== 17 | # Validate Admin Rights 18 | #====================================================================================== 19 | Write-Host "" 20 | # Verify Running as Admin 21 | $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 22 | If (!( $isAdmin )) { 23 | Write-Host "Checking User Account Control settings ..." -ForegroundColor Green 24 | if ((Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System).EnableLUA -eq 0) { 25 | #UAC Disabled 26 | Write-Host '========================================================================================' -ForegroundColor DarkGray 27 | Write-Host "User Account Control is Disabled ... " -ForegroundColor Green 28 | Write-Host "You will need to correct your UAC Settings ..." -ForegroundColor Green 29 | Write-Host "Try running this script in an Elevated PowerShell session ... Exiting" -ForegroundColor Green 30 | Write-Host '========================================================================================' -ForegroundColor DarkGray 31 | Start-Sleep -s 10 32 | Exit 0 33 | } else { 34 | #UAC Enabled 35 | Write-Host "UAC is Enabled" -ForegroundColor Green 36 | Start-Sleep -s 3 37 | if ($Silent) { 38 | Write-Host "-- Restarting as Administrator (Silent)" -ForegroundColor Cyan ; Start-Sleep -Seconds 1 39 | Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`" -Silent" -Verb RunAs -Wait 40 | } elseif($Restart) { 41 | Write-Host "-- Restarting as Administrator (Restart)" -ForegroundColor Cyan ; Start-Sleep -Seconds 1 42 | Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`" -Restart" -Verb RunAs -Wait 43 | } else { 44 | Write-Host "-- Restarting as Administrator" -ForegroundColor Cyan ; Start-Sleep -Seconds 1 45 | Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs -Wait 46 | } 47 | Exit 0 48 | } 49 | } else { 50 | Write-Host '========================================================================================' -ForegroundColor DarkGray 51 | Write-Host "-- Running with Elevated Permissions ..." -ForegroundColor Cyan ; Start-Sleep -Seconds 1 52 | Write-Host '========================================================================================' -ForegroundColor DarkGray 53 | } 54 | #====================================================================================== 55 | # Script Information 56 | #====================================================================================== 57 | $Invocation = (Get-Variable MyInvocation -Scope Script).Value 58 | $ScriptPath = Split-Path -Parent $Invocation.MyCommand.Path 59 | $ParentName = Split-Path $ScriptPath -Leaf 60 | #====================================================================================== 61 | # Logs 62 | #====================================================================================== 63 | $OSDAppName = "OSDUpdate-$ParentName" 64 | $OSDLogs = "$env:Temp" 65 | if (!(Test-Path $OSDLogs)) {New-Item $OSDLogs -ItemType Directory -Force | Out-Null} 66 | $OSDLogName = "$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-$OSDAppName.log" 67 | Start-Transcript -Path (Join-Path $OSDLogs $OSDLogName) 68 | #====================================================================================== 69 | # Start Script 70 | #====================================================================================== 71 | Write-Host "Start ... $(Join-Path $PSScriptRoot $MyInvocation.MyCommand.Name)" -ForegroundColor Green 72 | Write-Host "" 73 | #====================================================================================== 74 | # OS Information 75 | #====================================================================================== 76 | $OSCaption = $((Get-WmiObject -Class Win32_OperatingSystem).Caption).Trim() 77 | $OSArchitecture = $((Get-WmiObject -Class Win32_OperatingSystem).OSArchitecture).Trim() 78 | $OSProductType = $((Get-WmiObject -Class Win32_OperatingSystem).ProductType) 79 | $OSVersion = $((Get-WmiObject -Class Win32_OperatingSystem).Version).Trim() 80 | $OSBuildNumber = $((Get-WmiObject -Class Win32_OperatingSystem).BuildNumber).Trim() 81 | Write-Host "Operating System: $OSCaption" -ForegroundColor Cyan 82 | Write-Host "OS Architecture: $OSArchitecture" -ForegroundColor Cyan 83 | Write-Host "OS ProductType: $OSProductType" -ForegroundColor Cyan 84 | Write-Host "OS Version: $OSVersion" -ForegroundColor Cyan 85 | Write-Host "OS Build Number: $OSBuildNumber" -ForegroundColor Cyan 86 | if ($OSVersion -Like "10*") { 87 | $OSReleaseID = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ReleaseId).ReleaseId 88 | Write-Host "OS Release ID: $OSReleaseID" -ForegroundColor Cyan 89 | } 90 | #====================================================================================== 91 | # Begin 92 | #====================================================================================== 93 | Write-Host "Updating Windows Defender Signatures" -ForegroundColor Green 94 | #====================================================================================== 95 | # Execute 96 | #====================================================================================== 97 | Get-ChildItem -Path $PSScriptRoot mpam*.exe | foreach { 98 | Write-Host $_.FullName -ForegroundColor Cyan 99 | Start-Process $_.FullName -Wait 100 | } 101 | #====================================================================================== 102 | # Complete 103 | #====================================================================================== 104 | Write-Host "" 105 | Write-Host "Complete ... $(Join-Path $PSScriptRoot $MyInvocation.MyCommand.Name)" -ForegroundColor Green 106 | Stop-Transcript 107 | Start-Sleep 5 -------------------------------------------------------------------------------- /Scripts/Install-OSDUpdateMcAfee.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 5 2 | 3 | <# 4 | .SYNOPSIS 5 | Installs McAfee SuperDAT v2 renamed to xdat.exe 6 | 7 | .DESCRIPTION 8 | Installs McAfee SuperDAT v2 renamed to xdat.exe 9 | 10 | .NOTES 11 | Author: David Segura 12 | Website: osdeploy.com 13 | Twitter: @SeguraOSD 14 | Version: 21.1.7.2 15 | #> 16 | #====================================================================================== 17 | # Validate Admin Rights 18 | #====================================================================================== 19 | Write-Host "" 20 | # Verify Running as Admin 21 | $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 22 | If (!( $isAdmin )) { 23 | Write-Host "Checking User Account Control settings ..." -ForegroundColor Green 24 | if ((Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System).EnableLUA -eq 0) { 25 | #UAC Disabled 26 | Write-Host '========================================================================================' -ForegroundColor DarkGray 27 | Write-Host "User Account Control is Disabled ... " -ForegroundColor Green 28 | Write-Host "You will need to correct your UAC Settings ..." -ForegroundColor Green 29 | Write-Host "Try running this script in an Elevated PowerShell session ... Exiting" -ForegroundColor Green 30 | Write-Host '========================================================================================' -ForegroundColor DarkGray 31 | Start-Sleep -s 10 32 | Exit 0 33 | } else { 34 | #UAC Enabled 35 | Write-Host "UAC is Enabled" -ForegroundColor Green 36 | Start-Sleep -s 3 37 | if ($Silent) { 38 | Write-Host "-- Restarting as Administrator (Silent)" -ForegroundColor Cyan ; Start-Sleep -Seconds 1 39 | Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`" -Silent" -Verb RunAs -Wait 40 | } elseif($Restart) { 41 | Write-Host "-- Restarting as Administrator (Restart)" -ForegroundColor Cyan ; Start-Sleep -Seconds 1 42 | Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`" -Restart" -Verb RunAs -Wait 43 | } else { 44 | Write-Host "-- Restarting as Administrator" -ForegroundColor Cyan ; Start-Sleep -Seconds 1 45 | Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs -Wait 46 | } 47 | Exit 0 48 | } 49 | } else { 50 | Write-Host '========================================================================================' -ForegroundColor DarkGray 51 | Write-Host "-- Running with Elevated Permissions ..." -ForegroundColor Cyan ; Start-Sleep -Seconds 1 52 | Write-Host '========================================================================================' -ForegroundColor DarkGray 53 | } 54 | #====================================================================================== 55 | # Script Information 56 | #====================================================================================== 57 | $Invocation = (Get-Variable MyInvocation -Scope Script).Value 58 | $ScriptPath = Split-Path -Parent $Invocation.MyCommand.Path 59 | $ParentName = Split-Path $ScriptPath -Leaf 60 | #====================================================================================== 61 | # Logs 62 | #====================================================================================== 63 | $OSDAppName = "OSDUpdate-$ParentName" 64 | $OSDLogs = "$env:Temp" 65 | if (!(Test-Path $OSDLogs)) {New-Item $OSDLogs -ItemType Directory -Force | Out-Null} 66 | $OSDLogName = "$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-$OSDAppName.log" 67 | Start-Transcript -Path (Join-Path $OSDLogs $OSDLogName) 68 | #====================================================================================== 69 | # Start Script 70 | #====================================================================================== 71 | Write-Host "Start ... $(Join-Path $PSScriptRoot $MyInvocation.MyCommand.Name)" -ForegroundColor Green 72 | Write-Host "" 73 | #====================================================================================== 74 | # OS Information 75 | #====================================================================================== 76 | $OSCaption = $((Get-WmiObject -Class Win32_OperatingSystem).Caption).Trim() 77 | $OSArchitecture = $((Get-WmiObject -Class Win32_OperatingSystem).OSArchitecture).Trim() 78 | $OSProductType = $((Get-WmiObject -Class Win32_OperatingSystem).ProductType) 79 | $OSVersion = $((Get-WmiObject -Class Win32_OperatingSystem).Version).Trim() 80 | $OSBuildNumber = $((Get-WmiObject -Class Win32_OperatingSystem).BuildNumber).Trim() 81 | Write-Host "Operating System: $OSCaption" -ForegroundColor Cyan 82 | Write-Host "OS Architecture: $OSArchitecture" -ForegroundColor Cyan 83 | Write-Host "OS ProductType: $OSProductType" -ForegroundColor Cyan 84 | Write-Host "OS Version: $OSVersion" -ForegroundColor Cyan 85 | Write-Host "OS Build Number: $OSBuildNumber" -ForegroundColor Cyan 86 | if ($OSVersion -Like "10*") { 87 | $OSReleaseID = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ReleaseId).ReleaseId 88 | Write-Host "OS Release ID: $OSReleaseID" -ForegroundColor Cyan 89 | } 90 | #====================================================================================== 91 | # Begin 92 | #====================================================================================== 93 | Write-Host "Updating McAfee xDAT Signatures" -ForegroundColor Green 94 | #====================================================================================== 95 | # Validate McAfee SuperDAT v2 96 | #====================================================================================== 97 | if (Test-Path "$PSScriptRoot\xdat.exe") { 98 | $Software = "McAfee VirusScan" 99 | $Installed = Get-ItemProperty ('HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*','HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*') -EA SilentlyContinue | Where-Object { $_.DisplayName -like "*$Software*" } 100 | #====================================================================================== 101 | # Execute 102 | #====================================================================================== 103 | If ($null -eq $Installed) { 104 | Write-Warning "McAfee VirusScan is not installed" 105 | } else { 106 | Write-Host "Installing McAfee xDAT" -ForegroundColor Cyan 107 | if (!(Test-Path "$env:Temp\McAfee\xDAT")) { 108 | New-Item "$env:Temp\McAfee\xDAT" -ItemType Directory -Force | Out-Null 109 | } 110 | Copy-Item "$PSScriptRoot\xdat.exe" "$env:Temp\McAfee\xDAT" -Force | Out-Null 111 | Start-Process "$env:Temp\McAfee\xDAT\xdat.exe" -ArgumentList '/SILENT','/F' -Wait 112 | } 113 | } 114 | #====================================================================================== 115 | # Validate McAfee SuperDAT v3 116 | #====================================================================================== 117 | if (Test-Path "$PSScriptRoot\V3_xdat.exe") { 118 | $Software = "McAfee Endpoint Security Threat Prevention" 119 | $Installed = Get-ItemProperty ('HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*','HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*') -EA SilentlyContinue | Where-Object { $_.DisplayName -like "*$Software*" } 120 | #====================================================================================== 121 | # Execute 122 | #====================================================================================== 123 | If ($null -eq $Installed) { 124 | Write-Warning "McAfee Endpoint Security is not installed" 125 | } else { 126 | Write-Host "Installing McAfee xDAT" -ForegroundColor Cyan 127 | if (!(Test-Path "$env:Temp\McAfee\xDAT")) { 128 | New-Item "$env:Temp\McAfee\xDAT" -ItemType Directory -Force | Out-Null 129 | } 130 | Copy-Item "$PSScriptRoot\V3_xdat.exe" "$env:Temp\McAfee\xDAT" -Force | Out-Null 131 | Start-Process "$env:Temp\McAfee\xDAT\V3_xdat.exe" -ArgumentList '/SILENT','/F' -Wait 132 | } 133 | } 134 | #====================================================================================== 135 | # Complete 136 | #====================================================================================== 137 | Write-Host "" 138 | Write-Host "Complete ... $(Join-Path $PSScriptRoot $MyInvocation.MyCommand.Name)" -ForegroundColor Green 139 | Stop-Transcript 140 | Start-Sleep 5 -------------------------------------------------------------------------------- /Scripts/Install-OSDUpdatePackage.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 5 2 | 3 | <# 4 | .SYNOPSIS 5 | Installs Updates in an OSDUpdate Package for Office and Windows 6 | 7 | .DESCRIPTION 8 | Installs Updates in an OSDUpdate Package for Office and Windows 9 | 10 | .NOTES 11 | Author: David Segura 12 | Website: osdeploy.com 13 | Twitter: @SeguraOSD 14 | Version: 21.1.7.2 15 | #> 16 | 17 | function Convert-GuidToCompressedGuid { 18 | <# 19 | .SYNOPSIS 20 | This converts a GUID to a compressed GUID also known as a product code. 21 | .DESCRIPTION 22 | This function will typically be used to figure out the product code 23 | that matches up with the product code stored in the 'SOFTWARE\Classes\Installer\Products' 24 | registry path to a MSI installer GUID. 25 | .EXAMPLE 26 | Convert-GuidToCompressedGuid -Guid '{7C6F0282-3DCD-4A80-95AC-BB298E821C44}' 27 | 28 | This example would output the compressed GUID '2820F6C7DCD308A459CABB92E828C144' 29 | .PARAMETER Guid 30 | The GUID you'd like to convert. 31 | .LINK 32 | https://www.adamtheautomator.com/compressed-guid-with-powershell/ 33 | #> 34 | [CmdletBinding()] 35 | [OutputType()] 36 | param ( 37 | [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Mandatory)] 38 | [string]$Guid 39 | ) 40 | begin { 41 | $Guid = $Guid.Replace('-', '').Replace('{', '').Replace('}', '') 42 | } 43 | process { 44 | try { 45 | $Groups = @( 46 | $Guid.Substring(0, 8).ToCharArray(), 47 | $Guid.Substring(8, 4).ToCharArray(), 48 | $Guid.Substring(12, 4).ToCharArray(), 49 | $Guid.Substring(16, 16).ToCharArray() 50 | ) 51 | $Groups[0..2] | foreach { 52 | [array]::Reverse($_) 53 | } 54 | $CompressedGuid = ($Groups[0..2] | foreach { $_ -join '' }) -join '' 55 | 56 | $chararr = $Groups[3] 57 | for ($i = 0; $i -lt $chararr.count; $i++) { 58 | if (($i % 2) -eq 0) { 59 | $CompressedGuid += ($chararr[$i+1] + $chararr[$i]) -join '' 60 | } 61 | } 62 | $CompressedGuid 63 | } catch { 64 | Write-Error $_.Exception.Message 65 | } 66 | } 67 | } 68 | 69 | function Convert-CompressedGuidToGuid { 70 | <# 71 | .SYNOPSIS 72 | This converts a compressed GUID also known as a product code into a GUID. 73 | .DESCRIPTION 74 | This function will typically be used to figure out the MSI installer GUID 75 | that matches up with the product code stored in the 'SOFTWARE\Classes\Installer\Products' 76 | registry path. 77 | .EXAMPLE 78 | Convert-CompressedGuidToGuid -CompressedGuid '2820F6C7DCD308A459CABB92E828C144' 79 | 80 | This example would output the GUID '{7C6F0282-3DCD-4A80-95AC-BB298E821C44}' 81 | .PARAMETER CompressedGuid 82 | The compressed GUID you'd like to convert. 83 | .LINK 84 | https://www.adamtheautomator.com/convert-compressed-guid-to-guid/ 85 | #> 86 | [CmdletBinding()] 87 | [OutputType([System.String])] 88 | param ( 89 | [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Mandatory)] 90 | [ValidatePattern('^[0-9a-fA-F]{32}$')] 91 | [string]$CompressedGuid 92 | ) 93 | process { 94 | $Indexes = [ordered]@{ 95 | 0 = 8; 96 | 8 = 4; 97 | 12 = 4; 98 | 16 = 2; 99 | 18 = 2; 100 | 20 = 2; 101 | 22 = 2; 102 | 24 = 2; 103 | 26 = 2; 104 | 28 = 2; 105 | 30 = 2 106 | } 107 | #$Guid = '{' 108 | $Guid = '' 109 | foreach ($index in $Indexes.GetEnumerator()) { 110 | $part = $CompressedGuid.Substring($index.Key, $index.Value).ToCharArray() 111 | [array]::Reverse($part) 112 | $Guid += $part -join '' 113 | } 114 | $Guid = $Guid.Insert(9,'-').Insert(14, '-').Insert(19, '-').Insert(24, '-') 115 | #$Guid + '}' 116 | $Guid + '' 117 | } 118 | } 119 | #====================================================================================== 120 | # Validate Admin Rights 121 | #====================================================================================== 122 | Write-Host "" 123 | # Verify Running as Admin 124 | $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 125 | If (!( $isAdmin )) { 126 | Write-Host "Checking User Account Control settings ..." -ForegroundColor Green 127 | if ((Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System).EnableLUA -eq 0) { 128 | #UAC Disabled 129 | Write-Host '========================================================================================' -ForegroundColor DarkGray 130 | Write-Host "User Account Control is Disabled ... " -ForegroundColor Green 131 | Write-Host "You will need to correct your UAC Settings ..." -ForegroundColor Green 132 | Write-Host "Try running this script in an Elevated PowerShell session ... Exiting" -ForegroundColor Green 133 | Write-Host '========================================================================================' -ForegroundColor DarkGray 134 | Start-Sleep -s 10 135 | Exit 0 136 | } else { 137 | #UAC Enabled 138 | Write-Host "UAC is Enabled" -ForegroundColor Green 139 | Start-Sleep -s 3 140 | if ($Silent) { 141 | Write-Host "-- Restarting as Administrator (Silent)" -ForegroundColor Cyan ; Start-Sleep -Seconds 1 142 | Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`" -Silent" -Verb RunAs -Wait 143 | } elseif($Restart) { 144 | Write-Host "-- Restarting as Administrator (Restart)" -ForegroundColor Cyan ; Start-Sleep -Seconds 1 145 | Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`" -Restart" -Verb RunAs -Wait 146 | } else { 147 | Write-Host "-- Restarting as Administrator" -ForegroundColor Cyan ; Start-Sleep -Seconds 1 148 | Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs -Wait 149 | } 150 | Exit 0 151 | } 152 | } else { 153 | Write-Host '========================================================================================' -ForegroundColor DarkGray 154 | Write-Host "-- Running with Elevated Permissions ..." -ForegroundColor Cyan ; Start-Sleep -Seconds 1 155 | Write-Host '========================================================================================' -ForegroundColor DarkGray 156 | } 157 | #====================================================================================== 158 | # Script Information 159 | #====================================================================================== 160 | $Invocation = (Get-Variable MyInvocation -Scope Script).Value 161 | $ScriptPath = Split-Path -Parent $Invocation.MyCommand.Path 162 | $ParentName = Split-Path $ScriptPath -Leaf 163 | #====================================================================================== 164 | # Logs 165 | #====================================================================================== 166 | $OSDAppName = "OSDUpdate-$ParentName" 167 | $OSDLogs = "$env:Temp" 168 | if (!(Test-Path $OSDLogs)) {New-Item $OSDLogs -ItemType Directory -Force | Out-Null} 169 | $OSDLogName = "$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-$OSDAppName.log" 170 | Start-Transcript -Path (Join-Path $OSDLogs $OSDLogName) 171 | #====================================================================================== 172 | # Start Script 173 | #====================================================================================== 174 | Write-Host "Start ... $(Join-Path $PSScriptRoot $MyInvocation.MyCommand.Name)" -ForegroundColor Green 175 | Write-Host "" 176 | #====================================================================================== 177 | # OS Information 178 | #====================================================================================== 179 | $OSCaption = $((Get-WmiObject -Class Win32_OperatingSystem).Caption).Trim() 180 | $OSArchitecture = $((Get-WmiObject -Class Win32_OperatingSystem).OSArchitecture).Trim() 181 | $OSProductType = $((Get-WmiObject -Class Win32_OperatingSystem).ProductType) 182 | $OSVersion = $((Get-WmiObject -Class Win32_OperatingSystem).Version).Trim() 183 | $OSBuildNumber = $((Get-WmiObject -Class Win32_OperatingSystem).BuildNumber).Trim() 184 | Write-Host "Operating System: $OSCaption" -ForegroundColor Cyan 185 | Write-Host "OS Architecture: $OSArchitecture" -ForegroundColor Cyan 186 | Write-Host "OS ProductType: $OSProductType" -ForegroundColor Cyan 187 | Write-Host "OS Version: $OSVersion" -ForegroundColor Cyan 188 | Write-Host "OS Build Number: $OSBuildNumber" -ForegroundColor Cyan 189 | if ($OSVersion -Like "10*") { 190 | $OSReleaseID = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ReleaseId).ReleaseId 191 | 192 | if ($OSReleaseID -ge 2009) { 193 | $OSReleaseID = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name DisplayVersion).DisplayVersion 194 | } 195 | 196 | Write-Host "OS Release ID: $OSReleaseID" -ForegroundColor Cyan 197 | } 198 | #====================================================================================== 199 | # Begin 200 | #====================================================================================== 201 | Write-Host "Install-OSDUpdate Package" -ForegroundColor Green 202 | #====================================================================================== 203 | # Get OSDUpdate Package Catalog 204 | #====================================================================================== 205 | $Updates = @() 206 | $UpdateCatalogs = Get-ChildItem $PSScriptRoot "OSDUpdatePackage.xml" 207 | Try { 208 | foreach ($Catalog in $UpdateCatalogs) { 209 | $Updates += Import-Clixml -Path $Catalog.FullName 210 | } 211 | } 212 | Catch { 213 | Write-Warning -Message "Could not locate OSDUpdatePackage.xml ... Exiting" 214 | Break 215 | } 216 | #====================================================================================== 217 | # Determine Catalog 218 | #====================================================================================== 219 | $Catalog = ($Updates | Select-Object -First 1).Catalog 220 | Write-Host "OSDUpdate Catalog: $Catalog" -ForegroundColor Cyan 221 | #====================================================================================== 222 | # Catalog Office 223 | #====================================================================================== 224 | if ($Catalog -like "Office*") { 225 | #====================================================================================== 226 | # Installed Patches 227 | #====================================================================================== 228 | $PatchesInstalledRegistry = @() 229 | $PatchesInstalledRegistry = 'HKLM:\SOFTWARE\Classes\Installer\Patches' 230 | $PatchesInstalledProductCode = @() 231 | $PatchesInstalledProductCode = Get-ChildItem -Path $PatchesInstalledRegistry -EA SilentlyContinue | Select-Object -Property @{Name="ProductCode"; Expression = {$_.PSChildName}} -Unique 232 | $PatchesInstalledGuids = @() 233 | foreach ($InstalledPatch in $PatchesInstalledProductCode) { 234 | $InstalledPatchGuid = Convert-CompressedGuidToGuid -CompressedGuid "$($InstalledPatch.ProductCode)" 235 | $PatchesInstalledGuids += $InstalledPatchGuid 236 | } 237 | #====================================================================================== 238 | # Available Patches (MSP's) 239 | #====================================================================================== 240 | $PatchesAvailable = @() 241 | $PatchesAvailable = Get-ChildItem "$ScriptPath" -Recurse -File -Include *.msp | Select-Object -Property LastWriteTime,Name,Length,FullName,Directory,BaseName,Extension 242 | $PatchesAvailable = $PatchesAvailable | Sort-Object -Property @{Expression = {$_.LastWriteTime}; Ascending = $true}, Length -Descending 243 | #====================================================================================== 244 | # Get Patch XML Information 245 | #====================================================================================== 246 | foreach ($Patch in $PatchesAvailable) { 247 | $PatchXml = "$($Patch.Directory)\$($Patch.BaseName).xml" 248 | 249 | $Patch | Add-Member -MemberType NoteProperty -Name PatchGuid -value '' 250 | $Patch | Add-Member -MemberType NoteProperty -Name ProductCode -value '' 251 | $Patch | Add-Member -MemberType NoteProperty -Name TargetProductCode -value '' 252 | 253 | if (Test-Path $PatchXml) { 254 | $xml = [xml](Get-Content $PatchXml) 255 | $Patch.PatchGuid = $($xml.MsiPatch | Select PatchGuid).PatchGuid 256 | $Patch.ProductCode = Convert-GuidToCompressedGuid -Guid $($Patch.PatchGuid) 257 | $Patch.TargetProductCode = $($xml.MsiPatch.TargetProductCode) 258 | } 259 | } 260 | #====================================================================================== 261 | # Set InstallationStatus 262 | #====================================================================================== 263 | foreach ($Patch in $PatchesAvailable) { 264 | $Patch | Add-Member -MemberType NoteProperty -Name InstallStatus -value '' 265 | foreach ($PatchInstalled in $PatchesInstalledProductCode) { 266 | if ($Patch.ProductCode -eq $PatchInstalled.ProductCode) { 267 | $Patch.InstallStatus = 'Installed' 268 | } 269 | } 270 | } 271 | #====================================================================================== 272 | # Install Updates 273 | #====================================================================================== 274 | foreach ($Patch in $PatchesAvailable) { 275 | $PatchName = $($Patch.Directory) | Split-Path -Leaf 276 | 277 | if ($Patch.InstallStatus -eq 'Installed') { 278 | Write-Host "Installed: $PatchName $($Patch.Name)" -ForegroundColor DarkGray 279 | } else { 280 | Write-Host "$PatchName $($Patch.Name)" -ForegroundColor Cyan 281 | msiexec /p "$($Patch.FullName)" /qn REBOOT=ReallySuppress MSIRESTARTMANAGERCONTROL=Disable | Out-Null 282 | } 283 | } 284 | } 285 | #====================================================================================== 286 | # Catalog Windows 287 | #====================================================================================== 288 | if ($Catalog -like "Windows*") { 289 | #====================================================================================== 290 | # Sessions 291 | #====================================================================================== 292 | [xml]$SessionsXML = Get-Content -Path "$env:WinDir\Servicing\Sessions\Sessions.xml" 293 | 294 | $Sessions = $SessionsXML.SelectNodes('Sessions/Session') | ForEach-Object { 295 | New-Object -Type PSObject -Property @{ 296 | Id = $_.Tasks.Phase.package.id 297 | KBNumber = $_.Tasks.Phase.package.name 298 | TargetState = $_.Tasks.Phase.package.targetState 299 | Client = $_.Client 300 | Complete = $_.Complete 301 | Status = $_.Status 302 | } 303 | } 304 | $Sessions = $Sessions | Where-Object {$_.Id -like "Package*"} 305 | $Sessions = $Sessions | Select-Object -Property Id, KBNumber, TargetState, Client, Status, Complete | Sort-Object Complete -Descending 306 | #====================================================================================== 307 | # Sort Updates 308 | #====================================================================================== 309 | $Updates = $Updates | Sort-Object -Property CreationDate 310 | #====================================================================================== 311 | # Architecture 312 | #====================================================================================== 313 | if ($OSArchitecture -like "*64*") {$Updates = $Updates | Where-Object {$_.UpdateArch -eq 'x64'}} 314 | else {$Updates = $Updates | Where-Object {$_.UpdateArch -eq 'x86'}} 315 | #====================================================================================== 316 | # OSReleaseID 317 | #====================================================================================== 318 | if ($OSProductType -eq 1) { 319 | $Updates = $Updates | Where-Object {$_.Catalog -notlike "*Server*"} 320 | if ($OSVersion -like "6.1") {$Updates = $Updates | Where-Object {$_.Catalog -like "Windows 7*"}} 321 | } else { 322 | $Updates = $Updates | Where-Object {$_.Catalog -like "*Server*"} 323 | } 324 | if ($OSVersion -like "10.*") { 325 | $Updates = $Updates | Where-Object {$_.UpdateBuild -eq $OSReleaseID} 326 | if ($OSCaption -match '11') { 327 | $Updates = $Updates | Where-Object {$_.UpdateOS -eq 'Windows 11'} 328 | } 329 | else { 330 | $Updates = $Updates | Where-Object {$_.UpdateOS -ne 'Windows 11'} 331 | } 332 | } 333 | #====================================================================================== 334 | # Get-Hotfix 335 | #====================================================================================== 336 | $InstalledUpdates = Get-HotFix 337 | #====================================================================================== 338 | # Windows Updates 339 | #====================================================================================== 340 | Write-Host "Updating Windows" -ForegroundColor Green 341 | foreach ($Update in $Updates) { 342 | if ($Update.UpdateGroup -eq 'SSU') { 343 | $UpdatePath = "$PSScriptRoot\$($Update.Title)\$($Update.FileName)" 344 | if (Test-Path "$UpdatePath") { 345 | Write-Host "$UpdatePath" -ForegroundColor DarkGray 346 | if ($InstalledUpdates | Where-Object HotFixID -like "*$($Update.KBNumber)") { 347 | Write-Host "KB$($Update.KBNumber) is already installed" -ForegroundColor Cyan 348 | } else { 349 | Write-Host "Installing $($Update.Title) ..." -ForegroundColor Cyan 350 | Dism /Online /Add-Package /PackagePath:"$UpdatePath" /NoRestart 351 | } 352 | } else { 353 | Write-Warning "Not Found: $UpdatePath" 354 | } 355 | } 356 | } 357 | foreach ($Update in $Updates) { 358 | if ($Update.UpdateGroup -ne 'SSU') { 359 | $UpdatePath = "$PSScriptRoot\$($Update.Title)\$($Update.FileName)" 360 | if (Test-Path "$UpdatePath") { 361 | Write-Host "$UpdatePath" -ForegroundColor DarkGray 362 | if ($InstalledUpdates | Where-Object HotFixID -like "*$($Update.KBNumber)") { 363 | Write-Host "KB$($Update.KBNumber) is already installed" -ForegroundColor Cyan 364 | } else { 365 | Write-Host "Installing $($Update.Title) ..." -ForegroundColor Cyan 366 | Dism /Online /Add-Package /PackagePath:"$UpdatePath" /NoRestart 367 | } 368 | } else { 369 | #Write-Warning "Not Found: $UpdatePath" 370 | } 371 | } 372 | } 373 | } 374 | #====================================================================================== 375 | # Complete 376 | #====================================================================================== 377 | Write-Host "" 378 | Write-Host "Complete ... $(Join-Path $PSScriptRoot $MyInvocation.MyCommand.Name)" -ForegroundColor Green 379 | Stop-Transcript 380 | Start-Sleep 5 -------------------------------------------------------------------------------- /Scripts/Install-OSDUpdatePackageOffice.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 5 2 | 3 | <# 4 | .SYNOPSIS 5 | Standalone script for applying Legacy Office Updates 6 | 7 | .DESCRIPTION 8 | Standalone script for applying Legacy Office Updates 9 | 10 | .NOTES 11 | Author: David Segura 12 | Website: osdeploy.com 13 | Twitter: @SeguraOSD 14 | Version: 19.6.25.0 15 | #> 16 | function Convert-GuidToCompressedGuid { 17 | <# 18 | .SYNOPSIS 19 | This converts a GUID to a compressed GUID also known as a product code. 20 | .DESCRIPTION 21 | This function will typically be used to figure out the product code 22 | that matches up with the product code stored in the 'SOFTWARE\Classes\Installer\Products' 23 | registry path to a MSI installer GUID. 24 | .EXAMPLE 25 | Convert-GuidToCompressedGuid -Guid '{7C6F0282-3DCD-4A80-95AC-BB298E821C44}' 26 | 27 | This example would output the compressed GUID '2820F6C7DCD308A459CABB92E828C144' 28 | .PARAMETER Guid 29 | The GUID you'd like to convert. 30 | .LINK 31 | https://www.adamtheautomator.com/compressed-guid-with-powershell/ 32 | #> 33 | [CmdletBinding()] 34 | [OutputType()] 35 | param ( 36 | [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Mandatory)] 37 | [string]$Guid 38 | ) 39 | begin { 40 | $Guid = $Guid.Replace('-', '').Replace('{', '').Replace('}', '') 41 | } 42 | process { 43 | try { 44 | $Groups = @( 45 | $Guid.Substring(0, 8).ToCharArray(), 46 | $Guid.Substring(8, 4).ToCharArray(), 47 | $Guid.Substring(12, 4).ToCharArray(), 48 | $Guid.Substring(16, 16).ToCharArray() 49 | ) 50 | $Groups[0..2] | foreach { 51 | [array]::Reverse($_) 52 | } 53 | $CompressedGuid = ($Groups[0..2] | foreach { $_ -join '' }) -join '' 54 | 55 | $chararr = $Groups[3] 56 | for ($i = 0; $i -lt $chararr.count; $i++) { 57 | if (($i % 2) -eq 0) { 58 | $CompressedGuid += ($chararr[$i+1] + $chararr[$i]) -join '' 59 | } 60 | } 61 | $CompressedGuid 62 | } catch { 63 | Write-Error $_.Exception.Message 64 | } 65 | } 66 | } 67 | 68 | function Convert-CompressedGuidToGuid { 69 | <# 70 | .SYNOPSIS 71 | This converts a compressed GUID also known as a product code into a GUID. 72 | .DESCRIPTION 73 | This function will typically be used to figure out the MSI installer GUID 74 | that matches up with the product code stored in the 'SOFTWARE\Classes\Installer\Products' 75 | registry path. 76 | .EXAMPLE 77 | Convert-CompressedGuidToGuid -CompressedGuid '2820F6C7DCD308A459CABB92E828C144' 78 | 79 | This example would output the GUID '{7C6F0282-3DCD-4A80-95AC-BB298E821C44}' 80 | .PARAMETER CompressedGuid 81 | The compressed GUID you'd like to convert. 82 | .LINK 83 | https://www.adamtheautomator.com/convert-compressed-guid-to-guid/ 84 | #> 85 | [CmdletBinding()] 86 | [OutputType([System.String])] 87 | param ( 88 | [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Mandatory)] 89 | [ValidatePattern('^[0-9a-fA-F]{32}$')] 90 | [string]$CompressedGuid 91 | ) 92 | process { 93 | $Indexes = [ordered]@{ 94 | 0 = 8; 95 | 8 = 4; 96 | 12 = 4; 97 | 16 = 2; 98 | 18 = 2; 99 | 20 = 2; 100 | 22 = 2; 101 | 24 = 2; 102 | 26 = 2; 103 | 28 = 2; 104 | 30 = 2 105 | } 106 | #$Guid = '{' 107 | $Guid = '' 108 | foreach ($index in $Indexes.GetEnumerator()) { 109 | $part = $CompressedGuid.Substring($index.Key, $index.Value).ToCharArray() 110 | [array]::Reverse($part) 111 | $Guid += $part -join '' 112 | } 113 | $Guid = $Guid.Insert(9,'-').Insert(14, '-').Insert(19, '-').Insert(24, '-') 114 | #$Guid + '}' 115 | $Guid + '' 116 | } 117 | } 118 | #====================================================================================== 119 | # Begin 120 | #====================================================================================== 121 | Write-Host "OSDUpdate Microsoft Office" -ForegroundColor Green 122 | #====================================================================================== 123 | # Current Path 124 | #====================================================================================== 125 | $Invocation = (Get-Variable MyInvocation -Scope Script).Value 126 | $ScriptPath = Split-Path -Parent $Invocation.MyCommand.Path 127 | #====================================================================================== 128 | # Installed Patches 129 | #====================================================================================== 130 | $PatchesInstalledRegistry = @() 131 | $PatchesInstalledRegistry = 'HKLM:\SOFTWARE\Classes\Installer\Patches' 132 | $PatchesInstalledProductCode = @() 133 | $PatchesInstalledProductCode = Get-ChildItem -Path $PatchesInstalledRegistry -EA SilentlyContinue | Select-Object -Property @{Name="ProductCode"; Expression = {$_.PSChildName}} -Unique 134 | $PatchesInstalledGuids = @() 135 | foreach ($InstalledPatch in $PatchesInstalledProductCode) { 136 | $InstalledPatchGuid = Convert-CompressedGuidToGuid -CompressedGuid "$($InstalledPatch.ProductCode)" 137 | $PatchesInstalledGuids += $InstalledPatchGuid 138 | } 139 | #====================================================================================== 140 | # Available Patches (MSP's) 141 | #====================================================================================== 142 | $PatchesAvailable = @() 143 | $PatchesAvailable = Get-ChildItem "$ScriptPath" -Recurse -File -Include *.msp | Select-Object -Property LastWriteTime,Name,Length,FullName,Directory,BaseName,Extension 144 | $PatchesAvailable = $PatchesAvailable | Sort-Object -Property @{Expression = {$_.LastWriteTime}; Ascending = $true}, Length -Descending 145 | #====================================================================================== 146 | # Get Patch XML Information 147 | #====================================================================================== 148 | foreach ($Patch in $PatchesAvailable) { 149 | $PatchXml = "$($Patch.Directory)\$($Patch.BaseName).xml" 150 | 151 | $Patch | Add-Member -MemberType NoteProperty -Name PatchGuid -value '' 152 | $Patch | Add-Member -MemberType NoteProperty -Name ProductCode -value '' 153 | $Patch | Add-Member -MemberType NoteProperty -Name TargetProductCode -value '' 154 | 155 | if (Test-Path $PatchXml) { 156 | $xml = [xml](Get-Content $PatchXml) 157 | $Patch.PatchGuid = $($xml.MsiPatch | Select PatchGuid).PatchGuid 158 | $Patch.ProductCode = Convert-GuidToCompressedGuid -Guid $($Patch.PatchGuid) 159 | $Patch.TargetProductCode = $($xml.MsiPatch.TargetProductCode) 160 | } 161 | } 162 | #====================================================================================== 163 | # Set InstallationStatus 164 | #====================================================================================== 165 | foreach ($Patch in $PatchesAvailable) { 166 | $Patch | Add-Member -MemberType NoteProperty -Name InstallStatus -value '' 167 | foreach ($PatchInstalled in $PatchesInstalledProductCode) { 168 | if ($Patch.ProductCode -eq $PatchInstalled.ProductCode) { 169 | $Patch.InstallStatus = 'Installed' 170 | } 171 | } 172 | } 173 | #====================================================================================== 174 | # Install Updates 175 | #====================================================================================== 176 | foreach ($Patch in $PatchesAvailable) { 177 | $PatchName = $($Patch.Directory) | Split-Path -Leaf 178 | 179 | if ($Patch.InstallStatus -eq 'Installed') { 180 | Write-Host "Installed: $PatchName $($Patch.Name)" -ForegroundColor DarkGray 181 | } else { 182 | Write-Host "$PatchName $($Patch.Name)" -ForegroundColor Cyan 183 | msiexec /p "$($Patch.FullName)" /qn REBOOT=ReallySuppress MSIRESTARTMANAGERCONTROL=Disable | Out-Null 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /Scripts/Install-OSDUpdatePackageWindows.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 5 2 | 3 | <# 4 | .SYNOPSIS 5 | Standalone script for applying Legacy Office Updates 6 | 7 | .DESCRIPTION 8 | Standalone script for applying Legacy Office Updates 9 | 10 | .NOTES 11 | Author: David Segura 12 | Website: osdeploy.com 13 | Twitter: @SeguraOSD 14 | Version: 19.6.25.0 15 | #> 16 | 17 | #====================================================================================== 18 | # Begin 19 | #====================================================================================== 20 | Write-Host "OSDUpdate Microsoft Windows" -ForegroundColor Green 21 | #====================================================================================== 22 | # OS Information 23 | #====================================================================================== 24 | $OSCaption = $((Get-WmiObject -Class Win32_OperatingSystem).Caption).Trim() 25 | $OSArchitecture = $((Get-WmiObject -Class Win32_OperatingSystem).OSArchitecture).Trim() 26 | $OSVersion = $((Get-WmiObject -Class Win32_OperatingSystem).Version).Trim() 27 | $OSBuildNumber = $((Get-WmiObject -Class Win32_OperatingSystem).BuildNumber).Trim() 28 | Write-Host "Operating System: $OSCaption" -ForegroundColor Cyan 29 | Write-Host "OS Architecture: $OSArchitecture" -ForegroundColor Cyan 30 | Write-Host "OS Version: $OSVersion" -ForegroundColor Cyan 31 | Write-Host "OS Build Number: $OSBuildNumber" -ForegroundColor Cyan 32 | if ($OSCaption -Like "*Windows 10*") { 33 | $OSReleaseID = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ReleaseId).ReleaseId 34 | Write-Host "OS Release ID: $OSReleaseID" -ForegroundColor Cyan 35 | } 36 | #====================================================================================== 37 | # Updates 38 | #====================================================================================== 39 | $Updates = @() 40 | $UpdateCatalogs = Get-ChildItem $PSScriptRoot "OSDUpdateWindows*.xml" 41 | Try { 42 | foreach ($Catalog in $UpdateCatalogs) { 43 | $Updates += Import-Clixml -Path $Catalog.FullName 44 | } 45 | } 46 | Catch {} 47 | #====================================================================================== 48 | # Sessions 49 | #====================================================================================== 50 | [xml]$SessionsXML = Get-Content -Path "$env:WinDir\Servicing\Sessions\Sessions.xml" 51 | 52 | $Sessions = $SessionsXML.SelectNodes('Sessions/Session') | ForEach-Object { 53 | New-Object -Type PSObject -Property @{ 54 | Id = $_.Tasks.Phase.package.id 55 | KBNumber = $_.Tasks.Phase.package.name 56 | TargetState = $_.Tasks.Phase.package.targetState 57 | Client = $_.Client 58 | Complete = $_.Complete 59 | Status = $_.Status 60 | } 61 | } 62 | $Sessions = $Sessions | Where-Object {$_.Id -like "Package*"} 63 | $Sessions = $Sessions | Select-Object -Property Id, KBNumber, TargetState, Client, Status, Complete | Sort-Object Complete -Descending 64 | #====================================================================================== 65 | # Architecture 66 | #====================================================================================== 67 | if ($OSArchitecture -like "*64*") {$Updates = $Updates | Where-Object {$_.UpdateArch -eq 'x64'}} 68 | else {$Updates = $Updates | Where-Object {$_.UpdateArch -eq 'x86'}} 69 | #====================================================================================== 70 | # Operating System 71 | #====================================================================================== 72 | IF ($OSVersion -like "10.*") {$Updates = $Updates | Where-Object {$_.UpdateBuild -eq $OSReleaseID}} 73 | #====================================================================================== 74 | # Get-Hotfix 75 | #====================================================================================== 76 | $InstalledUpdates = Get-HotFix 77 | #====================================================================================== 78 | # Windows Updates 79 | #====================================================================================== 80 | Write-Host "Updating Windows" -ForegroundColor Green 81 | foreach ($Update in $Updates) { 82 | if ($Update.UpdateGroup -eq 'SSU') { 83 | $UpdatePath = "$PSScriptRoot\$($Update.Title)\$($Update.FileName)" 84 | if (Test-Path "$UpdatePath") { 85 | Write-Host "$UpdatePath" -ForegroundColor DarkGray 86 | if ($InstalledUpdates | Where-Object HotFixID -like "*$($Update.KBNumber)") { 87 | Write-Host "KB$($Update.KBNumber) is already installed" -ForegroundColor Cyan 88 | } else { 89 | Write-Host "Installing $($Update.Title) ..." -ForegroundColor Cyan 90 | Dism /Online /Add-Package /PackagePath:"$UpdatePath" /NoRestart 91 | } 92 | } else { 93 | Write-Warning "Not Found: $UpdatePath" 94 | } 95 | } 96 | } 97 | foreach ($Update in $Updates) { 98 | if ($Update.UpdateGroup -ne 'SSU') { 99 | $UpdatePath = "$PSScriptRoot\$($Update.Title)\$($Update.FileName)" 100 | if (Test-Path "$UpdatePath") { 101 | Write-Host "$UpdatePath" -ForegroundColor DarkGray 102 | if ($InstalledUpdates | Where-Object HotFixID -like "*$($Update.KBNumber)") { 103 | Write-Host "KB$($Update.KBNumber) is already installed" -ForegroundColor Cyan 104 | } else { 105 | Write-Host "Installing $($Update.Title) ..." -ForegroundColor Cyan 106 | Dism /Online /Add-Package /PackagePath:"$UpdatePath" /NoRestart 107 | } 108 | } else { 109 | Write-Warning "Not Found: $UpdatePath" 110 | } 111 | } 112 | } 113 | #====================================================================================== 114 | # Complete 115 | #====================================================================================== -------------------------------------------------------------------------------- /Scripts/Install-OSDUpdatePackages.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 5 2 | 3 | <# 4 | .SYNOPSIS 5 | Installs Updates in an OSDUpdate Package from Child Directories 6 | 7 | .DESCRIPTION 8 | Installs Updates in an OSDUpdate Package from Child Directories 9 | 10 | .NOTES 11 | Author: David Segura 12 | Website: osdeploy.com 13 | Twitter: @SeguraOSD 14 | Version: 19.6.25.0 15 | #> 16 | #====================================================================================== 17 | # Validate Admin Rights 18 | #====================================================================================== 19 | $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 20 | If (!( $isAdmin )) { 21 | Write-Host "Checking User Account Control settings ..." -ForegroundColor Green 22 | if ((Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System).EnableLUA -eq 0) { 23 | #UAC Disabled 24 | Write-Host '========================================================================================' -ForegroundColor DarkGray 25 | Write-Host "User Account Control is Disabled ... " -ForegroundColor Green 26 | Write-Host "You will need to correct your UAC Settings ..." -ForegroundColor Green 27 | Write-Host "Try running this script in an Elevated PowerShell session ... Exiting" -ForegroundColor Green 28 | Write-Host '========================================================================================' -ForegroundColor DarkGray 29 | Start-Sleep -s 10 30 | Exit 0 31 | } else { 32 | #UAC Enabled 33 | Write-Host "UAC is Enabled" -ForegroundColor Green 34 | Start-Sleep -s 3 35 | if ($Silent) { 36 | Write-Host "-- Restarting as Administrator (Silent)" -ForegroundColor Cyan ; Start-Sleep -Seconds 1 37 | Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`" -Silent" -Verb RunAs -Wait 38 | } elseif($Restart) { 39 | Write-Host "-- Restarting as Administrator (Restart)" -ForegroundColor Cyan ; Start-Sleep -Seconds 1 40 | Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`" -Restart" -Verb RunAs -Wait 41 | } else { 42 | Write-Host "-- Restarting as Administrator" -ForegroundColor Cyan ; Start-Sleep -Seconds 1 43 | Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs -Wait 44 | } 45 | Exit 0 46 | } 47 | } else { 48 | Write-Host '========================================================================================' -ForegroundColor DarkGray 49 | Write-Host "-- Running with Elevated Permissions ..." -ForegroundColor Cyan ; Start-Sleep -Seconds 1 50 | Write-Host '========================================================================================' -ForegroundColor DarkGray 51 | } 52 | #====================================================================================== 53 | # Start Transcript 54 | #====================================================================================== 55 | Start-Transcript 56 | #====================================================================================== 57 | # Start Script 58 | #====================================================================================== 59 | Write-Host "$PSCommandPath" -ForegroundColor Green 60 | $OSDUpdatePath = (get-item $PSScriptRoot ).FullName 61 | Write-Host "OSDUpdate Path: $OSDUpdatePath" -ForegroundColor Cyan 62 | #====================================================================================== 63 | # Get Child Scripts 64 | #====================================================================================== 65 | $OSDScripts = Get-ChildItem $OSDUpdatePath Install-OSDUpdatePackage.ps1 -Recurse | Select-Object -Property * 66 | #====================================================================================== 67 | # Process Child Scripts 68 | #====================================================================================== 69 | foreach ($OSDScript in $OSDScripts) { 70 | Write-Host '========================================================================================' -ForegroundColor DarkGray 71 | Write-Host "Installing '$($OSDScript.FullName)'" -ForegroundColor Green 72 | Invoke-Expression "& '$($OSDScript.FullName)'" 73 | } 74 | #====================================================================================== 75 | # Complete 76 | #====================================================================================== 77 | Write-Host '========================================================================================' -ForegroundColor DarkGray 78 | Write-Host (Join-Path $PSScriptRoot $MyInvocation.MyCommand.Name) " Complete" -ForegroundColor Green 79 | Write-Host '========================================================================================' -ForegroundColor DarkGray 80 | Stop-Transcript 81 | Start-Sleep 5 82 | #[void](Read-Host 'Press Enter to Continue') -------------------------------------------------------------------------------- /Scripts/Update-OSDUpdatePackages.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Modules OSDUpdate 2 | #Requires -Version 5 3 | 4 | <# 5 | .SYNOPSIS 6 | Uses the OSDUpdate Module to update subdirectory OSDUpdate Packages 7 | 8 | .DESCRIPTION 9 | Uses the OSDUpdate Module to update subdirectory OSDUpdate Packages 10 | 11 | .NOTES 12 | Author: David Segura 13 | Website: osdeploy.com 14 | Twitter: @SeguraOSD 15 | Version: 20.5.28.1 16 | #> 17 | 18 | #====================================================================================== 19 | # Set Error Action to Silently Continue 20 | #====================================================================================== 21 | $ErrorActionPreference = "SilentlyContinue" 22 | 23 | #====================================================================================== 24 | # Import OSDUpdate Module 25 | #====================================================================================== 26 | Import-Module OSDUpdate -Force 27 | 28 | #====================================================================================== 29 | # Get all Package Subdirectories 30 | #====================================================================================== 31 | $Packages = Get-ChildItem $PSScriptRoot -Directory | Select-Object -Property Name 32 | 33 | #====================================================================================== 34 | # Process Package Directories 35 | # Only directories named with a proper PackageName will be updated 36 | #====================================================================================== 37 | foreach ($Package in $Packages) { 38 | Write-Host "Updating Package $($Package.Name)" -ForegroundColor Cyan 39 | New-OSDUpdatePackage -PackageName "$($Package.Name)" -PackagePath $PSScriptRoot -AppendPackageName -RemoveSuperseded 40 | } 41 | --------------------------------------------------------------------------------