├── Add-CMSystemDiscoveryMethodContainer.ps1 ├── Clear-GpoRegistrySettings.ps1 ├── Example_Report_07.27.2019.txt ├── Get-ComponentDescription.ps1 ├── Get-KBDownloadLink.ps1 ├── Get-KnownIssuesWindowsUpdates.ps1 ├── Get-MissingDeviceUpdate.ps1 ├── Get-SccmSoftwareUpdateStatus.ps1 ├── Get-UpdateHistory.ps1 ├── Get-WindowsUpdateError.ps1 ├── Get-WindowsUpdateErrorCode.ps1 ├── Install-7Zip.ps1 ├── Install-AzureCli.ps1 ├── Install-AzureStorageExplorer.ps1 ├── Install-CherryTree.ps1 ├── Install-DrawIO.ps1 ├── Install-FileZilla.ps1 ├── Install-GitForWindows.ps1 ├── Install-KeePass.ps1 ├── Install-NodeJS.ps1 ├── Install-NotepadPlusPlus.ps1 ├── Install-PowerShellCore.ps1 ├── Install-Putty.ps1 ├── Install-RemoteDesktopManager.ps1 ├── Install-SSMS.ps1 ├── Install-SccmAgent.ps1 ├── Install-Signal.ps1 ├── Install-VLC.ps1 ├── Install-VSCode.ps1 ├── Install-WinRAR.ps1 ├── Install-WinSCP.ps1 ├── Install-WinSCPNetAssembly.ps1 ├── Invoke-MissingUpdateInstallation.ps1 ├── Invoke-SccmClientAction.ps1 ├── LICENSE ├── README.md ├── Remove-CMSystemDiscoveryMethodContainer.ps1 ├── Remove-WindowsUpdate.ps1 ├── Repair-WindowsUpdate.ps1 ├── Reset-SccmAgent.ps1 └── Update-Windows.ps1 /Add-CMSystemDiscoveryMethodContainer.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 3.0 2 | Function Add-CMSystemDiscoveryMethodContainer { 3 | <# 4 | .SYNOPSIS 5 | Import Organizational Units (OU) defined by their distinguished name to an Active Directory System Discovery components in ConfigMgr 6 | 7 | 8 | .DESCRIPTION 9 | This cmdlet uses the distinguished name defined in -SearchBase to the System Discovery method on an SCCM server. Existing containers for the specified Discovery Method will be preserved. If a container is already present, it will not be added again. 10 | 11 | 12 | .PARAMETER SiteServer 13 | SCCM Site Server to connect too 14 | 15 | .PARAMETER UseSSL 16 | Creates CIM session to SCCM server using SSL (WinRM over HTTPS) 17 | 18 | .PARAMETER SkipCACheck 19 | Skip Certificate authority trust check on WinRM connnection 20 | 21 | .PARAMETER SkipCNCheck 22 | Skip verifying the CN/subject name on the WinRM certificate 23 | 24 | .PARAMETER SkipRevocationCheck 25 | Skip checking certificate revocation for WinRM connections 26 | 27 | .PARAMETER SearchBase 28 | Define the LDAP container OU path to new domains being added to System Discovery 29 | 30 | .PARAMETER RestartService 31 | Tells the SCCM server to restart the System Discovery service after adding new containers to search for 32 | 33 | .PARAMETER Credential 34 | Enter credentials to authenticate to the SCCM server 35 | 36 | 37 | .EXAMPLE 38 | Add-CMSystemDiscoveryMethodContainer -SiteServer sccm-server.domain.com -SearchBase "DC=domain,DC=com" 39 | # This example adds the domain.com LDAP search base filter to the domain System Discovery method on the sccm-server.domain.com SCCM server 40 | 41 | .EXAMPLE 42 | Add-CMSystemDiscoveryMethodContainer -SiteServer sccm-server.domain.com -UseSSL -SkipCACheck -SkipCNCheck -SkipRevocationCheck -SearchBase "LDAP:\\DC=domain,DC=com" 43 | # This example adds the domain.com LDAP search base filter to the domain System Discovery method on the sccm-server.domain.com SCCM server 44 | 45 | 46 | .NOTES 47 | Author: Robert H. Osborne 48 | Alias: tobor 49 | Contact: info@osbornerpo.com 50 | 51 | 52 | .INPUTS 53 | None 54 | 55 | 56 | .OUTPUTS 57 | None 58 | #> 59 | [CmdletBinding( 60 | SupportsShouldProcess=$True, 61 | ConfirmImpact="Medium" 62 | )] # End CmdletBinding 63 | param( 64 | [Parameter( 65 | Mandatory=$True, 66 | ValueFromPipeline=$False, 67 | HelpMessage="Site server where the SMS Provider is installed.")] # End Parameter 68 | [ValidateNotNullOrEmpty()] 69 | [String]$SiteServer, 70 | 71 | [Parameter( 72 | Mandatory=$False 73 | )] # End Parameter 74 | [Switch]$UseSSL, 75 | 76 | [Parameter( 77 | Mandatory=$False 78 | )] # End Parameter 79 | [Switch]$SkipCACheck, 80 | 81 | [Parameter( 82 | Mandatory=$False 83 | )] # End Parameter 84 | [Switch]$SkipCNCheck, 85 | 86 | [Parameter( 87 | Mandatory=$False 88 | )] # End Parameter 89 | [Switch]$SkipRevocationCheck, 90 | 91 | [Parameter( 92 | Mandatory=$True, 93 | ValueFromPipeline=$True, 94 | ValueFromPipelineByPropertyName=$False, 95 | HelpMessage="Specify the Active Directory Search Base `nEXAMPLE: DC=domain,DC=com : ")] # End Parameter 96 | [ValidateScript({$_ -like "*DC=*,DC=*"})] 97 | [String]$SearchBase, 98 | 99 | [Parameter( 100 | Mandatory=$False 101 | )] # End Parameter 102 | [Switch]$RestartService 103 | 104 | [ValidateNotNull()] 105 | [System.Management.Automation.PSCredential] 106 | [System.Management.Automation.Credential()] 107 | $Credential = [System.Management.Automation.PSCredential]::Empty 108 | ) # End param 109 | 110 | BEGIN { 111 | 112 | $ComponentName = "SMS_AD_SYSTEM_DISCOVERY_AGENT" 113 | Try { 114 | 115 | Write-Verbose -Message "Determining Site Code for Site server: '$($SiteServer)'" 116 | $CIMSession = New-CimSession -Credential $Credential -ComputerName $SiteServer -SessionOption (New-CimSessionOption -UseSSL:$UseSSL.IsPresent -SkipCACheck:$SkipCACheck.IsPresent -SkipCNCheck:$SkipCNCheck.IsPresent -SkipRevocationCheck:$SkipReovcationCheck.IsPresent -Verbose:$False) -Verbose:$False 117 | $SiteCodeObjects = Get-CimInstance -CimSession $CIMSession -Namespace "Root\SMS" -ClassName SMS_ProviderLocation -ErrorAction Stop 118 | 119 | ForEach ($SiteCodeObject in $SiteCodeObjects) { 120 | 121 | If ($SiteCodeObject.ProviderForLocalSite -eq $True) { 122 | 123 | $SiteCode = $SiteCodeObject.SiteCode 124 | Write-Verbose -Message "Site Code: $($SiteCode)" 125 | Break 126 | 127 | } # End If 128 | 129 | } # End ForEach 130 | 131 | } Catch [System.UnauthorizedAccessException] { 132 | 133 | Throw "[x] Access denied" 134 | 135 | } Catch [System.Exception] { 136 | 137 | Throw "[x] Unable to determine Site Code" 138 | 139 | } # End Try Catch Catch 140 | 141 | If ($SearchBase -notlike "LDAP://*") { 142 | 143 | $SearchBase = "LDAP://$($SearchBase)" 144 | 145 | } # End If 146 | 147 | Try { 148 | 149 | $ContainerData = New-Object -TypeName PSCustomObject -Property @{ 150 | DistinguishedName="$($SearchBase)"; 151 | Recursive="Yes"; 152 | Group="Excluded"; 153 | } # End New-Object -Property 154 | 155 | } Catch [System.Exception] { 156 | 157 | Write-Warning -Message "$($_.Exception.Message). Line: $($_.InvocationInfo.ScriptLineNumber)" 158 | Break 159 | 160 | } # End Try Catch 161 | 162 | $OptionTable = @{ 163 | Yes = 0 164 | No = 1 165 | Included = 0 166 | Excluded = 1 167 | } # End $OptionTable 168 | 169 | } PROCESS { 170 | 171 | # Determine existing containers for selected Discovery Method 172 | Try { 173 | 174 | $DiscoveryContainerList = New-Object -TypeName System.Collections.ArrayList 175 | $DiscoveryComponent = Get-WmiObject -Class SMS_SCI_Component -Namespace "Root\SMS\Site_$($SiteCode)" -ComputerName $SiteServer -Filter "ComponentName like '$($ComponentName)'" -Credential $Credential -ErrorAction Stop -Verbose:$False 176 | $DiscoveryPropListADContainer = $DiscoveryComponent.PropLists | Where-Object -FilterScript { $_.PropertyListName -like "AD Containers" } 177 | 178 | If ($DiscoveryPropListADContainer.PropertyListName -eq "AD Containers") { 179 | 180 | $DiscoveryContainerList.AddRange(@($DiscoveryPropListADContainer.Values)) | Out-Null 181 | 182 | } # End If 183 | 184 | } Catch [System.Exception] { 185 | 186 | Throw "[x] Unable to determine existing discovery method component properties" 187 | 188 | } # End Catch 189 | 190 | 191 | ForEach ($ContainerItem in $ContainerData) { 192 | 193 | If ($ContainerItem.DistinguishedName -notlike "LDAP://*") { 194 | 195 | $ContainerItem.DistinguishedName = "LDAP://$($ContainerItem.DistinguishedName)" 196 | 197 | } # End If 198 | 199 | 200 | If ($ContainerItem.DistinguishedName -notin $DiscoveryContainerList) { 201 | 202 | Write-Verbose -Message "Adding new container item $($ContainerItem.DistinguishedName)" 203 | $DiscoveryContainerList.AddRange(@($ContainerItem.DistinguishedName, $OptionTable[$ContainerItem.Recursive], $OptionTable[$ContainerItem.Group])) | Out-Null 204 | 205 | } Else { 206 | 207 | Write-Verbose -Message "Detected duplicate container object: $($ContainerItem.DistinguishedName)" 208 | 209 | } # End If Else 210 | 211 | } # End ForEach 212 | 213 | Write-Verbose -Message "Attempting to save changes made to the $($ComponentName) component PropList" 214 | Try { 215 | 216 | $DiscoveryPropListADContainer.Values = $DiscoveryContainerList 217 | $DiscoveryComponent.PropLists = $DiscoveryPropListADContainer 218 | If ($PSCmdlet.ShouldProcess($DiscoveryComponent, '$DiscoveryComponent.Put()')) { 219 | 220 | $DiscoveryComponent.Put() | Out-Null 221 | 222 | } # End If 223 | 224 | } Catch [System.Exception] { 225 | 226 | Throw "[x] Unable to save changes made to $($ComponentName) component" 227 | 228 | } # End Try Catch 229 | 230 | 231 | If ($RestartService.IsPresent) { 232 | 233 | Write-Verbose -Message "Restarting the SMS_SITE_COMPONENT_MANAGER service" 234 | Try { 235 | 236 | Write-Output -InputObject "[*] Restarting the SMS_SITE_COMPONENT_MANAGER service on $SiteServer" 237 | Get-CimInstance -CimSession $CIMSession -ClassName Win32_Service -Filter 'Name = "SMS_SITE_COMPONENT_MANAGER"' -Verbose:$False | Invoke-CimMethod -MethodName StopService -WhatIf:$False -Verbose:$False | Out-Null 238 | Get-CimInstance -CimSession $CIMSession -ClassName Win32_Service -Filter 'Name = "SMS_SITE_COMPONENT_MANAGER"' -Verbose:$False | Invoke-CimMethod -MethodName StartService -WhatIf:$False -Verbose:$False | Out-Null 239 | 240 | } Catch [System.Exception] { 241 | 242 | Write-Warning -Message "$($_.Exception.Message). Line: $($_.InvocationInfo.ScriptLineNumber)" 243 | Break 244 | 245 | } # End Try Catch 246 | 247 | } # End If 248 | 249 | } END { 250 | 251 | If ($CIMSession) { 252 | 253 | Remove-CimSession -CimSession $CIMSession -Confirm:$False -WhatIf:$False -Verbose:$False 254 | 255 | } # End If 256 | 257 | } # End END 258 | 259 | } # End Function Add-CMSystemDiscoveryMethodContainer 260 | -------------------------------------------------------------------------------- /Clear-GpoRegistrySettings.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This cmdlet is used to rebuild the registry.pol machine group policy settings 4 | 5 | 6 | .DESCRIPTION 7 | Rename the registry.pol file to rebuild a local machines group policy settings 8 | 9 | 10 | .PARAMETER NewName 11 | Define a location to save the backup of the registry.pol file using this value 12 | 13 | .PARAMETER SkipGpUpdate 14 | Tell the cmdlet to not execute a gpupdate after renaming the registry.pol machine group policy file 15 | 16 | 17 | .EXAMPLE 18 | Clear-GpoRegistrySettings 19 | # This example renames C:\Windows\System32\GroupPolicy\Machine\Registry.pol to C:\Windows\System32\GroupPolicy\Machine\Registry.old and runs a gpupdate 20 | 21 | .EXAMPLE 22 | Clear-GpoRegistrySettings -NewName C:\Windows\System32\GroupPolicy\Machine\Registry.old 23 | # This example renames C:\Windows\System32\GroupPolicy\Machine\Registry.pol to C:\Windows\System32\GroupPolicy\Machine\Registry.old and runs a gpupdate 24 | 25 | .EXAMPLE 26 | Clear-GpoRegistrySettings -SkipGpUpdate 27 | # This example renames C:\Windows\System32\GroupPolicy\Machine\Registry.pol to C:\Windows\System32\GroupPolicy\Machine\Registry.old and does not run a gpupdate 28 | 29 | 30 | .NOTES 31 | Author: Robert H. Osborne 32 | Alias: tobor 33 | Contact: rosborne@osbornepro.com 34 | 35 | 36 | .INPUTS 37 | None 38 | 39 | 40 | .OUTPUTS 41 | None 42 | 43 | 44 | .LINK 45 | https://osbornepro.com 46 | https://btpssecpack.osbornepro.com 47 | https://writeups.osbornepro.com 48 | https://github.com/OsbornePro 49 | https://github.com/tobor88 50 | https://www.powershellgallery.com/profiles/tobor 51 | https://www.hackthebox.eu/profile/52286 52 | https://www.linkedin.com/in/roberthosborne/ 53 | https://www.credly.com/users/roberthosborne/badges 54 | #> 55 | Function Clear-GpoRegistrySettings { 56 | [CmdletBinding(SupportsShouldProcess)] 57 | param( 58 | [Parameter( 59 | Position=0, 60 | Mandatory=$False, 61 | ValueFromPipeline=$False)] # End Parameter 62 | [String]$NewName = "C:\Windows\System32\GroupPolicy\Machine\Registry.old", 63 | 64 | [Parameter( 65 | Mandatory=$False)] # End Parameter 66 | [Switch][Bool]$SkipGpUpdate 67 | ) # End param 68 | 69 | $RegPolPath = "C:\Windows\System32\GroupPolicy\Machine\Registry.pol" 70 | If (Test-Path -Path $RegPolPath -ErrorAction SilentlyContinue) { 71 | 72 | If ($PSCmdlet.ShouldProcess($NewName)) { 73 | 74 | Write-Output "[*] $RegPolPath file verified to exist, renaming file" 75 | Move-Item -Path $RegPolPath -Destination $NewName -Force -Confirm:$False -PassThru -ErrorVariable $MoveFailed 76 | 77 | If ($MoveFailed) { 78 | 79 | Write-Ouput "[x] Failed to rename Registry.pol file to $NewName" 80 | 81 | } # End If 82 | 83 | If (Test-ComputerSecureChannel) { 84 | 85 | If (!($SkipGpUpdate.IsPresent)) { 86 | 87 | Write-Output "[*] Performing group policy update" 88 | gpupdate /force 89 | 90 | } # End If 91 | 92 | } Else { 93 | 94 | Throw "[x] $env:COMPUTERNAME : Domain trust failed, group policy update can not be performed" 95 | 96 | } # End If Else 97 | 98 | 99 | } Else { 100 | 101 | # Rename $RegPolPath to $NewName and performs a group policy update 102 | Move-Item -Path $RegPolPath -Destination $NewName -Force -Confirm:$False -PassThru -WhatIf 103 | 104 | } # End If Else 105 | 106 | } Else { 107 | 108 | Write-Error "[x] $RegPolPath file does NOT exist!" 109 | 110 | } # End If Else 111 | 112 | } # End Function Clear-GpoRegistrySettings 113 | -------------------------------------------------------------------------------- /Example_Report_07.27.2019.txt: -------------------------------------------------------------------------------- 1 | #===================================================================# 2 | # Update Report # 3 | #===================================================================# 4 | 5 | Computer Hostname : DESKTOP 6 | 7 | Creation Date : 07/27/2019 22:24:00 8 | 9 | Report Directory : C:\Windows\Temp\DESKTOP 10 | 11 | --------------------------------------------------------------------- 12 | AVAILABLE UPDATES 13 | --------------------------------------------------------------------- 14 | 15 | 1.) Microsoft Silverlight (KB4481252) 16 | 2.) Definition Update for Windows Defender Antivirus - KB2267602 (Definition 1.299.668.0) 17 | 18 | --------------------------------------------------------------------- 19 | INITIALISING UPDATE DOWNLOADS 20 | --------------------------------------------------------------------- 21 | 22 | 1.) Downloading Update: Microsoft Silverlight (KB4481252) 23 | 24 | Download Status: FAILED With Error 25 | Cannot create a file when that file already exists 26 | 27 | 28 | 2.) Downloading Update: Definition Update for Windows Defender Antivirus - KB2267602 (Definition 1.299.668.0) 29 | 30 | Download Status: FAILED With Error 31 | A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond 207.46.163.74:25 32 | 33 | 34 | --------------------------------------------------------------------- 35 | UPDATE INSTALLATION 36 | --------------------------------------------------------------------- 37 | 38 | 1.) Installing Update: Microsoft Silverlight (KB4481252) 39 | 40 | - Update Installation Status: SUCCESS 41 | 42 | 2.) Installing Update: Definition Update for Windows Defender Antivirus - KB2267602 (Definition 1.299.668.0) 43 | 44 | - Update Installation Status: SUCCESS 45 | 46 | #===================================================================# 47 | # END OF REPORT # 48 | #===================================================================# 49 | -------------------------------------------------------------------------------- /Get-KBDownloadLink.ps1: -------------------------------------------------------------------------------- 1 | Function Get-KBDownloadLink { 2 | <# 3 | .SYNOPSIS 4 | This cmdlet is used to retrieve from the Microsoft Update Catalog, a download link for the Article ID KB number you specify 5 | 6 | 7 | .DESCRIPTION 8 | Retrieves the KB Download link from the Microsoft Update Catalog 9 | 10 | 11 | .PARAMETER ArticleID 12 | Defines the KB identification number you want to retrieve a download link for 13 | 14 | .PARAMETER OperatingSystem 15 | Define the Operating System you want a link for 16 | 17 | .PARAMETER Architecture 18 | Define the architecture of the system you are going to install the update on. Default value is x64 19 | 20 | .PARAMETER VersionInfo 21 | Define the version of Windows 10 or 11 being used 22 | 23 | 24 | .EXAMPLE 25 | Get-KBDownloadLink -ArticleId KB5014692 26 | # This obtains the download link for KB5014692 for the OS version and arhcitecture of the machine this command is executed on 27 | 28 | .EXAMPLE 29 | Get-KBDownloadLink -ArticleId KB5014692 -Architecture "x64" -OperatingSystem 'Windows Server 2019' 30 | # This obtains the download link for KB5014692 for a 64-bit architecture Windows Server 2019 machine 31 | 32 | .EXAMPLE 33 | Get-KBDownloadLink -ArticleId KB5014692 -Architecture "x64" -OperatingSystem 'Windows 10' -VersionInfo '21H1' 34 | # This obtains the download link for KB5014692 for a 64-bit architecture Windows 10 Enterprise version 21H1 machine 35 | 36 | 37 | .INPUTS 38 | None 39 | 40 | 41 | .OUTPUTS 42 | System.String[] 43 | 44 | 45 | .NOTES 46 | Author: Robrt H. Osborne 47 | Alias: tobor 48 | Contact: rosborne@osbornepro.com 49 | 50 | 51 | .LINK 52 | https://github.com/tobor88 53 | https://github.com/osbornepro 54 | https://www.powershellgallery.com/profiles/tobor 55 | https://osbornepro.com 56 | https://writeups.osbornepro.com 57 | https://encrypit.osbornepro.com 58 | https://btpssecpack.osbornepro.com 59 | https://www.powershellgallery.com/profiles/tobor 60 | https://www.hackthebox.eu/profile/52286 61 | https://www.linkedin.com/in/roberthosborne/ 62 | https://www.credly.com/users/roberthosborne/badges 63 | #> 64 | [CmdletBinding(DefaultParameterSetName="Server")] 65 | param( 66 | [Parameter( 67 | Position=0, 68 | Mandatory=$True, 69 | ValueFromPipeline=$False, 70 | HelpMessage="Enter the KB number `nEXAMPLE: KB5014692 `nEXAMPLE: 5014692 " 71 | )] # End Parameter 72 | [Alias("Id","Article","KB")] 73 | [String]$ArticleId, 74 | 75 | [Parameter( 76 | Position=1, 77 | Mandatory=$False, 78 | ValueFromPipeline=$False 79 | )] # End Parameter 80 | [ValidateSet("Windows Server 2012 R2", "Windows Server 2016", "Windows Server 2019", "Windows Server 2022", "Windows 10", "Windows 11","SQL Server 2014","SQL Server 2016","SQL Server 2017","SQL Server 2019")] 81 | [String]$OperatingSystem = "$((Get-CimInstance -ClassName Win32_OperatingSystem).Caption.Replace('Microsoft ','').Replace(' Pro','').Replace(' Standard ','').Replace(' Datacenter ',''))", 82 | 83 | [Parameter( 84 | Position=2, 85 | Mandatory=$False, 86 | ValueFromPipeline=$False 87 | )] # End Parameter 88 | [ValidateSet("x64", "x86", "ARM")] 89 | [String]$Architecture, 90 | 91 | [Parameter( 92 | ParameterSetName="Windows10", 93 | Position=3, 94 | Mandatory=$False, 95 | ValueFromPipeline=$False 96 | )] # End Parameter 97 | [Alias('Windows10Version','Windows11Version')] 98 | [String]$VersionInfo 99 | ) # End param 100 | 101 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]'Tls12,Tls13' 102 | $DownloadLink = @() 103 | $UpdateIdResponse = Invoke-WebRequest -Uri "https://www.catalog.update.microsoft.com/Search.aspx?q=$ArticleId" -Method GET -UserAgent 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0' -ContentType 'text/html; charset=utf-8' -UseBasicParsing 104 | $DownloadOptions = ($UpdateIdResponse.Links | Where-Object -Property ID -like "*_link") 105 | 106 | If (!($PSBoundParameters.ContainsKey('Architecture') -and $OperatingSystem -notlike "*SQL*")) { 107 | 108 | $Architecture = "x$((Get-CimInstance -ClassName Win32_OperatingSystem).OSArchitecture.Replace('-bit',''))" 109 | 110 | } # End If 111 | 112 | If ($PSCmdlet.ParameterSetName -eq "Windows10" -and $OperatingSystem -notlike "*SQL*") { 113 | 114 | If (!($PSBoundParameters.ContainsKey('VersionInfo') -and $OperatingSystem -notlike "*SQL*")) { 115 | 116 | $VersionInfo = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name DisplayVersion).DisplayVersion 117 | 118 | } # End If 119 | 120 | Write-verbose -Message "$OperatingSystem link being discovered" 121 | $DownloadOptions = $DownloadOptions | Where-Object -FilterScript { $_.OuterHTML -like "*$($OperatingSystem)*" -and $_.OuterHTML -notlike "*Dynamic*" } 122 | If ($PSBoundParameters.Contains('Architecture')) { 123 | 124 | $DownloadOptions = $DownloadOptions | Where-Object -FilterScript { $_.OuterHTML -like "*$($Architecture)*" } 125 | 126 | } # End If 127 | 128 | } Else { 129 | 130 | Write-verbose -Message "$OperatingSystem link being discovered" 131 | $DownloadOptions = $DownloadOptions | Where-Object -FilterScript { $_.OuterHTML -like "*$($OperatingSystem)*" -and $_.OuterHTML -notlike "*Dynamic*" } 132 | If ($PSBoundParameters.ContainsKey('Architecture') -and $OperatingSystem -notlike "*SQL*") { 133 | 134 | $DownloadOptions = $DownloadOptions | Where-Object -FilterScript { $_.OuterHTML -like "*$($Architecture)*" } 135 | 136 | } # End If 137 | 138 | } # End If Else 139 | 140 | If ($Null -eq $DownloadOptions) { 141 | 142 | Throw "[x] No results were returned using the specified options $OperatingSystem and $Architecture" 143 | 144 | } # End If 145 | 146 | ForEach ($DownloadOption in $DownloadOptions) { 147 | 148 | $Guid = $DownloadOption.id.Replace("_link","") 149 | Write-Verbose -Message "Downloading information for $($ArticleID) $($Guid)" 150 | $Body = @{ UpdateIDs = "[$(@{ Size = 0; UpdateID = $Guid; UidInfo = $Guid } | ConvertTo-Json -Compress)]" } 151 | $LinksResponse = (Invoke-WebRequest -Uri 'https://catalog.update.microsoft.com/DownloadDialog.aspx' -Method POST -Body $Body -UseBasicParsing -SessionVariable WebSession).Content 152 | $DownloadLink += ($LinksResponse.Split("$([Environment]::NewLine)") | Select-String -Pattern 'downloadInformation' | Select-String -Pattern 'url' | Out-String).Trim() 153 | If ($PSBoundParameters.ContainsKey('Architecture') -and $OperatingSystem -like "*SQL*") { 154 | 155 | $DownloadLink = ($DownloadLink | ForEach-Object { $_.Split("$([System.Environment]::NewLine)") } | Where-Object -FilterScript { $_ -like "*$Architecture*" }).Trim().Split("'")[-2] 156 | 157 | } ElseIf ($OperatingSystem -like "*SQL*") { 158 | 159 | $DownloadLink = ($DownloadLink | ForEach-Object { $_.Split("'") } | Where-Object -FilterScript { $_ -like "https://*" }).Split("$([System.Environment]::NewLine)") 160 | 161 | } Else { 162 | 163 | $DownloadLink = ($LinksResponse.Split("$([Environment]::NewLine)") | Select-String -Pattern 'downloadInformation' | Select-String -Pattern 'url' | Out-String).Trim().Split("'")[-2] 164 | 165 | } # End If Else 166 | 167 | } # End ForEach 168 | 169 | Return $DownloadLink 170 | 171 | } # End Function Get-KBDownloadLink 172 | -------------------------------------------------------------------------------- /Get-MissingDeviceUpdate.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This cmdlet is used to retrieve a list of updates that are missing from a device 4 | 5 | 6 | .DESCRIPTION 7 | Get all missing or all SCCM approved updates that are missing from device(s) that are remote or local 8 | 9 | 10 | .PARAMETER CompuerName 11 | Define the remote device(s) you want to return missing update information on 12 | 13 | .PARAMETER UseSSL 14 | Create CIM sessions using WinRM over HTTPS 15 | 16 | .PARAMETER CompliantOnly 17 | Used to return only SCCM approved updates that are missing from a device 18 | 19 | .PARAMETER Credential 20 | Enter credentials to remotely establish connections with remote machines using WinRM CIM Sessions 21 | 22 | 23 | .EXAMPLE 24 | Get-MissingDeviceUpdate 25 | # Get all missing updates on the local device 26 | 27 | .EXAMPLE 28 | Get-MissingDeviceUpdate -CompliantOnly 29 | # Get all SCCM approved missing updates 30 | 31 | .EXAMPLE 32 | Get-MissingDeviceUpdate -ComputerName "dc01.domain.com","dhcp.domain.com","fs01.domain.com" -UseSSL -CompliantOnly -Credential $LiveCred 33 | # Get all SCCM Approved missing updates on those remote devices using WinRM over HTTPS to build your CIM sessions 34 | 35 | 36 | .INPUTS 37 | System.String, System.Array 38 | 39 | 40 | .OUTPUTS 41 | PSCustomObject 42 | 43 | 44 | .NOTES 45 | Author: Robert H. Osborne 46 | Alias: tobor 47 | Contact: rosborne@osbornepro.com 48 | 49 | 50 | .LINK 51 | https://github.com/tobor88 52 | https://github.com/OsbornePro 53 | https://www.powershellgallery.com/profiles/tobor 54 | https://osbornepro.com 55 | https://writeups.osbornepro.com 56 | https://btpssecpack.osbornepro.com 57 | https://www.powershellgallery.com/profiles/tobor 58 | https://www.hackthebox.eu/profile/52286 59 | https://www.linkedin.com/in/roberthosborne/ 60 | https://www.credly.com/users/roberthosborne/badges 61 | #> 62 | Function Get-MissingDeviceUpdate { 63 | [CmdletBinding(DefaultParameterSetName="Local")] 64 | param( 65 | [Parameter( 66 | ParameterSetName="Remote", 67 | Position=0, 68 | Mandatory=$False, 69 | ValueFromPipelineByPropertyName=$True, 70 | ValueFromPipeline=$True)] # End Parameter 71 | [String[]]$ComputerName = "$env:COMPUTERNAME.$((Get-CimInstance -ClassName Win32_ComputerSystem).Domain)", 72 | 73 | [Parameter( 74 | ParameterSetName="Remote", 75 | Mandatory=$False)] # End Parameter 76 | [Switch][Bool]$UseSSL, 77 | 78 | [Parameter( 79 | Mandatory=$False)] # End Parameter 80 | [Switch][Bool]$CompliantOnly, 81 | 82 | [ValidateNotNull()] 83 | [System.Management.Automation.PSCredential] 84 | [System.Management.Automation.Credential()] 85 | [Parameter( 86 | Mandatory=$True, 87 | ParameterSetName="Remote")] 88 | $Credential = [System.Management.Automation.PSCredential]::Empty 89 | ) # End param 90 | 91 | BEGIN { 92 | 93 | $Return = @() 94 | $NotReachable = @() 95 | 96 | $ConfirmSSL = $False 97 | If ($UseSSL.IsPresent) { 98 | 99 | $ConfirmSSL = $True 100 | 101 | } # End If 102 | 103 | } PROCESS { 104 | 105 | If ($PSCmdlet.ParameterSetName -eq "Remote") { 106 | 107 | 108 | Write-Verbose "Creating CIM Sessions to $ComputerName" 109 | $CIMSession = New-CimSession -ComputerName $ComputerName -SessionOption (New-CimSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck -UseSsl:$ConfirmSSL) -Credential $Credential -ErrorAction SilentlyContinue 110 | 111 | $CIMConnections = (Get-CimSession).ComputerName 112 | ForEach ($C in $ComputerName) { 113 | 114 | If ($C -notin $CIMConnections) { 115 | 116 | $NotReachable += $C 117 | 118 | } # End If 119 | 120 | } # End ForEach 121 | 122 | Write-Verbose "Getting all missing updates from $ComputerName" 123 | If ($CompliantOnly.IsPresent) { 124 | 125 | $CCMUpdates = Get-CimInstance -CimSession $CIMSession -NameSpace "Root\CCM\ClientSDK" -ClassName "CCM_SoftwareUpdate" -Filter "ComplianceState=0" -ErrorAction Continue 126 | 127 | } Else { 128 | 129 | $CCMUpdates = Get-CimInstance -CimSession $CIMSession -Namespace 'Root\CCM\SoftwareUpdates\UpdatesStore' -ClassName CCM_UpdateStatus -ErrorAction Continue | Where-Object -FilterScript { $_.Status -eq "Missing" } 130 | 131 | } # End If Else 132 | 133 | If ($Null -eq $CCMUpdates) { 134 | 135 | Write-Output "[*] All updates are installed on $ComputerName" 136 | 137 | } Else { 138 | 139 | If ($CompliantOnly.IsPresent) { 140 | 141 | $Return += $CCMUpdates | ForEach-Object { 142 | 143 | New-Object -TypeName PSCustomObject -Property @{ 144 | ExecutingDevice=$env:COMPUTERNAME; 145 | ComputerName=$_.PSComputerName; 146 | PercentComplete=$_.PercentComplete; 147 | ComplianceState=$_.ComplianceState; 148 | Deadline=$_.Deadline; 149 | Article=$_.ArticleID; 150 | ErrorCode=$_.ErrorCode; 151 | Update=$_.Name; 152 | } # End New-Object -Property 153 | 154 | } # End ForEach-Object 155 | 156 | } Else { 157 | 158 | $Return += $CCMUpdates | ForEach-Object { 159 | 160 | New-Object -TypeName PSCustomObject -Property @{ 161 | RunningDevice=$env:COMPUTERNAME; 162 | ComputerName=$_.PSComputerName; 163 | Status=$_.Status; 164 | Article=$_.Article; 165 | Title=$_.Title; 166 | } # End New-Object -Property 167 | 168 | } # End ForEach-Object 169 | 170 | } # End If Else 171 | 172 | } # End If Else 173 | 174 | If ($CIMSession) { 175 | 176 | Write-Verbose "Closing CIM Sessions" 177 | Remove-CimSession -CimSession $CIMSession -Confirm:$False -ErrorAction SilentlyContinue | Out-Null 178 | 179 | } # End If 180 | 181 | } Else { 182 | 183 | Write-Verbose "Getting all missing updates from $ComputerName" 184 | If ($CompliantOnly.IsPresent) { 185 | 186 | $CCMUpdates = Get-CimInstance -NameSpace "Root\CCM\ClientSDK" -ClassName "CCM_SoftwareUpdate" -Filter "ComplianceState=0" -ErrorAction Continue 187 | 188 | } Else { 189 | 190 | $CCMUpdates = Get-CimInstance -Namespace 'Root\CCM\SoftwareUpdates\UpdatesStore' -ClassName CCM_UpdateStatus -ErrorAction Continue | Where-Object -FilterScript { $_.Status -eq "Missing" } 191 | 192 | } # End If Else 193 | 194 | If ($Null -eq $CCMUpdates) { 195 | 196 | Write-Output "[*] All updates are installed on $ComputerName" 197 | 198 | } Else { 199 | 200 | If ($CompliantOnly.IsPresent) { 201 | 202 | $Return += $CCMUpdates | ForEach-Object { 203 | 204 | New-Object -TypeName PSCustomObject -Property @{ 205 | ExecutingDevice=$env:COMPUTERNAME; 206 | ComputerName=$_.PSComputerName; 207 | PercentComplete=$_.PercentComplete; 208 | ComplianceState=$_.ComplianceState; 209 | Deadline=$_.Deadline; 210 | Article=$_.ArticleID; 211 | ErrorCode=$_.ErrorCode; 212 | Update=$_.Name; 213 | } # End New-Object -Property 214 | 215 | } # End ForEach-Object 216 | 217 | } Else { 218 | 219 | $Return += $CCMUpdates | ForEach-Object { 220 | 221 | New-Object -TypeName PSCustomObject -Property @{ 222 | RunningDevice=$env:COMPUTERNAME; 223 | ComputerName=$_.PSComputerName; 224 | Status=$_.Status; 225 | Article=$_.Article; 226 | Title=$_.Title; 227 | } # End New-Object -Property 228 | 229 | } # End ForEach-Object 230 | 231 | } # End If Else 232 | 233 | } # End If Else 234 | 235 | If ($CIMSession) { 236 | 237 | Write-Verbose "Closing CIM Sessions" 238 | Remove-CimSession -CimSession $CIMSession -Confirm:$False -ErrorAction SilentlyContinue | Out-Null 239 | 240 | } # End If 241 | 242 | } # End If Else 243 | 244 | } END { 245 | 246 | If ($NotReachable) { 247 | 248 | $NotReachable | ForEach-Object { 249 | 250 | $Return += New-Object -TypeName PSCustomObject -Property @{ 251 | RunningDevice=$env:COMPUTERNAME; 252 | ComputerName=$_; 253 | Status="No CIM Session could be created"; 254 | Article="NA"; 255 | Title="NA"; 256 | } # End New-Object -Property 257 | 258 | } # End ForEach-Object 259 | 260 | } # End If 261 | 262 | If ($Null -ne $Return) { 263 | 264 | Return $Return 265 | 266 | } # End If 267 | 268 | } # End B P E 269 | 270 | } # End Function Get-MissingDeviceUpdate 271 | -------------------------------------------------------------------------------- /Get-SccmSoftwareUpdateStatus.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This cmdlet is used to return devices and their update deployment results from an SCCM server 4 | 5 | 6 | .DESCRIPTION 7 | Return information on deployment statuses for devices in an SCCM group 8 | 9 | 10 | .PARAMETER SiteCode 11 | The SCCM Site code 12 | 13 | .PARAMETER SiteServer 14 | Defines the SCCM site server FQDN or hostname 15 | 16 | .PARAMETER DeploymentID 17 | Define the deployment by its assignment ID value 18 | 19 | .PARAMETER Status 20 | Specify the results you would like to see returned. Can be Success, InProgress, Error, Unknown, or left blank 21 | 22 | .PARAMETER UseSSL 23 | Specifies the CIM session that gets created should use SSL 24 | 25 | .PARAMETER Credential 26 | Enter your credentials used to connect to the SCCM server when creating the CIM session 27 | 28 | 29 | .EXAMPLE 30 | Get-SccmSoftwareUpdateStatus -SiteCode ABC -SiteServer sccm.osbornepro.com -DeploymentId 16779910 -UseSSL -Credential (Get-Credential) 31 | # This example creates an SSL protected CIM session to an SCCM server and returns the devices with an Error Status 32 | 33 | .EXAMPLE 34 | $DeploymentResults = (Get-CMSoftwareUpdateDeployment | Where-Object -FilterScript { $_.AssignmentName -like "DEV 2022-06-14"}) | ForEach-Object { $_ | Get-CMSoftwareUpdateDeploymentStatus | Where-Object -FilterScript { $_.CollectionName -like "Patch Tuesday" } 35 | FprEach ($D in $DeploymentResults) { Get-SccmSoftwareUpdateStatus -SiteCode 123 -SiteServer sccm.osbornepro.com -UseSSL -DeploymentId $D.AssignmentId -Status Unknown -Credential (Get-Credential) } 36 | # This example gets deployment IDs from SCCM and uses them to return Unknown device status results from the deployment 37 | 38 | 39 | .INPUTS 40 | System.Int 41 | 42 | 43 | .OUTPUTS 44 | PSCustomObject 45 | 46 | 47 | .NOTES 48 | Author: Robrt H. Osborne 49 | Alias: tobor 50 | Contact: rosborne@osbornepro.com 51 | 52 | 53 | .LINK 54 | https://github.com/tobor88 55 | https://github.com/osbornepro 56 | https://www.powershellgallery.com/profiles/tobor 57 | https://osbornepro.com 58 | https://writeups.osbornepro.com 59 | https://btpssecpack.osbornepro.com 60 | https://www.powershellgallery.com/profiles/tobor 61 | https://www.hackthebox.eu/profile/52286 62 | https://www.linkedin.com/in/roberthosborne/ 63 | https://www.credly.com/users/roberthosborne/badges 64 | #> 65 | Function Get-SccmSoftwareUpdateStatus { 66 | [CmdletBinding()] 67 | param( 68 | [Parameter( 69 | Position=0, 70 | Mandatory=$True, 71 | ValueFromPipeline=$False, 72 | HelpMessage="Get you SCCM servers Site Code from your SCCM servers \Monitoring\Overview\System Status\Site Status location. EXAMPLE: ABC")] # End Parameter 73 | [String]$SiteCode, 74 | 75 | [Parameter( 76 | Position=1, 77 | Mandatory=$True, 78 | ValueFromPipeline=$False, 79 | HelpMessage="Enter the FQDN of your SCCM server. `nEXAMPLE: sscm-server01.domain.com")] # End Parameter 80 | [String]$SiteServer, 81 | 82 | [Parameter( 83 | Position=3, 84 | Mandatory=$True, 85 | ValueFromPipeline=$True, 86 | ValueFromPipelineByPropertyName=$True, 87 | HelpMessage="Define the deployment ID a.k.a Assignment ID to return results in. `,EXAMPLE: 16779910")] # End Parameter 88 | [Alias('ID', 'AssignmentID')] 89 | [Int32]$DeploymentID, 90 | 91 | [Parameter( 92 | Position=4, 93 | Mandatory=$False, 94 | ValueFromPipeline=$False)] # End Parameter 95 | [ValidateSet('Success', 'InProgress', 'Error', 'Unknown')] 96 | [String]$Status, 97 | 98 | [Parameter( 99 | Mandatory=$False)] # End Parameter 100 | [Switch][Bool]$UseSSL, 101 | 102 | [ValidateNotNull()] 103 | [System.Management.Automation.PSCredential] 104 | [System.Management.Automation.Credential()] 105 | $Credential = [System.Management.Automation.PSCredential]::Empty 106 | ) # End param 107 | 108 | BEGIN { 109 | 110 | If ((Get-PackageProvider -Name Nuget).Version -lt 2.8.5.201) { 111 | 112 | Try { 113 | 114 | Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Confirm:$False 115 | 116 | } Catch { 117 | 118 | Throw $Error 119 | 120 | } # End Try Catch 121 | 122 | } # End If 123 | 124 | $Module = "ConfigurationManager" 125 | If (!(Get-Module -ListAvailable -Name $Module)) { 126 | 127 | Install-Module -Name $Module -Force -Confirm:$False 128 | 129 | } # End If 130 | 131 | $ConfigManagerPath = (Get-Module -Name ConfigurationManager).Path 132 | If (Test-Path -Path $ConfigManagerPath) { 133 | 134 | Import-Module -Name $ConfigManagerPath 135 | Set-Location -Path "$env:SMS_ADMIN_UI_PATH\..\" 136 | New-PSDrive -Name "$($SiteCode)" -PSProvider "CMSite" -Root "$SiteServer" -Description "$SiteCode SCCM Site" | Out-Null 137 | Set-Location -Path "$($SiteCode):\" 138 | 139 | } Else { 140 | 141 | Throw "[x] ConfigurationManager PowerShell module not available on this device" 142 | 143 | } # End If Else 144 | 145 | Switch ($Status) { 146 | 147 | 'Success' { $StatusType = 1 } 148 | 'InProgress' { $StatusType = 2 } 149 | 'Unknown' { $StatusType = 4 } 150 | 'Error' { $StatusType = 5 } 151 | 152 | } # End Switch 153 | 154 | $Confirm = $False 155 | If ($UseSSL.IsPresent) { 156 | 157 | $Confirm = $True 158 | 159 | } # End If 160 | 161 | $FilterDate = Get-Date -Date $FilterDate -Format yyyy-MM-dd 162 | 163 | } PROCESS { 164 | 165 | Write-Verbose "Creating CIM session to $SiteServer" 166 | $CIMSession = New-CimSession -ComputerName $SiteServer -Credential $Credential -SessionOption (New-CimSessionOption -UseSsl:$Confirm) -ErrorAction Stop 167 | 168 | If ($Status) { 169 | 170 | $Results = Get-CimInstance -CimSession $CIMSession -ClassName SMS_SUMDeploymentAssetDetails -Namespace root\sms\site_$SiteCode -Filter "AssignmentID = $DeploymentID and StatusType = $StatusType" 171 | $Return = $Results | ForEach-Object { 172 | 173 | New-Object -TypeName PSCustomObject -Property @{ 174 | DeploymentName=$($_.AssignmentName | Select-Object -Unique); 175 | AssignmentId=$($_.AssignmentId | Select-Object -Unique); 176 | DeviceName=$($_.DeviceName); 177 | CollectionName=$($_.CollectionName); 178 | StatusTime=$(Get-Date -Date ($_.StatusTime)); 179 | Status=$(If ($_.StatusType -eq 1) {'Success'} ElseIf ($_.StatusType -eq 2) {'InProgress'} ElseIf ($_.StatusType -eq 5) {'Error'} ElseIf ($_.StatusType -eq 4) {'Unknown'}) 180 | } # End New-Object Properties 181 | 182 | } # End ForEach-Object 183 | 184 | } Else { 185 | 186 | $Results = Get-CimInstance -ComputerName $SiteServer -ClassName SMS_SUMDeploymentAssetDetail -Namespace root\sms\site_$SiteCode -Filter "AssignmentID = $DeploymentID" 187 | $Return = $Results | ForEach-Object { 188 | 189 | New-Object -TypeName PSCustomObject -Property @{ 190 | DeploymentName=$($_.AssignmentName | Select-Object -Unique); 191 | AssignmentId=$($_.AssignmentId | Select-Object -Unique); 192 | DeviceName=$_.DeviceName; 193 | CollectionName=$_.CollectionName; 194 | StatusTime=$($_.ConvertToDateTime($_.StatusTime)); 195 | Status=$(If ($_.StatusType -eq 1) {'Success'} ElseIf ($_.StatusType -eq 2) {'InProgress'} ElseIf ($_.StatusType -eq 5) {'Error'} ElseIf ($_.StatusType -eq 4) {'Unknown'}) 196 | } # End New-Object Properties 197 | 198 | } # End ForEach-Object 199 | 200 | } # End If Else 201 | 202 | If ($Null -eq $Results) { 203 | 204 | Throw "[x] Deployment ID $($DeploymentID) was not found to exist" 205 | 206 | } # End If 207 | 208 | } END { 209 | 210 | If ($Return) { 211 | 212 | Write-Verbose "Closing CIM Session Connection" 213 | Remove-CimSession -CimSession $CIMSession -Confirm:$False 214 | 215 | Return $Return 216 | 217 | } Else { 218 | 219 | Write-Output "[i] No results returned" 220 | 221 | } # End If Else 222 | 223 | } # End B P E 224 | 225 | } # End Get-SccmSoftwareUpdateStatus 226 | -------------------------------------------------------------------------------- /Get-UpdateHistory.ps1: -------------------------------------------------------------------------------- 1 | Function Get-UpdateHistory { 2 | <# 3 | .SYNOPSIS 4 | This cmdlet is used to return information on the history of Windows Updates 5 | 6 | 7 | .DESCRIPTION 8 | Return a list of installed updates on local or remote devices 9 | 10 | 11 | .PARAMETER ComputerName 12 | Define computer(s) to remotely return the Windows Update history of 13 | 14 | 15 | .EXAMPLE 16 | "DC01.domain.com","DHCP.domain.com" | Get-WUHistory 17 | # Return information on Windows Update history for remote devices 18 | 19 | 20 | .EXAMPLE 21 | Get-WUHistory 22 | # Return information on Windows Updates that were installed and how 23 | 24 | 25 | .NOTES 26 | Author: Robert Osborne 27 | Contact: rosborne@advisor360.com, rosborne@vinebrooktech.com 28 | 29 | 30 | .LINK 31 | https://vinebrooktech.com 32 | 33 | 34 | .INPUTS 35 | System.String[] 36 | 37 | 38 | .OUTPUTS 39 | PSCustonObject 40 | #> 41 | [OutputType('PSWindowsUpdate.WUHistory')] 42 | [CmdletBinding( 43 | SupportsShouldProcess=$True, 44 | ConfirmImpact="Low")] 45 | param( 46 | [Parameter( 47 | Position=0, 48 | Mandatory=$False, 49 | ValueFromPipeline=$True, 50 | ValueFromPipelineByPropertyName=$True)] # End Parameter 51 | [ValidateScript({Test-Connection -CompuerName $env:COMPUTERNAME -Count 2 -BufferSize 32 -Quiet})] 52 | [String[]]$ComputerName = $env:COMPUTERNAME 53 | ) # End param 54 | 55 | BEGIN { 56 | 57 | $UpdateCollection = @() 58 | 59 | } PROCESS { 60 | 61 | ForEach ($Computer in $ComputerName) { 62 | 63 | Write-Verbose "Building Windows Update history list" 64 | 65 | If ($PSCmdlet.ShouldProcess($Computer,"Get updates history")) { 66 | 67 | Write-Verbose -Message "Getting updates history for $Computer" 68 | If ($Computer -like $env:COMPUTERNAME) { 69 | 70 | Write-Verbose -Message "Creating Microsoft.Update.Session object for local device $Computer" 71 | $Session = New-Object -ComObject Microsoft.Update.Session 72 | 73 | } Else { 74 | 75 | Write-Verbose -Message "Creating update session for remote device $Computer" 76 | $Session = [Activator]::CreateInstance([Type]::GetTypeFromProgID("Microsoft.Update.Session",$Computer)) 77 | 78 | } # End If Else 79 | 80 | Write-Verbose -Message "Creating update searcher for $Computer" 81 | $Searcher = $Session.CreateUpdateSearcher() 82 | $TotalHistoryCount = $Searcher.GetTotalHistoryCount() 83 | 84 | If($TotalHistoryCount -gt 0) { 85 | 86 | $History = $Searcher.QueryHistory(0, $TotalHistoryCount) 87 | $NumberOfUpdate = 1 88 | Foreach($H in $History) { 89 | 90 | Write-Verbose -Message "Searching $($NumberOfUpdate)/$($TotalHistoryCount) $($H.Title) `nUPDATE: $($H.Title)" 91 | 92 | $Matches = $Null 93 | $H.Title -match "KB(\d+)" | Out-Null 94 | 95 | If($Matches -eq $Null) { 96 | 97 | Add-Member -InputObject $H -MemberType NoteProperty -Name KB -Value "" 98 | 99 | } Else { 100 | 101 | Add-Member -InputObject $H -MemberType NoteProperty -Name KB -Value ($matches[0]) 102 | 103 | } # End If Else 104 | 105 | Add-Member -InputObject $H -MemberType NoteProperty -Name ComputerName -Value $Computer 106 | Switch ($H.ResultCode) { 107 | 108 | '1' { $Result = "In Progress" } 109 | 110 | '2' { $Result = "Succeeded" } 111 | 112 | '3' { $Result = "Succeeded with Errors" } 113 | 114 | '4' { $Result = "Failed" } 115 | 116 | '5' { $Result = "Aborted" } 117 | 118 | } # End Switch 119 | Add-Member -InputObject $H -MemberType NoteProperty -Name Result -Value $Result 120 | 121 | $H.PSTypeNames.Clear() 122 | $H.PSTypeNames.Add('PSWindowsUpdate.WUHistory') 123 | 124 | $UpdateCollection += $H 125 | $NumberOfUpdate++ 126 | 127 | } # End Foreach 128 | 129 | } Else { 130 | 131 | Write-Warning "Update history was likely cleared. No results could be returned" 132 | 133 | } # End If Else 134 | 135 | } # End If 136 | 137 | } # End Foreach 138 | 139 | } END { 140 | 141 | Return $UpdateCollection 142 | 143 | } # End BPE 144 | 145 | } # End Function Get-UpdateHistory 146 | -------------------------------------------------------------------------------- /Get-WindowsUpdateError.ps1: -------------------------------------------------------------------------------- 1 | Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force -Confirm:$False 2 | Write-Output "[*] Building update log file, please wait as this may take a up to a minute to complete." 3 | $Job = Start-Job -ScriptBlock { Get-WindowsUpdateLog -ErrorVariable ErrorVariable } 4 | $Job | Wait-Job | Remove-Job 5 | 6 | 7 | Write-Output "[*] Verifying log was updated today" 8 | If ($env:OneDrive) { 9 | 10 | $UpdateLog = "$env:OneDrive\Desktop\WindowsUpdate.log" 11 | 12 | } Else { 13 | 14 | $UpdateLog = "$env:USERPROFILE\Desktop\WindowsUpdate.log" 15 | 16 | } # End If Else 17 | 18 | 19 | Write-Output "[*] Verifying update log was last written too today" 20 | [datetime]$Today = Get-Date 21 | $FileProperties = Get-ChildItem -Path $UpdateLog 22 | If ((Test-Path -Path $UpdateLog) -and ($FileProperties.LastWriteTime.ToShortDateString() -eq ($Today).ToShortDateString())) { 23 | 24 | Write-Output "[*] Successfully created Windows Update log file" 25 | $Pattern = 'ERROR' 26 | $ErrorLog = $UpdateLog.Replace("WindowsUpdate.log","WindowsError.log") 27 | Get-Content -Path $UpdateLog | Select-String -Pattern $Pattern | Out-File -FilePath $ErrorLog 28 | $ErrorLogContents = Get-Content -Path $ErrorLog 29 | 30 | Do { 31 | 32 | $Answer = Read-Host -Prompt "Would you like to view errors from the last 24 hours or the Week? [t/w]" 33 | If ($Answer -like "t*") { 34 | 35 | $WriteLine = @() 36 | ForEach ($Line in $ErrorLogContents) { 37 | 38 | If ($Line -NotLike "*succeeded with errors = 0*" -and $Line -NotLike "*and error 0") { 39 | 40 | Write-Verbose "Checking for entires in the last 24 hours" 41 | Try { 42 | 43 | [datetime]$CheckDate = ($Line.ToCharArray() | Select-Object -First 19 ) -Join '' 44 | If (($Null -ne $CheckDate) -and ($CheckDate -gt $Today.AddHours(-24))) { 45 | 46 | $WriteLine += $Line 47 | 48 | } # End If 49 | 50 | } Catch { 51 | 52 | Continue 53 | 54 | } # End Try Catch 55 | 56 | } # End If 57 | 58 | } # End ForEach 59 | 60 | If (!$WriteLine) { 61 | 62 | Write-Host "SUCCESS! No Windows Update errors over the last 24 hours" -ForegroundColor Green 63 | 64 | } Else { 65 | 66 | $WriteLine 67 | $Answer = Read-Host -Prompt "Based on the error messages above, should we run the Windows Update Troubleshooter? [y/N]" 68 | If ($Answer -like "y*") { 69 | 70 | Get-TroubleshootingPack -Path "C:\Windows\Diagnostics\System\WindowsUpdate" | Invoke-TroubleshootingPack -Result "C:\DiagResult" 71 | Write-Output "[*] Troubleshooter results saved to C:\DiagResult" 72 | 73 | } # End If 74 | 75 | $RunUpdate = Read-Host -Prompt "Would you like to try updating Windows again now? [y/N]" 76 | If ($RunUpdate -like "y*") { 77 | 78 | Write-Output "[*] Running Windows Update" 79 | $Updates = Start-WUScan -SearchCriteria "Type='Software' AND IsInstalled=0" 80 | If ($Updates) { 81 | 82 | Install-WUUpdates -Updates $Updates 83 | 84 | } Else { 85 | 86 | Write-Host "Hooray! No more Windows Updates to install" -ForegroundColor Green 87 | 88 | } # End Else 89 | 90 | } # End If 91 | 92 | } # End If Else 93 | 94 | } ElseIf ($Answer -like "w*") { 95 | 96 | $WriteLine = @() 97 | ForEach ($Line in $ErrorLogContents) { 98 | 99 | If ($Line -NotLike "*succeeded with errors = 0*" -and $Line -NotLike "*and error 0") { 100 | 101 | Write-Verbose "Checking all the Windows Update error log entries" 102 | $WriteLine += $Line 103 | 104 | } # End If 105 | 106 | } # End ForEach 107 | 108 | If (!$WriteLine) { 109 | 110 | Write-Host "SUCCESS! No Windows Update errors over the last 24 hours" -ForegroundColor Green 111 | 112 | } Else { 113 | 114 | $WriteLine + "`n" 115 | $Answer = Read-Host -Prompt "Based on the error messages above, should we run the Windows Update Troubleshooter? [y/N]" 116 | If ($Answer -like "y*") { 117 | 118 | Get-TroubleshootingPack -Path "C:\Windows\Diagnostics\System\WindowsUpdate" | Invoke-TroubleshootingPack -Result "C:\DiagResult" 119 | Write-Output "[*] Troubleshooter results saved to C:\DiagResult" 120 | 121 | } # End If 122 | 123 | $RunUpdate = Read-Host -Prompt "Would you like to try updating Windows again now? [y/N]" 124 | If ($RunUpdate -like "y*") { 125 | 126 | Write-Output "[*] Running Windows Update" 127 | $Updates = Start-WUScan -SearchCriteria "Type='Software' AND IsInstalled=0" 128 | If ($Updates) { 129 | 130 | Install-WUUpdates -Updates $Updates 131 | 132 | } Else { 133 | 134 | Write-Host "Hooray! No more Windows Updates to install" -ForegroundColor Green 135 | 136 | } # End Else 137 | 138 | 139 | } # End If 140 | 141 | Write-Output "[*] Script Execution Complete" 142 | 143 | } # End If Else 144 | 145 | } Else { 146 | 147 | Write-Output "You just had to be difficult :) Lets try again" 148 | 149 | } # End If ElseIf Else 150 | 151 | } Until ($Answer -like "t*" -or $Answer -like "w*") # End Do Until 152 | 153 | } Else { 154 | 155 | Write-Output "[x] Failed to create Windows Update log file" 156 | Throw "$ErrorVariable" 157 | 158 | } # End If Else 159 | -------------------------------------------------------------------------------- /Get-WindowsUpdateErrorCode.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This cmdlet is used to return the error code that caused a windows update to fail. 4 | 5 | 6 | .DESCRIPTION 7 | Return the error codes that contains information on a failed Windows or SCCM update 8 | 9 | 10 | .PARAMETER Path 11 | Define the log file or directory containing log files to search for error codes in. Accepts wildcard values 12 | 13 | .PARAMETER Date 14 | Define the date to use when searching a collection of C:\Windows\CCM\Log files for SCCM error codes. This parameter can not be used in conjunction with -Path and is for searching SCCM logs 15 | 16 | .PARAMETER All 17 | Return every error code found in the log files instead of the latest unique values only 18 | 19 | 20 | .EXAMPLE 21 | Get-WindowsUpdateErrorCode 22 | # Generates a Windows Update log file and saves it to the running users desktop and returns the error code for the failed updates 23 | 24 | .EXAMPLE 25 | Get-WindowsUpdateErrorCode -Path C:\Windows\Temp\Custom.log -All 26 | # Searches the log file Custom.log for error codes and returns everyone one of them 27 | 28 | .EXAMPLE 29 | Get-WindowsUpdateErrorCode -Date (Get-Date).AddDays(-3) 30 | # Searches all log files in C:\Windows\CCM\Log that have the date from 3 days ago in the log files name 31 | 32 | 33 | .NOTES 34 | Author: Robert H. Osborne 35 | Alias: tobor 36 | Contact: rosborne@osbornepro.com 37 | 38 | 39 | .LINK 40 | https://github.com/tobor88 41 | https://github.com/osbornepro 42 | https://gitlab.com/tobor88 43 | https://osbornepro.com 44 | https://writeups.osbornepro.com 45 | https://btpssecpack.osbornepro.com 46 | https://www.powershellgallery.com/profiles/tobor 47 | https://www.hackthebox.eu/profile/52286 48 | https://www.credly.com/users/roberthosborne/badges 49 | https://www.linkedin.com/in/roberthosborne/ 50 | 51 | 52 | .INPUTS 53 | None 54 | 55 | 56 | .OUTPUTS 57 | System.String 58 | #> 59 | Function Get-WindowsUpdateErrorCode { 60 | [CmdletBinding()] 61 | param( 62 | [Parameter( 63 | ParameterSetName="File", 64 | Position=0, 65 | Mandatory=$True, 66 | ValueFromPipeline=$True, 67 | HelpMessage="Define the path to log files. Wildcards are accepted EXAMPLE: C:\Windows\CCM\Logs\*202205*.log")] # End Parameter 68 | [SupportsWildcards()] 69 | [String]$Path, 70 | 71 | [Parameter( 72 | ParameterSetName="SCCM", 73 | Position=0, 74 | Mandatory=$False, 75 | ValueFromPipeline=$False 76 | #HelpMessage="Enter the date of the log files you are checking for errors on. `nEXAMPLE: Get-Date -Date 6/14/2022 `nEXAMPLE: (Get-Date).AddDays(-7)" 77 | )] # End Parameter 78 | [DateTime]$Date = (Get-Date), 79 | 80 | [Parameter( 81 | Mandatory=$False)] 82 | [Switch][Bool]$All 83 | ) # End param 84 | 85 | If ($PSCmdlet.ParameterSetName -eq "SCCM") { 86 | 87 | $Month = $Date.Month.ToString("00") 88 | $Year = $Date.Year.ToString("0000") 89 | $Day = $Date.Day.ToString("00") 90 | 91 | $Path = "C:\Windows\CCM\Logs\*$($Year)$($Month)$($Day)*.log" 92 | 93 | } # End If 94 | 95 | If (Test-Path -Path $Path -ErrorAction SilentlyContinue) { 96 | 97 | Write-Verbose "Successfully created Windows Update log file" 98 | [regex]$Pattern = '0x8(.*){5,20}' 99 | 100 | $Results = Select-String -Pattern $Pattern -Path $Path -AllMatches | Where-Object -FilterScript { $_ -notlike "*HRESULT = `"0x00000000`";*" -and $_ -notlike "*0x0,*"} | ForEach-Object { $_.Matches } | ForEach-Object { $_.Value } 101 | $CodeFilter = @() 102 | ForEach ($Line in $Results) { 103 | 104 | $Code = Try { (($Line | Out-String).Substring(0,10) | Select-String -Pattern $Pattern | Out-String).Trim() } Catch { Continue } 105 | 106 | If ($All.IsPresent) { 107 | 108 | $TimeFilter = Try { ($Line | Out-String).Split("=")[1].Split(" ")[0].Replace('"','').Split(".")[0] } Catch { "Error" } 109 | $DateFilter = Try { ($Line | Out-String).Split("=")[2].Split(" ")[0].Replace('"','') } Catch { Continue } 110 | $ComponentFilter = Try { ($Line | Out-String).Split("=")[3].Split(" ")[0].Replace('"','') } Catch { Continue } 111 | If ($ComponentFilter) { Try { $Description = Get-ComponentDescription -Name $ComponentFilter } Catch { $Description = "No translation available. Update Get-ComponentDescription" } } 112 | 113 | $CodeFilter += New-Object -TypeName PSCustomObject -Property @{ErrorCode=$Code;Date=$DateFilter;Time=$TimeFilter;Log=$ComponentFilter;LogDesc=$Description} 114 | 115 | } ElseIf ($Code -notin $CodeFilter.ErrorCode) { 116 | 117 | $Line = (($Results | Select-String -Pattern $Code)[-1] | Out-String).Trim() 118 | $TimeFilter = Try { ($Line | Out-String).Split("=")[1].Split(" ")[0].Replace('"','').Split(".")[0] } Catch { "Error" } 119 | $DateFilter = Try { ($Line | Out-String).Split("=")[2].Split(" ")[0].Replace('"','') } Catch { Continue } 120 | $ComponentFilter = Try { ($Line | Out-String).Split("=")[3].Split(" ")[0].Replace('"','') } Catch { Continue } 121 | If ($ComponentFilter) { Try { $Description = Get-ComponentDescription -Name $ComponentFilter } Catch { $Description = "No translation available. Update Get-ComponentDescription" } } 122 | 123 | $CodeFilter += New-Object -TypeName PSCustomObject -Property @{ErrorCode=$Code;Date=$DateFilter;Time=$TimeFilter;Log=$ComponentFilter;LogDesc=$Description} 124 | 125 | } # End If ElseIf 126 | 127 | } # End ForEach 128 | 129 | If (-Not $All.IsPresent) { 130 | 131 | Write-Verbose "Selecting unique error codes" 132 | $Results = $CodeFilter | Sort-Object -Unique -Property ErrorCode 133 | 134 | } Else { 135 | 136 | Write-Verbose "Selecting all error codes" 137 | $Results = $CodeFilter 138 | 139 | } # End If Else 140 | 141 | If (!$Results) { 142 | 143 | Write-Output "[*] SUCCESS! No Windows Update errors on $($Date.ToShortDateString())" 144 | 145 | } Else { 146 | 147 | If ($Null -ne $CodeFilter) { 148 | 149 | Return $Results 150 | 151 | } Else { 152 | 153 | Write-Output "[i] No error codes found in the windows update logs" 154 | 155 | } # End If Else 156 | 157 | } # End If Else 158 | 159 | } Else { 160 | 161 | Write-Error "[x] No log files in the location specified: $Path" 162 | 163 | } # End If Else 164 | 165 | } # End Function Get-WindowsUpdateErrorCode 166 | -------------------------------------------------------------------------------- /Install-7Zip.ps1: -------------------------------------------------------------------------------- 1 | Function Install-7Zip { 2 | <# 3 | .SYNOPSIS 4 | This cmdlet is used to install/update 7Zip for Windows. It can also be used to simply download the installer 5 | 6 | 7 | .DESCRIPTION 8 | Download the lates 7Zip installed for Windows, verify that hash and install the file 9 | 10 | 11 | .PARAMETER OutFile 12 | Define where to save the installer file. Default location is your Temp directory 13 | 14 | .PARAMETER DownloadOnly 15 | Switch parameter to specify you only want to download the installer 16 | 17 | .PARAMETER TryTLSv13 18 | Switch parameter that tells PowerShell to try download file using TLSv1.3. This seems to fail as of 7/25/2023 due to 1.3 being so new 19 | 20 | .EXAMPLE 21 | PS> Install-7Zip 22 | # This example downloads the 7Zip installer and verifies the checksum before installing it 23 | 24 | 25 | .EXAMPLE 26 | PS> Install-7Zip -OutFile "$env:TEMP\7zip-installer.msi" 27 | # This example downloads the 7Zip installer and installs it 28 | 29 | .EXAMPLE 30 | PS> Install-7Zip -OutFile "$env:TEMP\7zip-installer.msi" -DownloadOnly 31 | # This example downloads the 7Zip installer 32 | 33 | 34 | .NOTES 35 | Author: Robert H. Osborne 36 | Alias: tobor 37 | Contact: rosborne@osbornepro.com 38 | 39 | 40 | .LINK 41 | https://github.com/tobor88 42 | https://github.com/osbornepro 43 | https://www.powershellgallery.com/profiles/tobor 44 | https://osbornepro.com 45 | https://writeups.osbornepro.com 46 | https://encrypit.osbornepro.com 47 | https://btpssecpack.osbornepro.com 48 | https://www.powershellgallery.com/profiles/tobor 49 | https://www.hackthebox.eu/profile/52286 50 | https://www.linkedin.com/in/roberthosborne/ 51 | https://www.credly.com/users/roberthosborne/badges 52 | 53 | 54 | .INPUTS 55 | None 56 | 57 | 58 | .OUTPUTS 59 | System.Management.Automation.PSObject 60 | #> 61 | [OutputType([System.Management.Automation.PSObject])] 62 | [CmdletBinding(DefaultParameterSetName="Installer")] 63 | param( 64 | [Parameter( 65 | Mandatory=$False 66 | )] # End Parameter 67 | [ValidateScript({$_ -like "*.exe"})] 68 | [String]$OutFile = "$env:TEMP\7zip-installer.exe", 69 | 70 | [Parameter( 71 | Mandatory=$False 72 | )] # End Parameter 73 | [ValidateSet('32','64')] 74 | [String]$Architecture = "64", 75 | 76 | [Parameter( 77 | Mandatory=$False 78 | )] # End Parameter 79 | [Switch]$DownloadOnly, 80 | 81 | [Parameter( 82 | Mandatory=$False 83 | )] # End Parameter 84 | [Switch]$TryTLSv13 85 | ) # End param 86 | 87 | $TlsVersion = "TLSv1.2" 88 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 89 | If ($TryTLSv13.IsPresent) { 90 | 91 | $TlsVersion = "TLSv1.3" 92 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls13 93 | 94 | } # End If 95 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') utilizing $TlsVersion" 96 | 97 | $MainUrl = "https://www.7-zip.org/download.html" 98 | $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 99 | 100 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Obtaining latest version information for 7Zip" 101 | $Version = ((Invoke-WebRequest -UseBasicParsing -Uri $MainUrl -UserAgent $UserAgent -Method GET -ContentType 'text/html' -Verbos:$False).Links | Where-Object -FilterScript { $_.outerHTML -like "*7z*64.exe`">Download<*" } | Select-Object -First 1 -ExpandProperty href).Split('z')[1].Split('-')[0] 102 | Switch ($Architecture) { 103 | 104 | '32' { $DownloadLink = "https://www.7-zip.org/a/7z$($Version).exe" } 105 | 106 | '64' { $DownloadLink = "https://www.7-zip.org/a/7z$($Version)-x64.exe" } 107 | 108 | } # End Switch 109 | 110 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading 7zip" 111 | Invoke-WebRequest -UseBasicParsing -Uri $DownloadLink -UserAgent $UserAgent -OutFile $OutFile -ContentType 'application/octet-stream' -Verbose:$False -ErrorAction Stop | Out-Null 112 | 113 | If ($DownloadOnly.IsPresent -and (Test-Path -Path $OutFile)) { 114 | 115 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') File saved to $OutFile" 116 | 117 | } Else { 118 | 119 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Executing installation of 7zip version $Version" 120 | Start-Process -FilePath $OutFile -ArgumentList @("/S") -NoNewWindow -Wait -PassThru -ErrorAction Stop 121 | 122 | } # End If Else 123 | 124 | } # End Function Install-7Zip 125 | -------------------------------------------------------------------------------- /Install-AzureCli.ps1: -------------------------------------------------------------------------------- 1 | Function Install-AzureCli { 2 | <# 3 | .SYNOPSIS 4 | This cmdlet is used to install/update AzureCli for Windows. It can also be used to simply download the installer 5 | 6 | 7 | .DESCRIPTION 8 | Download the lates AzureCli installed for Windows, verify that hash and install the file 9 | 10 | 11 | .PARAMETER OutFile 12 | Define where to save the installer file. Default location is your Temp directory 13 | 14 | .PARAMETER DownloadOnly 15 | Switch parameter to specify you only want to download the installer 16 | 17 | .PARAMETER TryTLSv13 18 | Switch parameter that tells PowerShell to try download file using TLSv1.3. This seems to fail as of 3/28/2023 due to 1.3 being so new 19 | 20 | 21 | .EXAMPLE 22 | Install-AzureCli 23 | # This example downloads the AzureCli installer and verifies the checksum before installing it 24 | 25 | .EXAMPLE 26 | Install-AzureCli -OutFile "$env:TEMP\AzureCli-Setup.exe" 27 | # This example downloads the AzureCli installer and verifies the checksum before installing it 28 | 29 | .EXAMPLE 30 | Install-AzureCli -OutFile "$env:TEMP\AzureCli-Setup.exe" -DownloadOnly 31 | # This example downloads the AzureCli installer and verifies the checksum 32 | 33 | 34 | .NOTES 35 | Author: Robert H. Osborne 36 | Alias: tobor 37 | Contact: rosborne@osbornepro.com 38 | 39 | 40 | .LINK 41 | https://github.com/tobor88 42 | https://github.com/osbornepro 43 | https://www.powershellgallery.com/profiles/tobor 44 | https://osbornepro.com 45 | https://writeups.osbornepro.com 46 | https://encrypit.osbornepro.com 47 | https://btpssecpack.osbornepro.com 48 | https://www.powershellgallery.com/profiles/tobor 49 | https://www.hackthebox.eu/profile/52286 50 | https://www.linkedin.com/in/roberthosborne/ 51 | https://www.credly.com/users/roberthosborne/badges 52 | 53 | 54 | .INPUTS 55 | None 56 | 57 | 58 | .OUTPUTS 59 | System.Management.Automation.PSObject 60 | #> 61 | [OutputType([System.Management.Automation.PSObject])] 62 | [CmdletBinding()] 63 | param( 64 | [Parameter( 65 | Position=0, 66 | Mandatory=$False 67 | )] # End Parameter 68 | [ValidateScript({$_ -like "*.msi"})] 69 | [String]$OutFile = "$env:TEMP\azure-cli-version.msi", 70 | 71 | [Parameter( 72 | Mandatory=$False 73 | )] # End Parameter 74 | [Switch]$DownloadOnly, 75 | 76 | [Parameter( 77 | Mandatory=$False 78 | )] # End Parameter 79 | [Switch]$TryTLSv13 80 | ) # End param 81 | 82 | $TlsVersion = "TLSv1.2" 83 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 84 | If ($TryTLSv13.IsPresent) { 85 | 86 | $TlsVersion = "TLSv1.3" 87 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls13 88 | 89 | } # End If 90 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') utilizing $TlsVersion" 91 | 92 | $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 93 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading Azure CLI from GitHub" 94 | Try { 95 | 96 | $DownloadLink = 'https://aka.ms/installazurecliwindows' 97 | Invoke-WebRequest -Uri $DownloadLink -UseBasicParsing -UserAgent $UserAgent -OutFile $OutFile -Method GET -Verbose:$False | Out-Null 98 | 99 | } Catch { 100 | 101 | Throw $Error[0] 102 | 103 | } # End Try Catch Catch 104 | 105 | Write-Warning -Message "[!] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') I have not been able to find a checksum for the Azure CLI installer file" 106 | If ($DownloadOnly.IsPresent -and (Test-Path -Path $OutFile)) { 107 | 108 | Write-Output -InputObject "[*] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully downloaded file for Azure CLI.`n[i] File saved to $OutFile" 109 | 110 | } Else { 111 | 112 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Executing installation of Microsoft Azure CLI for Windows" 113 | If (Test-Path -Path $OutFile) { 114 | 115 | Start-Process -FilePath "C:\Windows\System32\msiexec.exe" -ArgumentList @('/i', "$OutFile", '/quiet') -NoNewWindow -Wait -PassThru -ErrorAction Stop 116 | 117 | } Else { 118 | 119 | Throw "[x] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Failed to download file for Azure CLI" 120 | 121 | } # End If Else 122 | 123 | } # End If Else 124 | 125 | } # End FunctionInstall-AzureCli 126 | -------------------------------------------------------------------------------- /Install-AzureStorageExplorer.ps1: -------------------------------------------------------------------------------- 1 | Function Install-AzureStorageExplorer { 2 | <# 3 | .SYNOPSIS 4 | This cmdlet is used to install/update Azure Storage Explorer for Windows. It can also be used to simply download the installer 5 | 6 | 7 | .DESCRIPTION 8 | Download the lates Azure Storage Explorer installed for Windows. I have not found a checksum to verify the hash 9 | 10 | 11 | .PARAMETER OutFile 12 | Define where to save the installer file. Default location is your Temp directory 13 | 14 | .PARAMETER DownloadOnly 15 | Switch parameter to specify you only want to download the installer 16 | 17 | .PARAMETER TryTLSv13 18 | Switch parameter that tells PowerShell to try download file using TLSv1.3. This seems to fail as of 4/26/2023 due to 1.3 being so new 19 | 20 | 21 | .EXAMPLE 22 | Install-AzureStorageExplorer 23 | # This example downloads the Azure Storage Explorer installer. I have not found a check to verify the hash before installing it 24 | 25 | .EXAMPLE 26 | Install-AzureStorageExplorer -OutFile "$env:TEMP\Windows_StorageExplorer.exe" 27 | # This example downloads the Azure Storage Explorer installer and verifies the checksum before installing it 28 | 29 | .EXAMPLE 30 | Install-AzureStorageExplorer -OutFile "$env:TEMP\Windows_StorageExplorer.exe" -DownloadOnly 31 | # This example downloads the Azure Storage Explorer installer and verifies the checksum 32 | 33 | 34 | .NOTES 35 | Author: Robert H. Osborne 36 | Alias: tobor 37 | Contact: rosborne@osbornepro.com 38 | 39 | 40 | .LINK 41 | https://github.com/tobor88 42 | https://github.com/osbornepro 43 | https://www.powershellgallery.com/profiles/tobor 44 | https://osbornepro.com 45 | https://writeups.osbornepro.com 46 | https://encrypit.osbornepro.com 47 | https://btpssecpack.osbornepro.com 48 | https://www.powershellgallery.com/profiles/tobor 49 | https://www.hackthebox.eu/profile/52286 50 | https://www.linkedin.com/in/roberthosborne/ 51 | https://www.credly.com/users/roberthosborne/badges 52 | 53 | 54 | .INPUTS 55 | None 56 | 57 | 58 | .OUTPUTS 59 | System.Management.Automation.PSObject 60 | #> 61 | [OutputType([System.Management.Automation.PSObject])] 62 | [CmdletBinding()] 63 | param( 64 | [Parameter( 65 | Position=0, 66 | Mandatory=$False 67 | )] # End Parameter 68 | [ValidateScript({$_ -like "*.exe"})] 69 | [String]$OutFile = "C:\Windows\Temp\Windows_StorageExplorer.exe", 70 | 71 | [Parameter( 72 | Mandatory=$False 73 | )] # End Parameter 74 | [Switch]$DownloadOnly, 75 | 76 | [Parameter( 77 | Mandatory=$False 78 | )] # End Parameter 79 | [Switch]$TryTLSv13 80 | ) # End param 81 | 82 | $TlsVersion = "TLSv1.2" 83 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 84 | If ($TryTLSv13.IsPresent) { 85 | 86 | $TlsVersion = "TLSv1.3" 87 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls13 88 | 89 | } # End If 90 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') utilizing $TlsVersion" 91 | 92 | $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 93 | $Uri = "https://api.github.com/repos/Microsoft/AzureStorageExplorer/releases/latest" 94 | 95 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading Azure Storage Explorer from GitHub" 96 | Try { 97 | 98 | $GetLinks = Invoke-RestMethod -Uri $Uri -Method GET -UseBasicParsing -UserAgent $UserAgent -ContentType 'application/json; charset=utf-8' -Verbose:$False 99 | $DownloadLink = ($GetLinks.assets | Where-Object -FilterScript { $_.Name -like "Windows-StorageExplorer.exe"}).browser_download_url 100 | Invoke-WebRequest -Uri $DownloadLink -UseBasicParsing -UserAgent $UserAgent -OutFile $OutFile -Method GET -ContentType 'application/octet-stream' -Verbose:$False | Out-Null 101 | 102 | } Catch { 103 | 104 | Throw $Error[0] 105 | 106 | } # End Try Catch Catch 107 | 108 | If ($DownloadOnly.IsPresent -and (Test-Path -Path $OutFile)) { 109 | 110 | Write-Warning -Message "[!] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') I have not found a checksum value online to compare for Azure Storage Explorer" 111 | Write-Output -InputObject "[*] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully downloaded file for Azure Storage Explorer.`n[i] File saved to $OutFile" 112 | 113 | } Else { 114 | 115 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Executing installation of Windows Azure Storage Explorer for Windows" 116 | Start-Process -FilePath $OutFile -ArgumentList @('/VERYSILENT', '/NORESTART', '/ALLUSERS') -NoNewWindow -Wait -PassThru -ErrorAction Stop 117 | 118 | } # End If Else 119 | 120 | } # End Function Install-AzureStorageExplorer 121 | -------------------------------------------------------------------------------- /Install-CherryTree.ps1: -------------------------------------------------------------------------------- 1 | Function Install-CherryTree { 2 | <# 3 | .SYNOPSIS 4 | This cmdlet is used to install/update CherryTree for Windows. It can also be used to simply download the installer 5 | 6 | 7 | .DESCRIPTION 8 | Download the lates CherryTree installed for Windows, verify that hash and install the file 9 | 10 | 11 | .PARAMETER OutFile 12 | Define where to save the installer file. Default location is your Temp directory 13 | 14 | .PARAMETER DownloadOnly 15 | Switch parameter to specify you only want to download the installer 16 | 17 | .PARAMETER TryTLSv13 18 | Switch parameter that tells PowerShell to try download file using TLSv1.3. This seems to fail as of 3/28/2023 due to 1.3 being so new 19 | 20 | 21 | .EXAMPLE 22 | Install-CherryTree 23 | # This example downloads the CherryTree installer and verifies the checksum before installing it 24 | 25 | .EXAMPLE 26 | Install-CherryTree -OutFile "$env:TEMP\CherryTreeClientx64.exe" 27 | # This example downloads the CherryTree installer and verifies the checksum before installing it 28 | 29 | .EXAMPLE 30 | Install-CherryTree -OutFile "$env:TEMP\CherryTreeClientx64.exe" -DownloadOnly 31 | # This example downloads the CherryTree installer and verifies the checksum 32 | 33 | 34 | .NOTES 35 | Author: Robert H. Osborne 36 | Alias: tobor 37 | Contact: rosborne@osbornepro.com 38 | 39 | 40 | .LINK 41 | https://github.com/tobor88 42 | https://github.com/osbornepro 43 | https://www.powershellgallery.com/profiles/tobor 44 | https://osbornepro.com 45 | https://writeups.osbornepro.com 46 | https://encrypit.osbornepro.com 47 | https://btpssecpack.osbornepro.com 48 | https://www.powershellgallery.com/profiles/tobor 49 | https://www.hackthebox.eu/profile/52286 50 | https://www.linkedin.com/in/roberthosborne/ 51 | https://www.credly.com/users/roberthosborne/badges 52 | 53 | 54 | .INPUTS 55 | None 56 | 57 | 58 | .OUTPUTS 59 | System.Management.Automation.PSObject 60 | #> 61 | [OutputType([System.Management.Automation.PSObject])] 62 | [CmdletBinding()] 63 | param( 64 | [Parameter( 65 | Position=0, 66 | Mandatory=$False 67 | )] # End Parameter 68 | [ValidateScript({$_ -like "*.exe"})] 69 | [String]$OutFile = "$env:TEMP\cherrytree-version_win64_setup.exe", 70 | 71 | [Parameter( 72 | Mandatory=$False 73 | )] # End Parameter 74 | [Switch]$DownloadOnly, 75 | 76 | [Parameter( 77 | Mandatory=$False 78 | )] # End Parameter 79 | [Switch]$TryTLSv13 80 | ) # End param 81 | 82 | $TlsVersion = "TLSv1.2" 83 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 84 | If ($TryTLSv13.IsPresent) { 85 | 86 | $TlsVersion = "TLSv1.3" 87 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls13 88 | 89 | } # End If 90 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') utilizing $TlsVersion" 91 | 92 | $Uri = "https://api.github.com/repos/giuspen/cherrytree/releases/latest" 93 | $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 94 | 95 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading CherryTree from GitHub" 96 | Try { 97 | 98 | $GetLinks = Invoke-RestMethod -Uri $Uri -Method GET -UseBasicParsing -UserAgent $UserAgent -ContentType 'application/json; charset=utf-8' -Verbose:$False 99 | $DownloadLink = ($GetLinks.assets | Where-Object -Property Name -like "cherrytree_*_win64_setup.exe").browser_download_url 100 | 101 | } Catch { 102 | 103 | Throw $Error[0] 104 | 105 | } # End Try Catch Catch 106 | 107 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading CherryTree" 108 | Invoke-WebRequest -UseBasicParsing -Uri $DownloadLink -UserAgent $UserAgent -OutFile $OutFile -ContentType 'application/octet-stream' -Verbose:$False | Out-Null 109 | 110 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Getting hash values for CherryTree" 111 | $Version = (Get-Item -Path $OutFile).VersionInfo.ProductVersion 112 | $FileHash = (Get-FileHash -Path $OutFile -Algorithm SHA256).Hash.ToLower() 113 | $CheckSum = ((Invoke-WebRequest -UseBasicParsing -Uri "https://www.giuspen.net/cherrytree/#downl" -UserAgent $UserAgent -ContentType 'text/html; charset=UTF-8' -Verbose:$False).RawContent.Split("`n") | Select-String -Pattern "cherrytree_$($Version.Trim())_win64_setup.exe" | Out-String).Split(" ")[-3].Split('>')[-1].Trim() 114 | 115 | If ($CheckSum -eq $FileHash) { 116 | 117 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully verified hash of newly downloaded file for CherryTree version $Version" 118 | If ($DownloadOnly.IsPresent -and (Test-Path -Path $OutFile)) { 119 | 120 | Write-Output -InputObject "[*] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully downloaded file and verified hash.`n[i] File saved to $OutFile" 121 | 122 | } Else { 123 | 124 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Executing installation of CherryTree version $Version" 125 | Move-Item -Path $OutFile -Destination $OutFile.Replace("version", $Version) -Force -Confirm:$False 126 | Start-Process -FilePath $OutFile.Replace("version", $Version) -ArgumentList @('/VERYSILENT') -NoNewWindow -Wait -PassThru 127 | 128 | } # End If Else 129 | 130 | } Else { 131 | 132 | Throw "[x] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Failed to validate hash of newly downloaded file for CherryTree version $Version" 133 | 134 | } # End If Else 135 | 136 | } # End Function Install-CherryTree 137 | -------------------------------------------------------------------------------- /Install-DrawIO.ps1: -------------------------------------------------------------------------------- 1 | Function Install-DrawIO { 2 | <# 3 | .SYNOPSIS 4 | This cmdlet is used to install/update Draw.IO for Windows. It can also be used to simply download the installer 5 | 6 | 7 | .DESCRIPTION 8 | Download the lates Draw.IO installed for Windows, verify that hash and install the file 9 | 10 | 11 | .PARAMETER OutFile 12 | Define where to save the installer file. Default location is your Temp directory 13 | 14 | .PARAMETER DownloadOnly 15 | Switch parameter to specify you only want to download the installer 16 | 17 | .PARAMETER TryTLSv13 18 | Switch parameter that tells PowerShell to try download file using TLSv1.3. This seems to fail as of 3/28/2023 due to 1.3 being so new 19 | 20 | 21 | .EXAMPLE 22 | Install-DrawIO 23 | # This example downloads the Draw.IO installer and verifies the checksum before installing it 24 | 25 | .EXAMPLE 26 | Install-DrawIO -OutFile "$env:TEMP\Draw.IOClientx64.exe" 27 | # This example downloads the Draw.IO installer and verifies the checksum before installing it 28 | 29 | .EXAMPLE 30 | Install-DrawIO -OutFile "$env:TEMP\Draw.IOClientx64.exe" -DownloadOnly 31 | # This example downloads the Draw.IO installer and verifies the checksum 32 | 33 | 34 | .NOTES 35 | Author: Robert H. Osborne 36 | Alias: tobor 37 | Contact: rosborne@osbornepro.com 38 | 39 | 40 | .LINK 41 | https://github.com/tobor88 42 | https://github.com/osbornepro 43 | https://www.powershellgallery.com/profiles/tobor 44 | https://osbornepro.com 45 | https://writeups.osbornepro.com 46 | https://encrypit.osbornepro.com 47 | https://btpssecpack.osbornepro.com 48 | https://www.powershellgallery.com/profiles/tobor 49 | https://www.hackthebox.eu/profile/52286 50 | https://www.linkedin.com/in/roberthosborne/ 51 | https://www.credly.com/users/roberthosborne/badges 52 | 53 | 54 | .INPUTS 55 | None 56 | 57 | 58 | .OUTPUTS 59 | System.Management.Automation.PSObject 60 | #> 61 | [OutputType([System.Management.Automation.PSObject])] 62 | [CmdletBinding()] 63 | param( 64 | [Parameter( 65 | Position=0, 66 | Mandatory=$False 67 | )] # End Parameter 68 | [ValidateScript({$_ -like "*.exe"})] 69 | [String]$OutFile = "$env:TEMP\draw.io-version-windows-installer.exe", 70 | 71 | [Parameter( 72 | Mandatory=$False 73 | )] # End Parameter 74 | [Switch]$DownloadOnly, 75 | 76 | [Parameter( 77 | Mandatory=$False 78 | )] # End Parameter 79 | [Switch]$TryTLSv13 80 | ) # End param 81 | 82 | $TlsVersion = "TLSv1.2" 83 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 84 | If ($TryTLSv13.IsPresent) { 85 | 86 | $TlsVersion = "TLSv1.3" 87 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls13 88 | 89 | } # End If 90 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') utilizing $TlsVersion" 91 | 92 | $Uri = 'https://api.github.com/repos/jgraph/drawio-desktop/releases/latest' 93 | $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 94 | 95 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Getting download link for DrawIO from GitHub" 96 | Try { 97 | 98 | $GetLinks = Invoke-RestMethod -Uri $Uri -Method GET -UseBasicParsing -UserAgent $UserAgent -ContentType 'application/json; charset=utf-8' -Verbose:$False 99 | $DownloadLink = ($GetLinks.assets | Where-Object -Property Name -like "draw.io-*-windows-installer.exe").browser_download_url 100 | $CheckSumLink = ($GetLinks.assets | Where-Object -FilterScript { $_.Name -like "Files-SHA256-Hashes.txt" }).browser_download_url 101 | 102 | } Catch { 103 | 104 | Throw $Error[0] 105 | 106 | } # End Try Catch Catch 107 | 108 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading Draw.IO" 109 | Invoke-WebRequest -UseBasicParsing -Uri $DownloadLink -UserAgent $UserAgent -OutFile $OutFile -ContentType 'application/octet-stream' -Verbose:$False | Out-Null 110 | 111 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Getting hash values for Draw.IO" 112 | $Version = (Get-Item -Path $OutFile).VersionInfo.ProductVersion 113 | $FileHash = (Get-FileHash -Path $OutFile -Algorithm SHA256).Hash.ToLower() 114 | $CheckSum = ((Invoke-WebRequest -UseBasicParsing -Uri $CheckSumLink -UserAgent $UserAgent -ContentType 'application/octet-stream' -Method GET -Verbose:$False).RawContent.Split("`n") | Where-Object -FilterScript { $_ -like "draw.io-$($Version.Trim())-windows-installer.exe *"}).Split(' ')[-1] 115 | 116 | If ($CheckSum -eq $FileHash) { 117 | 118 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully verified hash of newly downloaded file for Draw.IO version $Version" 119 | If ($DownloadOnly.IsPresent -and (Test-Path -Path $OutFile)) { 120 | 121 | Write-Output -InputObject "[*] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully downloaded file and verified hash.`n[i] File saved to $OutFile" 122 | 123 | } Else { 124 | 125 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Executing installation of Draw.IO version $Version" 126 | Move-Item -Path $OutFile -Destination $OutFile.Replace("version", $Version) -Force -Confirm:$False 127 | Start-Process -FilePath $OutFile.Replace("version", $Version) -ArgumentList @('/S') -NoNewWindow -Wait -PassThru 128 | 129 | } # End If Else 130 | 131 | } Else { 132 | 133 | Throw "[x] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Failed to validate hash of newly downloaded file for Draw.IO version $Version" 134 | 135 | } # End If Else 136 | 137 | } # End Function Install-DrawIO 138 | -------------------------------------------------------------------------------- /Install-FileZilla.ps1: -------------------------------------------------------------------------------- 1 | Function Install-FileZilla { 2 | <# 3 | .SYNOPSIS 4 | This cmdlet is used to install/update FileZilla Client for Windows on a machine. It can also be used to simply download the installer 5 | 6 | 7 | .DESCRIPTION 8 | Download the lates FileZilla Client installed for Windows, verify that hash and install the file 9 | 10 | 11 | .PARAMETER OutFile 12 | Define where to save the installer file. Default location is your Temp directory 13 | 14 | .PARAMETER DownloadOnly 15 | Switch parameter to specify you only want to download the installer 16 | 17 | .PARAMETER TryTLSv13 18 | Switch parameter that tells PowerShell to try download file using TLSv1.3. This seems to fail as of 3/28/2023 due to 1.3 being so new 19 | 20 | 21 | .EXAMPLE 22 | Install-FileZilla 23 | # This example downloads the FileZilla installer and verifies the checksum before installing it 24 | 25 | .EXAMPLE 26 | Install-FileZilla -OutFile "$env:TEMP\FilezillaClientx64.exe" 27 | # This example downloads the FileZilla installer and verifies the checksum before installing it 28 | 29 | .EXAMPLE 30 | Install-FileZilla -OutFile "$env:TEMP\FilezillaClientx64.exe" -DownloadOnly 31 | # This example downloads the FileZilla installer and verifies the checksum 32 | 33 | 34 | .NOTES 35 | Author: Robert H. Osborne 36 | Alias: tobor 37 | Contact: rosborne@osbornepro.com 38 | 39 | 40 | .LINK 41 | https://github.com/tobor88 42 | https://github.com/osbornepro 43 | https://www.powershellgallery.com/profiles/tobor 44 | https://osbornepro.com 45 | https://writeups.osbornepro.com 46 | https://encrypit.osbornepro.com 47 | https://btpssecpack.osbornepro.com 48 | https://www.powershellgallery.com/profiles/tobor 49 | https://www.hackthebox.eu/profile/52286 50 | https://www.linkedin.com/in/roberthosborne/ 51 | https://www.credly.com/users/roberthosborne/badges 52 | 53 | 54 | .INPUTS 55 | None 56 | 57 | 58 | .OUTPUTS 59 | System.Management.Automation.PSObject 60 | #> 61 | [OutputType([System.Management.Automation.PSObject])] 62 | [CmdletBinding()] 63 | param( 64 | [Parameter( 65 | Position=0, 66 | Mandatory=$False 67 | )] # End Parameter 68 | [ValidateScript({$_ -like "*.exe"})] 69 | [String]$OutFile = "$env:TEMP\filezilla-client-win64-setup.exe", 70 | 71 | [Parameter( 72 | Mandatory=$False 73 | )] # End Parameter 74 | [Switch]$DownloadOnly, 75 | 76 | [Parameter( 77 | Mandatory=$False 78 | )] # End Parameter 79 | [Switch]$TryTLSv13 80 | ) # End param 81 | 82 | $TlsVersion = "TLSv1.2" 83 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 84 | If ($TryTLSv13.IsPresent) { 85 | 86 | $TlsVersion = "TLSv1.3" 87 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls13 88 | 89 | } # End If 90 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') utilizing $TlsVersion" 91 | 92 | $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 93 | $Uri = 'https://filezilla-project.org/download.php?show_all=1' 94 | 95 | Try { 96 | 97 | $HtmlLinks = Invoke-WebRequest -Uri $Uri -UserAgent $UserAgent -UseBasicParsing -Method GET -ContentType 'text/html; charset=UTF-8' -Verbose:$False 98 | $Links = (($HtmlLinks.Links | Where-Object -FilterScript { $_.href -like "*win64-setup.exe*" }).href | Out-String).Replace("$([System.Environment]::NewLine)","") 99 | $Url = $Links.Substring(0, $Links.IndexOf('download')) 100 | 101 | } Catch { 102 | 103 | Throw $Error[0] 104 | 105 | } # End Try Catch Catch 106 | 107 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading FileZilla Client" 108 | Invoke-WebRequest -UseBasicParsing -Uri $Url -OutFile $OutFile -ContentType 'application/octet-stream' -Verbose:$False | Out-Null 109 | 110 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Getting hash values for FileZilla Client" 111 | $Version = (Get-Item -Path $OutFile).VersionInfo.FileVersion 112 | $FileHash = (Get-FileHash -Path $OutFile -Algorithm SHA512).Hash.ToLower() 113 | $Hashes = ($HtmlLinks.RawContent.Split("`n") | Select-String -Pattern "SHA-512 hash:" | Out-String) 114 | $CheckSum = $Hashes.Split(":").Replace(' ','').Split("`n") | ForEach-Object { If ($_.Length -ge 128) { $_.Replace('

', '') }} 115 | 116 | #If ($CheckSum -contains $FileHash) { 117 | 118 | # Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully verified hash of newly downloaded file for FileZilla Client version $Version" 119 | If ($DownloadOnly.IsPresent -and (Test-Path -Path $OutFile)) { 120 | 121 | Write-Output -InputObject "[*] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully downloaded file and verified hash.`n[i] File saved to $OutFile" 122 | 123 | } Else { 124 | 125 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Executing installation of FileZilla Client version $Version" 126 | Start-Process -FilePath $OutFile -ArgumentList @('/S', '/D=%PROGRAMFILES%/FileZilla FTP Client', '/user=all') -NoNewWindow -Wait -PassThru 127 | 128 | } # End If Else 129 | 130 | # } Else { 131 | 132 | # Throw "[x] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Failed to validate hash of newly downloaded file for FileZilla Client version $Version" 133 | 134 | # } # End If Else 135 | 136 | } # End Function Install-FileZilla 137 | -------------------------------------------------------------------------------- /Install-GitForWindows.ps1: -------------------------------------------------------------------------------- 1 | Function Install-GitForWindows { 2 | <# 3 | .SYNOPSIS 4 | This cmdlet is used to install/update Git For Windows on a machine. It can also be used to simply download the installer 5 | 6 | 7 | .DESCRIPTION 8 | Download the lates Git For Windows installed for Windows, verify that hash and instal the file 9 | 10 | 11 | .PARAMETER OutFile 12 | Define where to save the installer file. Default location is your Temp directory 13 | 14 | .PARAMETER InfFile 15 | Define an INF configuration file for Git if you have customizations you prefere to make. 16 | SAMPLE INF FILE CONTENTS 17 | [Setup] 18 | Lang=default 19 | Dir=C:\Program Files\Git 20 | Group=Git 21 | NoIcons=0 22 | SetupType=default 23 | Compontents=ext,ext\shellhere,ext\guihere,gitlfs,assoc,autoupdate 24 | Tasks= 25 | EditorOption=powershell 26 | CustomEditorPath= 27 | PathOption=Cmd 28 | SSHOption=OpenSSH 29 | TortoiseOption=false 30 | CURLOption=WinSSL 31 | CRLFOption=LFOnly 32 | BashTerminalOption=ConHost 33 | PerformanceTweaksFSCache=Enabled 34 | UseCredentialManager=Enabled 35 | UseCredentialManager=Enabled 36 | EnableSymlinks=Disabled 37 | EnalbedBuiltinInteractiveAdd=Disabled 38 | 39 | .PARAMETER DownloadOnly 40 | Switch parameter to specify you only want to download the installer 41 | 42 | .PARAMETER TryTLSv13 43 | Switch parameter that tells PowerShell to try download file using TLSv1.3. This seems to fail as of 3/28/2023 due to 1.3 being so new 44 | 45 | 46 | .EXAMPLE 47 | Install-GitForWindows 48 | # This example downloads the Git For Windows installer and verifies the checksum before installing it 49 | 50 | .EXAMPLE 51 | Install-GitForWindows -OutFile "$env:TEMP\git-for-windows-x64-bit.exe" 52 | # This example downloads the Git For Windows installer and verifies the checksum before installing it 53 | 54 | .EXAMPLE 55 | Install-GitForWindows -OutFile "$env:TEMP\git-for-windows-x64-bit.exe" -DownloadOnly 56 | # This example downloads the Git For Windows installer and verifies the checksum 57 | 58 | 59 | .NOTES 60 | Author: Robert H. Osborne 61 | Alias: tobor 62 | Contact: rosborne@osbornepro.com 63 | 64 | 65 | .LINK 66 | https://github.com/tobor88 67 | https://github.com/osbornepro 68 | https://www.powershellgallery.com/profiles/tobor 69 | https://osbornepro.com 70 | https://writeups.osbornepro.com 71 | https://encrypit.osbornepro.com 72 | https://btpssecpack.osbornepro.com 73 | https://www.powershellgallery.com/profiles/tobor 74 | https://www.hackthebox.eu/profile/52286 75 | https://www.linkedin.com/in/roberthosborne/ 76 | https://www.credly.com/users/roberthosborne/badges 77 | 78 | 79 | .INPUTS 80 | None 81 | 82 | 83 | .OUTPUTS 84 | System.Management.Automation.PSObject 85 | #> 86 | [OutputType([System.Management.Automation.PSObject])] 87 | [CmdletBinding()] 88 | param( 89 | [Parameter( 90 | Position=0, 91 | Mandatory=$False 92 | )] # End Parameter 93 | [ValidateScript({$_ -like "*.exe"})] 94 | [String]$OutFile = "$env:TEMP\git-for-windows-x64-bit.exe", 95 | 96 | [Parameter( 97 | Position=1, 98 | Mandatory=$False 99 | )] # End Parameter 100 | [ValidateScript({ ($_ -like "*.inf") -and (Test-Path -Path $_) })] 101 | [String]$InfFile, 102 | 103 | [Parameter( 104 | Mandatory=$False 105 | )] # End Parameter 106 | [Switch]$DownloadOnly, 107 | 108 | [Parameter( 109 | Mandatory=$False 110 | )] # End Parameter 111 | [Switch]$TryTLSv13 112 | ) # End param 113 | 114 | $TlsVersion = "TLSv1.2" 115 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 116 | If ($TryTLSv13.IsPresent) { 117 | 118 | $TlsVersion = "TLSv1.3" 119 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls13 120 | 121 | } # End If 122 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') utilizing $TlsVersion" 123 | 124 | $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 125 | $Uri = 'https://api.github.com/repos/git-for-windows/git/releases/latest' 126 | 127 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading Git for Windows from GitHub" 128 | Try { 129 | 130 | $GetLinks = Invoke-RestMethod -Uri $Uri -Method GET -UseBasicParsing -UserAgent $UserAgent -ContentType 'application/json; charset=utf-8' -Verbose:$False 131 | $DownloadLink = ($GetLinks | ForEach-Object { $_.Assets } | Where-Object -Property Name -like "*64-bit.exe").browser_download_url 132 | Invoke-WebRequest -Uri $DownloadLink -UseBasicParsing -UserAgent $UserAgent -OutFile $OutFile -Method GET -ContentType 'application/octet-stream' -Verbose:$False | Out-Null 133 | 134 | } Catch { 135 | 136 | Throw $Error[0] 137 | 138 | } # End Try Catch Catch 139 | 140 | $FileHash = (Get-FileHash -Path $OutFile -Algorithm SHA256).Hash.ToLower() 141 | $CheckSum = ($GetLinks.body.Split("`n") | Where-Object -FilterScript { $_ -like "*Git-*-64-bit.exe*" } | Out-String).Split(" ")[-1].Trim() 142 | 143 | If ($FileHash -eq $CheckSum) { 144 | 145 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully verified hash of newly downloaded file for Git for Windows" 146 | If ($DownloadOnly.IsPresent -and (Test-Path -Path $OutFile)) { 147 | 148 | Write-Output -InputObject "[*] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully downloaded file and verified hash.`n[i] File saved to $OutFile" 149 | 150 | } Else { 151 | 152 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Executing installation of Git for Windows" 153 | If ($PSBoundParameters.ContainsKey("InfFile")) { 154 | 155 | Start-Process -FilePath $OutFile -ArgumentList @('/SP-','/VERYSILENT', '/SUPPRESSMSGBOXES', '/NOCANCEL', '/NORESTART', '/CLOSEAPPLICATIONS', '/RESTARTAPPLICATIONS', '/LOADINF=`"$InfFile`"') -NoNewWindow -Wait -PassThru 156 | 157 | } Else { 158 | 159 | Start-Process -FilePath $OutFile -ArgumentList @('/SP-','/VERYSILENT', '/SUPPRESSMSGBOXES', '/NOCANCEL', '/NORESTART', '/CLOSEAPPLICATIONS', '/RESTARTAPPLICATIONS') -NoNewWindow -Wait -PassThru 160 | 161 | } # End If Else 162 | 163 | } # End If Else 164 | 165 | } Else { 166 | 167 | Throw "[x] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Failed to validate hash of newly downloaded file for Git for Windows" 168 | 169 | } # End If Else 170 | 171 | } # End Function Install-GitForWindows 172 | -------------------------------------------------------------------------------- /Install-KeePass.ps1: -------------------------------------------------------------------------------- 1 | Function Install-KeePass { 2 | <# 3 | .SYNOPSIS 4 | This cmdlet is used to install/update KeePass on a machine. It can also be used to simply download the installer 5 | 6 | 7 | .DESCRIPTION 8 | Download the lates KeePass installed for Windows, verify that hash and install the file 9 | 10 | 11 | .PARAMETER OutFile 12 | Define where to save the installer file. Default location is your Temp directory 13 | 14 | .PARAMETER DownloadOnly 15 | Switch parameter to specify you only want to download the installer 16 | 17 | .PARAMETER TryTLSv13 18 | Switch parameter that tells PowerShell to try download file using TLSv1.3. This seems to fail as of 3/28/2023 due to 1.3 being so new 19 | 20 | 21 | .EXAMPLE 22 | Install-KeePass 23 | # This example downloads the KeePass installer and verifies the checksum before installing it 24 | 25 | .EXAMPLE 26 | Install-KeePass -OutFile "$env:TEMP\KeePass-Setup.exe" 27 | # This example downloads the KeePass installer and verifies the checksum before installing it 28 | 29 | .EXAMPLE 30 | Install-KeePass -OutFile "$env:TEMP\KeePass-Setup.exe" -DownloadOnly 31 | # This example downloads the KeePass installer and verifies the checksum 32 | 33 | 34 | .NOTES 35 | Author: Robert H. Osborne 36 | Alias: tobor 37 | Contact: rosborne@osbornepro.com 38 | 39 | 40 | .LINK 41 | https://github.com/tobor88 42 | https://github.com/osbornepro 43 | https://www.powershellgallery.com/profiles/tobor 44 | https://osbornepro.com 45 | https://writeups.osbornepro.com 46 | https://encrypit.osbornepro.com 47 | https://btpssecpack.osbornepro.com 48 | https://www.powershellgallery.com/profiles/tobor 49 | https://www.hackthebox.eu/profile/52286 50 | https://www.linkedin.com/in/roberthosborne/ 51 | https://www.credly.com/users/roberthosborne/badges 52 | 53 | 54 | .INPUTS 55 | None 56 | 57 | 58 | .OUTPUTS 59 | System.Management.Automation.PSObject 60 | #> 61 | [OutputType([System.Management.Automation.PSObject])] 62 | [CmdletBinding()] 63 | param( 64 | [Parameter( 65 | Position=0, 66 | Mandatory=$False 67 | )] # End Parameter 68 | [ValidateScript({$_ -like "*.exe"})] 69 | [String]$OutFile = "$env:TEMP\KeePass-Setup.exe", 70 | 71 | [Parameter( 72 | Mandatory=$False)] # End Parameter 73 | [Switch]$DownloadOnly, 74 | 75 | [Parameter( 76 | Mandatory=$False)] # End Parameter 77 | [Switch]$TryTLSv13 78 | ) # End param 79 | 80 | $TlsVersion = "TLSv1.2" 81 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 82 | If ($TryTLSv13.IsPresent) { 83 | 84 | $TlsVersion = "TLSv1.3" 85 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls13 86 | 87 | } # End If 88 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') utilizing $TlsVersion" 89 | 90 | $DLUserAgebt = "wget" 91 | $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 92 | $DownloadPage = 'https://keepass.info/download.html' 93 | $CheckSumPage = 'https://keepass.info/integrity.html' 94 | 95 | Try { 96 | 97 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading KeePass" 98 | $Uri = ((Invoke-WebRequest -Uri $DownloadPage -UseBasicParsing -UserAgent $UserAgent -ContentType 'text/html' -Verbose:$False).Links | Where-Object -Property "OuterHTML" -like "','').Replace('','').Replace('','').Replace("SHA-256:","").Replace(" ","").Trim().ToLower() 112 | $CheckSum = $Hashes.Split([System.Environment]::NewLine) | Where-Object -FilterScript { $_ -like $FileHash } 113 | 114 | If ($CheckSum -eq $FileHash) { 115 | 116 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully verified hash of newly downloaded file for KeePass" 117 | If ($DownloadOnly.IsPresent -and (Test-Path -Path $OutFile)) { 118 | 119 | Write-Output -InputObject "[*] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully downloaded file and verified hash.`n[i] File saved to $OutFile" 120 | 121 | } Else { 122 | 123 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Executing installation of KeePass" 124 | Start-Process -FilePath $OutFile -ArgumentList @('/VERYSILENT') -NoNewWindow -Wait -PassThru 125 | 126 | } # End If Else 127 | 128 | } Else { 129 | 130 | Throw "[x] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Failed to validate hash of newly downloaded file for KeePass" 131 | 132 | } # End If Else 133 | 134 | } # End Function Install-KeePass 135 | -------------------------------------------------------------------------------- /Install-NodeJS.ps1: -------------------------------------------------------------------------------- 1 | Function Install-NodeJS { 2 | <# 3 | .SYNOPSIS 4 | This cmdlet is used to install/update NodeJS for Windows. It can also be used to simply download the installer 5 | 6 | 7 | .DESCRIPTION 8 | Download the latest NodeJS installed for Windows, verify the checksum and install the file 9 | 10 | 11 | .PARAMETER OutFile 12 | Define where to save the installer file. Default location is your Temp directory 13 | 14 | .PARAMETER DownloadOnly 15 | Switch parameter to specify you only want to download the installer 16 | 17 | .PARAMETER TryTLSv13 18 | Switch parameter that tells PowerShell to try download file using TLSv1.3. This seems to fail as of 7/5/2023 due to 1.3 being so new 19 | 20 | 21 | .EXAMPLE 22 | Install-NodeJS 23 | # This example downloads the NodeJS installer and verifies the checksum before installing it 24 | 25 | .EXAMPLE 26 | Install-NodeJS -OutFile "$env:TEMP\NodeJS-Installer.exe" 27 | # This example downloads the NodeJS installer and verifies the checksum before installing it 28 | 29 | .EXAMPLE 30 | Install-NodeJS -OutFile "$env:TEMP\NodeJS-Installer.exe" -DownloadOnly 31 | # This example downloads the NodeJS installer and verifies the checksum 32 | 33 | 34 | .NOTES 35 | Author: Robert H. Osborne 36 | Alias: tobor 37 | Contact: rosborne@osbornepro.com 38 | 39 | 40 | .LINK 41 | https://github.com/tobor88 42 | https://github.com/osbornepro 43 | https://www.powershellgallery.com/profiles/tobor 44 | https://osbornepro.com 45 | https://writeups.osbornepro.com 46 | https://encrypit.osbornepro.com 47 | https://btpssecpack.osbornepro.com 48 | https://www.powershellgallery.com/profiles/tobor 49 | https://www.hackthebox.eu/profile/52286 50 | https://www.linkedin.com/in/roberthosborne/ 51 | https://www.credly.com/users/roberthosborne/badges 52 | 53 | 54 | .INPUTS 55 | None 56 | 57 | 58 | .OUTPUTS 59 | System.Management.Automation.PSObject 60 | #> 61 | [OutputType([System.Management.Automation.PSObject])] 62 | [CmdletBinding()] 63 | param( 64 | [Parameter( 65 | Position=0, 66 | Mandatory=$False 67 | )] # End Parameter 68 | [ValidateScript({$_ -like "*.msi"})] 69 | [String]$OutFile = "$env:TEMP\node-installer.msi", 70 | 71 | [Parameter( 72 | Position=1, 73 | Mandatory=$False 74 | )] # End Parameter 75 | [ValidateSet("86", "64")] 76 | [String]$Architecture = $(If ($env:PROCESSOR_ARCHITECTURE -like "AMD64") { "64" } Else { "86" }), 77 | 78 | [Parameter( 79 | Mandatory=$False 80 | )] # End Parameter 81 | [Switch]$DownloadOnly 82 | ) # End param 83 | 84 | $TlsVersion = "TLSv1.2" 85 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 86 | If ($TryTLSv13.IsPresent) { 87 | 88 | $TlsVersion = "TLSv1.3" 89 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls13 90 | 91 | } # End If 92 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') utilizing $TlsVersion" 93 | 94 | $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 95 | $Uri = "https://api.github.com/repos/nodejs/node/releases/latest" 96 | 97 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading Node.JS from GitHub" 98 | Try { 99 | 100 | $GetLinks = Invoke-RestMethod -Uri $Uri -Method GET -UseBasicParsing -UserAgent $UserAgent -Verbose:$False 101 | $DownloadLink = "https://nodejs.org/dist/$($GetLinks.tag_name)/node-$($GetLinks.tag_name)-x64.msi" 102 | $CheckSumLink = "https://nodejs.org/dist/$($GetLinks.tag_name)/SHASUMS256.txt" 103 | Invoke-WebRequest -Uri $DownloadLink -UseBasicParsing -UserAgent $UserAgent -OutFile $OutFile -Method GET -Verbose:$False | Out-Null 104 | 105 | } Catch { 106 | 107 | Throw $Error[0] 108 | 109 | } # End Try Catch Catch 110 | 111 | $FileHash = (Get-FileHash -Path $OutFile -Algorithm SHA256 -Verbose:$False).Hash.ToLower() 112 | $CheckSum = ((Invoke-WebRequest -Uri $CheckSumLink -Method GET -UseBasicParsing -UserAgent $UserAgent -Verbose:$False).RawContent.Split("`n") | Where-Object -FilterScript { $_ -like "*node-$($GetLinks.tag_name)-x64.msi" }).Split(' ')[0] 113 | 114 | If ($FileHash -eq $CheckSum) { 115 | 116 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully verified hash of newly downloaded file for Node.JS" 117 | If ($DownloadOnly.IsPresent -and (Test-Path -Path $OutFile)) { 118 | 119 | Write-Output -InputObject "[*] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully downloaded file and verified hash.`n[i] File saved to $OutFile" 120 | 121 | } Else { 122 | 123 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Executing installation of Node.JS" 124 | If (Test-Path -Path $OutFile) { 125 | 126 | Start-Process -FilePath "C:\Windows\System32\msiexec.exe" -ArgumentList @('/a', "$OutFile", '/quiet') -NoNewWindow -Wait -PassThru -ErrorAction Stop 127 | 128 | } Else { 129 | 130 | Throw "[x] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Failed to download file" 131 | 132 | } # End If Else 133 | 134 | } # End If Else 135 | 136 | } Else { 137 | 138 | Throw "[x] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Failed to validate hash of newly downloaded file for Node.JS" 139 | 140 | } # End If Else 141 | 142 | } # End Function Install-NodeJS 143 | -------------------------------------------------------------------------------- /Install-NotepadPlusPlus.ps1: -------------------------------------------------------------------------------- 1 | Function Install-NotepadPlusPlus { 2 | <# 3 | .SYNOPSIS 4 | This cmdlet is used to install/update Notepad++ on a machine. It can also be used to simply download the installer 5 | 6 | 7 | .DESCRIPTION 8 | Download the lates Notepad++ installed for Windows, verify that hash and instal the file 9 | 10 | 11 | .PARAMETER OutFile 12 | Define where to save the installer file. Default location is your Temp directory 13 | 14 | .PARAMETER DownloadOnly 15 | Switch parameter to specify you only want to download the installer 16 | 17 | .PARAMETER TryTLSv13 18 | Switch parameter that tells PowerShell to try download file using TLSv1.3. This seems to fail as of 3/28/2023 due to 1.3 being so new 19 | 20 | 21 | .EXAMPLE 22 | Install-NotepadPlusPlus 23 | # This example downloads the Notepad++ installer and verifies the checksum before installing it 24 | 25 | .EXAMPLE 26 | Install-NotepadPlusPlus -OutFile "$env:TEMP\npp.latest.Installer.x64.exe" 27 | # This example downloads the Notepad++ installer and verifies the checksum before installing it 28 | 29 | .EXAMPLE 30 | Install-NotepadPlusPlus -OutFile "$env:TEMP\npp.latest.Installer.x64.exe" -DownloadOnly 31 | # This example downloads the Notepad++ installer and verifies the checksum 32 | 33 | 34 | .NOTES 35 | Author: Robert H. Osborne 36 | Alias: tobor 37 | Contact: rosborne@osbornepro.com 38 | 39 | 40 | .LINK 41 | https://github.com/tobor88 42 | https://github.com/osbornepro 43 | https://www.powershellgallery.com/profiles/tobor 44 | https://osbornepro.com 45 | https://writeups.osbornepro.com 46 | https://encrypit.osbornepro.com 47 | https://btpssecpack.osbornepro.com 48 | https://www.powershellgallery.com/profiles/tobor 49 | https://www.hackthebox.eu/profile/52286 50 | https://www.linkedin.com/in/roberthosborne/ 51 | https://www.credly.com/users/roberthosborne/badges 52 | 53 | 54 | .INPUTS 55 | None 56 | 57 | 58 | .OUTPUTS 59 | System.Management.Automation.PSObject 60 | #> 61 | [OutputType([System.Management.Automation.PSObject])] 62 | [CmdletBinding()] 63 | param( 64 | [Parameter( 65 | Position=0, 66 | Mandatory=$False 67 | )] # End Parameter 68 | [ValidateScript({$_ -like "*.exe"})] 69 | [String]$OutFile = "$env:TEMP\npp.latest.Installer.x64.exe", 70 | 71 | [Parameter( 72 | Mandatory=$False 73 | )] # End Parameter 74 | [Switch]$DownloadOnly, 75 | 76 | [Parameter( 77 | Mandatory=$False 78 | )] # End Parameter 79 | [Switch]$TryTLSv13 80 | ) # End param 81 | 82 | $TlsVersion = "TLSv1.2" 83 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 84 | If ($TryTLSv13.IsPresent) { 85 | 86 | $TlsVersion = "TLSv1.3" 87 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls13 88 | 89 | } # End If 90 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') utilizing $TlsVersion" 91 | 92 | $Uri = 'https://api.github.com/repos/notepad-plus-plus/notepad-plus-plus/releases/latest' 93 | $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 94 | 95 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading Notepad++ from GitHub" 96 | Try { 97 | 98 | $GetLinks = Invoke-RestMethod -Uri $Uri -Method GET -UseBasicParsing -UserAgent $UserAgent -ContentType 'application/json; charset=utf-8' -Verbose:$False 99 | $DownloadLink = ($GetLinks.assets | Where-Object -Property Name -like "npp.*.Installer.x64.exe").browser_download_url 100 | Invoke-WebRequest -Uri $DownloadLink -UseBasicParsing -UserAgent $UserAgent -OutFile $OutFile -Verbose:$False | Out-Null 101 | 102 | } Catch { 103 | 104 | Throw $Error[0] 105 | 106 | } # End Try Catch Catch 107 | 108 | $FileHash = (Get-FileHash -Path $OutFile -Algorithm SHA256).Hash.ToLower() 109 | $CheckSum = ($GetLinks.body.Split(" ") | Where-Object -FilterScript { $_ -like "*$FileHash*" } | Out-String).Trim().ToLower().Split("`n")[-1] 110 | 111 | If ($FileHash -eq $CheckSum) { 112 | 113 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully verified hash of newly downloaded file for Notepad++" 114 | If ($DownloadOnly.IsPresent -and (Test-Path -Path $OutFile)) { 115 | 116 | Write-Output -InputObject "[*] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully downloaded file and verified hash.`n[i] File saved to $OutFile" 117 | 118 | } Else { 119 | 120 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Executing installation of Notepad++" 121 | Start-Process -FilePath $OutFile -ArgumentList @('/S') -NoNewWindow -Wait -PassThru 122 | 123 | } # End If Else 124 | 125 | } Else { 126 | 127 | Throw "[x] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Failed to validate hash of newly downloaded file for Notepad++" 128 | 129 | } # End If Else 130 | 131 | } # End Function Install-NotepadPlusPlus 132 | -------------------------------------------------------------------------------- /Install-PowerShellCore.ps1: -------------------------------------------------------------------------------- 1 | Function Install-PowerShellCore { 2 | <# 3 | .SYNOPSIS 4 | This cmdlet is used to install/update PowerShell Core on a machine. It can also be used to simply download the installer 5 | 6 | 7 | .DESCRIPTION 8 | Download the lates PowerShell Core installed for Windows, verify that hash and install the file 9 | 10 | 11 | .PARAMETER OutFile 12 | Define where to save the installer file. Default location is your Temp directory 13 | 14 | .PARAMETER DownloadOnly 15 | Switch parameter to specify you only want to download the installer 16 | 17 | .PARAMETER TryTLSv13 18 | Switch parameter that tells PowerShell to try download file using TLSv1.3. This seems to fail as of 3/28/2023 due to 1.3 being so new 19 | 20 | 21 | .EXAMPLE 22 | Install-PowerShellCore 23 | # This example downloads the PowerShell Core installer and verifies the checksum before installing it 24 | 25 | .EXAMPLE 26 | Install-PowerShellCore -OutFile "$env:TEMP\PowerShell-version-win-x64.msi" 27 | # This example downloads the PowerShell Core installer and verifies the checksum before installing it 28 | 29 | .EXAMPLE 30 | Install-PowerShellCore -OutFile "$env:TEMP\PowerShell-version-win-x64.msi" -DownloadOnly 31 | # This example downloads the FileZilla installer and verifies the checksum 32 | 33 | 34 | .NOTES 35 | Author: Robert H. Osborne 36 | Alias: tobor 37 | Contact: rosborne@osbornepro.com 38 | 39 | 40 | .LINK 41 | https://github.com/tobor88 42 | https://github.com/osbornepro 43 | https://www.powershellgallery.com/profiles/tobor 44 | https://osbornepro.com 45 | https://writeups.osbornepro.com 46 | https://encrypit.osbornepro.com 47 | https://btpssecpack.osbornepro.com 48 | https://www.powershellgallery.com/profiles/tobor 49 | https://www.hackthebox.eu/profile/52286 50 | https://www.linkedin.com/in/roberthosborne/ 51 | https://www.credly.com/users/roberthosborne/badges 52 | 53 | 54 | .INPUTS 55 | None 56 | 57 | 58 | .OUTPUTS 59 | System.Management.Automation.PSObject 60 | #> 61 | [OutputType([System.Management.Automation.PSObject])] 62 | [CmdletBinding()] 63 | param( 64 | [Parameter( 65 | Position=0, 66 | Mandatory=$False 67 | )] # End Parameter 68 | [ValidateScript({$_ -like "*.msi"})] 69 | [String]$OutFile = "$env:TEMP\PowerShell-version-win-x64.msi", 70 | 71 | [Parameter( 72 | Mandatory=$False 73 | )] # End Parameter 74 | [Switch]$DownloadOnly, 75 | 76 | [Parameter( 77 | Mandatory=$False 78 | )] # End Parameter 79 | [Switch]$TryTLSv13 80 | ) # End param 81 | 82 | $TlsVersion = "TLSv1.2" 83 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 84 | If ($TryTLSv13.IsPresent) { 85 | 86 | $TlsVersion = "TLSv1.3" 87 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls13 88 | 89 | } # End If 90 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') utilizing $TlsVersion" 91 | 92 | $Uri = 'https://api.github.com/repos/PowerShell/PowerShell/releases/latest' 93 | $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 94 | 95 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading PowerShell Core from GitHub" 96 | Try { 97 | 98 | $GetLinks = Invoke-RestMethod -Uri $Uri -Method GET -UseBasicParsing -UserAgent $UserAgent -ContentType 'application/json; charset=utf-8' -Verbose:$False 99 | $DownloadLink = ($GetLinks.assets | Where-Object -Property Name -like "*PowerShell-*-win-x64.msi").browser_download_url 100 | Invoke-WebRequest -Uri $DownloadLink -UseBasicParsing -UserAgent $UserAgent -OutFile $OutFile -Method GET -ContentType 'application/octet-stream' -Verbose:$False | Out-Null 101 | 102 | } Catch { 103 | 104 | Throw $Error[0] 105 | 106 | } # End Try Catch Catch 107 | 108 | $FileHash = (Get-FileHash -Path $OutFile -Algorithm SHA256).Hash.ToLower() 109 | $CheckSum = ($GetLinks.body.Split("-") | Where-Object -FilterScript { $_ -like "*$FileHash*" } | Out-String).Trim().ToLower() 110 | 111 | If ($FileHash -eq $CheckSum) { 112 | 113 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully verified hash of newly downloaded file for PowerShell Core" 114 | If ($DownloadOnly.IsPresent -and (Test-Path -Path $OutFile)) { 115 | 116 | Write-Output -InputObject "[*] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully downloaded file and verified hash.`n[i] File saved to $OutFile" 117 | 118 | } Else { 119 | 120 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Executing installation of PowerShell Core" 121 | Start-Process -FilePath "C:\Windows\System32\msiexec.exe" -ArgumentList @('/i', "$OutFile", '/quiet') -NoNewWindow -Wait -PassThru 122 | 123 | } # End If Else 124 | 125 | } Else { 126 | 127 | Throw "[x] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Failed to validate hash of newly downloaded file for PowerShell Core" 128 | 129 | } # End If Else 130 | 131 | } # End Function Install-PowerShellCore 132 | -------------------------------------------------------------------------------- /Install-Putty.ps1: -------------------------------------------------------------------------------- 1 | Function Install-Putty { 2 | <# 3 | .SYNOPSIS 4 | This cmdlet is used to install/update Putty for Windows. It can also be used to simply download the installer 5 | 6 | 7 | .DESCRIPTION 8 | Download the lates Putty installed for Windows, verify that hash and install the file 9 | 10 | 11 | .PARAMETER OutFile 12 | Define where to save the installer file. Default location is your Temp directory 13 | 14 | .PARAMETER DownloadOnly 15 | Switch parameter to specify you only want to download the installer 16 | 17 | .PARAMETER TryTLSv13 18 | Switch parameter that tells PowerShell to try download file using TLSv1.3. This seems to fail as of 3/28/2023 due to 1.3 being so new 19 | 20 | 21 | .EXAMPLE 22 | Install-Putty 23 | # This example downloads the Signal installer and verifies the checksum before installing it 24 | 25 | .EXAMPLE 26 | Install-Putty -OutFile "$env:TEMP\putty-installer.msi" 27 | # This example downloads the Signal installer and verifies the checksum before installing it 28 | 29 | .EXAMPLE 30 | Install-Putty -OutFile "$env:TEMP\putty-installer.exe" -DownloadOnly 31 | # This example downloads the Signal installer and verifies the checksum 32 | 33 | 34 | .NOTES 35 | Author: Robert H. Osborne 36 | Alias: tobor 37 | Contact: rosborne@osbornepro.com 38 | 39 | 40 | .LINK 41 | https://github.com/tobor88 42 | https://gitlab.com/tobor88 43 | https://github.com/osbornepro 44 | https://www.powershellgallery.com/profiles/tobor 45 | https://osbornepro.com 46 | https://writeups.osbornepro.com 47 | https://encrypit.osbornepro.com 48 | https://btpssecpack.osbornepro.com 49 | https://www.powershellgallery.com/profiles/tobor 50 | https://www.hackthebox.eu/profile/52286 51 | https://www.linkedin.com/in/roberthosborne/ 52 | https://www.credly.com/users/roberthosborne/badges 53 | 54 | 55 | .INPUTS 56 | None 57 | 58 | 59 | .OUTPUTS 60 | System.Management.Automation.PSObject 61 | #> 62 | [OutputType([System.Management.Automation.PSObject])] 63 | [CmdletBinding(DefaultParameterSetName="Installer")] 64 | param( 65 | [Parameter( 66 | ParameterSetName="Installer", 67 | Position=0, 68 | Mandatory=$False 69 | )] # End Parameter 70 | [ValidateScript({$_ -like "*.msi"})] 71 | [String]$OutFile = "$env:TEMP\putty-installer.msi", 72 | 73 | [Parameter( 74 | ParameterSetName="Portable", 75 | Position=0, 76 | Mandatory=$False 77 | )] # End Parameter 78 | [ValidateScript({$_ -like "*.exe"})] 79 | [String]$FilePath = "$env:TEMP\putty.exe", 80 | 81 | [Parameter( 82 | Position=1, 83 | Mandatory=$False 84 | )] # End Parameter 85 | [ValidateSet('32','64','arm64')] 86 | [String]$Architecture = "64", 87 | 88 | [Parameter( 89 | ParameterSetName="Portable", 90 | Mandatory=$False 91 | )] # End Parameter 92 | [Switch]$DownloadPortable, 93 | 94 | [Parameter( 95 | Mandatory=$False 96 | )] # End Parameter 97 | [Switch]$TryTLSv13 98 | ) # End param 99 | 100 | $TlsVersion = "TLSv1.2" 101 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 102 | If ($TryTLSv13.IsPresent) { 103 | 104 | $TlsVersion = "TLSv1.3" 105 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls13 106 | 107 | } # End If 108 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') utilizing $TlsVersion" 109 | 110 | $MainUrl = "https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html" 111 | $CheckSumLink = "https://the.earth.li/~sgtatham/putty/latest/sha256sums" 112 | $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 113 | 114 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Obtaining latest version information for Putty" 115 | $Version = (Invoke-RestMethod -UseBasicParsing -Uri $MainUrl -Method GET -UserAgent $UserAgent -ContentType 'text/html' -Verbose:$False).Split("`n")[2].Split('(')[-1].Split(')')[0] 116 | 117 | Write-Debug -Message "[d] ParameterSetName: $($PSCmdlet.ParameterSetName)" 118 | Switch ($Architecture) { 119 | 120 | '32' { 121 | 122 | If ($PSCmdlet.ParameterSetName -eq "Portable") { 123 | 124 | $Uri = "https://the.earth.li/~sgtatham/putty/latest/w$($Architecture)/putty.exe" 125 | $Path = $FilePath 126 | 127 | } Else { 128 | 129 | $Uri = "https://the.earth.li/~sgtatham/putty/latest/w$($Architecture)/putty-$($Version)-installer.msi" 130 | $Path = $OutFile 131 | 132 | } # End If Else 133 | 134 | } '64' { 135 | 136 | If ($PSCmdlet.ParameterSetName -eq "Portable") { 137 | 138 | $Uri = "https://the.earth.li/~sgtatham/putty/latest/w$($Architecture)/putty.exe" 139 | $Path = $FilePath 140 | 141 | } Else { 142 | 143 | $Uri = "https://the.earth.li/~sgtatham/putty/latest/w$($Architecture)/putty-$($Architecture)bit-$($Version)-installer.msi" 144 | $Path = $OutFile 145 | 146 | } # End If Else 147 | 148 | } 'arm64' { 149 | 150 | If ($PSCmdlet.ParameterSetName -eq "Portable") { 151 | 152 | $Uri = "https://the.earth.li/~sgtatham/putty/latest/wa64/putty.exe" 153 | $Path = $FilePath 154 | 155 | } Else { 156 | 157 | $Uri = "https://the.earth.li/~sgtatham/putty/latest/wa64/putty-$($Architecture)-$($Version)-installer.msi" 158 | $Path = $OutFile 159 | 160 | } # End If Else 161 | 162 | } # End Switch Options 163 | 164 | } # End Switch 165 | 166 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Obtaining checksums for Putty" 167 | $CheckSumList = ((Invoke-RestMethod -UseBasicParsing -Uri $CheckSumLink -Method GET -UserAgent $UserAgent -ContentType 'text/html' -Verbose:$False).Split(' ').Split("`n") | ForEach-Object { If ($_.Length -eq 64) { $_ } }).Trim() 168 | 169 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading Putty" 170 | Invoke-WebRequest -UseBasicParsing -Uri $Uri -UserAgent $UserAgent -OutFile $Path -ContentType 'application/octet-stream' -Verbose:$False | Out-Null 171 | $CheckSumValue = (Get-FileHash -Path $Path -Algorithm SHA256 -Verbose:$False).Hash.ToLower() 172 | 173 | If ($CheckSumList -contains $CheckSumValue) { 174 | 175 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully verified hash of newly downloaded file for Putty" 176 | If ($DownloadPortable.IsPresent -and (Test-Path -Path $Path)) { 177 | 178 | Write-Output -InputObject "[*] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully downloaded file and verified hash.`n[i] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') File saved to $Path" 179 | 180 | } Else { 181 | 182 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Executing installation of Putty version $Version" 183 | Start-Process -FilePath "C:\Windows\System32\msiexec.exe" -ArgumentList @("/i", $Path, "/qn", "ALLUSERS=1") -NoNewWindow -Wait -PassThru -ErrorAction Stop 184 | 185 | } # End If Else 186 | 187 | } Else { 188 | 189 | Throw "[x] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Failed to validate checksum of the downloaded file $Path" 190 | 191 | } # End If Else 192 | 193 | } # End Function Install-Putty 194 | -------------------------------------------------------------------------------- /Install-RemoteDesktopManager.ps1: -------------------------------------------------------------------------------- 1 | Function Install-RemoteDesktopManager { 2 | <# 3 | .SYNOPSIS 4 | This cmdlet is used to install/update Remote Desktop Manager for Windows on a machine. It can also be used to simply download the installer 5 | 6 | 7 | .DESCRIPTION 8 | Download the lates Remote Desktop Manager installed for Windows, verify that hash and install the file 9 | 10 | 11 | .PARAMETER OutFile 12 | Define where to save the installer file. Default location is your Temp directory 13 | 14 | .PARAMETER DownloadOnly 15 | Switch parameter to specify you only want to download the installer 16 | 17 | .PARAMETER TryTLSv13 18 | Switch parameter that tells PowerShell to try download file using TLSv1.3. This seems to fail as of 8/9/2023 due to 1.3 being so new 19 | 20 | 21 | .EXAMPLE 22 | Install-RemoteDesktopManager 23 | # This example downloads the RemoteDesktopManager installer and verifies the checksum before installing it 24 | 25 | .EXAMPLE 26 | Install-RemoteDesktopManager -OutFile "$env:TEMP\RemoteDesktopManager-Installer.exe" 27 | # This example downloads the Remote Desktop Manager installer and verifies the checksum before installing it 28 | 29 | .EXAMPLE 30 | Install-RemoteDesktopManager -OutFile "$env:TEMP\RemoteDesktopManager-Installer.exe" -DownloadOnly 31 | # This example downloads the Remote Desktop Manager installer and verifies the checksum 32 | 33 | 34 | .NOTES 35 | Author: Robert H. Osborne 36 | Alias: tobor 37 | Contact: rosborne@osbornepro.com 38 | 39 | 40 | .LINK 41 | https://github.com/tobor88 42 | https://github.com/osbornepro 43 | https://www.powershellgallery.com/profiles/tobor 44 | https://osbornepro.com 45 | https://writeups.osbornepro.com 46 | https://encrypit.osbornepro.com 47 | https://btpssecpack.osbornepro.com 48 | https://www.powershellgallery.com/profiles/tobor 49 | https://www.hackthebox.eu/profile/52286 50 | https://www.linkedin.com/in/roberthosborne/ 51 | https://www.credly.com/users/roberthosborne/badges 52 | 53 | 54 | .INPUTS 55 | None 56 | 57 | 58 | .OUTPUTS 59 | System.Management.Automation.PSObject 60 | #> 61 | [OutputType([System.Management.Automation.PSObject])] 62 | [CmdletBinding()] 63 | param( 64 | [Parameter( 65 | Position=0, 66 | Mandatory=$False 67 | )] # End Parameter 68 | [ValidateScript({$_ -like "*.exe"})] 69 | [String]$OutFile = "$env:TEMP\RemoteDesktopManager-installer.exe", 70 | 71 | [Parameter( 72 | Mandatory=$False 73 | )] # End Parameter 74 | [Switch]$DownloadOnly, 75 | 76 | [Parameter( 77 | Mandatory=$False 78 | )] # End Parameter 79 | [Switch]$TryTLSv13 80 | ) # End param 81 | 82 | $TlsVersion = "TLSv1.2" 83 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 84 | If ($TryTLSv13.IsPresent) { 85 | 86 | $TlsVersion = "TLSv1.3" 87 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls13 88 | 89 | } # End If 90 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') utilizing $TlsVersion" 91 | 92 | $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 93 | $VersionUri = "https://devolutions.net/remote-desktop-manager/home/download/" 94 | $Version = (((Invoke-WebRequest -UseBasicParsing -Uri $VersionUri -Method GET -UserAgent $UserAgent -ContentType 'text/html' -Verbose:$False).Content.Split("`n") | Select-String -Pattern "data-g-version=")[0] | Out-String).Trim().Split('"')[1] 95 | $Uri = "https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.$($Version).exe" 96 | 97 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading RemoteDesktopManager" 98 | Invoke-WebRequest -UseBasicParsing -Method GET -Uri $Uri -OutFile $OutFile -UserAgent $UserAgent -ContentType 'application/octet-stream' -Verbose:$False | Out-Null 99 | 100 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Getting hash values for RemoteDesktopManager" 101 | #$FileHash = (Get-FileHash -Path $OutFile -Algorithm SHA512).Hash.ToLower() 102 | 103 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully verified hash of newly downloaded file for Remote Desktop Manager version $Version" 104 | If ($DownloadOnly.IsPresent -and (Test-Path -Path $OutFile)) { 105 | 106 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully downloaded file and verified hash: $OutFile" 107 | 108 | } Else { 109 | 110 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Executing installation of Remote Desktop Manager version $Version" 111 | Start-Process -FilePath $OutFile -ArgumentList @('/S') -NoNewWindow -Wait -PassThru 112 | 113 | } # End If Else 114 | 115 | } # End Function Install-RemoteDesktopManager 116 | -------------------------------------------------------------------------------- /Install-SSMS.ps1: -------------------------------------------------------------------------------- 1 | Function Install-SSMS { 2 | <# 3 | .SYNOPSIS 4 | This cmdlet is used to install/update SQL Server Management Studio (SSMS) on a Windows machine. It can also be used to simply download the installer 5 | 6 | 7 | .DESCRIPTION 8 | Download the lates SQL Server Management Studio and install for Windows 9 | 10 | 11 | .PARAMETER OutFile 12 | Define where to save the installer file. Default location is your Temp directory 13 | 14 | .PARAMETER DownloadOnly 15 | Switch parameter to specify you only want to download the installer 16 | 17 | .PARAMETER TryTLSv13 18 | Switch parameter that tells PowerShell to try download file using TLSv1.3. This seems to fail as of 8/9/2023 due to 1.3 being so new 19 | 20 | 21 | .EXAMPLE 22 | Install-SSMS 23 | # This example downloads the SSMS installer and installs it 24 | 25 | .EXAMPLE 26 | Install-SSMS -OutFile "$env:TEMP\SSMS-installer.exe" 27 | # This example downloads the SSMS installer and installs it 28 | 29 | .EXAMPLE 30 | Install-SSMS -OutFile "$env:TEMP\SSMS-installer.exe" -DownloadOnly 31 | # This example downloads the SSMS installer 32 | 33 | 34 | .NOTES 35 | Author: Robert H. Osborne 36 | Alias: tobor 37 | Contact: rosborne@osbornepro.com 38 | 39 | 40 | .LINK 41 | https://github.com/tobor88 42 | https://github.com/osbornepro 43 | https://www.powershellgallery.com/profiles/tobor 44 | https://osbornepro.com 45 | https://writeups.osbornepro.com 46 | https://encrypit.osbornepro.com 47 | https://btpssecpack.osbornepro.com 48 | https://www.powershellgallery.com/profiles/tobor 49 | https://www.hackthebox.eu/profile/52286 50 | https://www.linkedin.com/in/roberthosborne/ 51 | https://www.credly.com/users/roberthosborne/badges 52 | 53 | 54 | .INPUTS 55 | None 56 | 57 | 58 | .OUTPUTS 59 | System.Management.Automation.PSObject 60 | #> 61 | [OutputType([System.Management.Automation.PSObject])] 62 | [CmdletBinding()] 63 | param( 64 | [Parameter( 65 | Position=0, 66 | Mandatory=$False 67 | )] # End Parameter 68 | [ValidateScript({$_ -like "*.exe"})] 69 | [String]$OutFile = "$env:TEMP\SSMS-installer.exe", 70 | 71 | [Parameter( 72 | Mandatory=$False 73 | )] # End Parameter 74 | [Switch]$DownloadOnly, 75 | 76 | [Parameter( 77 | Mandatory=$False 78 | )] # End Parameter 79 | [Switch]$TryTLSv13 80 | ) # End param 81 | 82 | $TlsVersion = "TLSv1.2" 83 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 84 | If ($TryTLSv13.IsPresent) { 85 | 86 | $TlsVersion = "TLSv1.3" 87 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls13 88 | 89 | } # End If 90 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') utilizing $TlsVersion" 91 | 92 | $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 93 | $Uri = 'https://aka.ms/ssmsfullsetup' 94 | 95 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading SSMS from Microsoft" 96 | Invoke-WebRequest -UseBasicParsing -Uri $Uri -OutFile $OutFile -ContentType 'application/octet-stream' -Verbose:$False | Out-Null 97 | 98 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Getting hash values for SSMS" 99 | $Version = (Get-Item -Path $OutFile).VersionInfo.FileVersion 100 | #$FileHash = (Get-FileHash -Path $OutFile -Algorithm SHA512).Hash.ToLower() 101 | 102 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully verified hash of newly downloaded file for SSMS version $Version" 103 | If ($DownloadOnly.IsPresent -and (Test-Path -Path $OutFile)) { 104 | 105 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully downloaded file: $OutFile" 106 | 107 | } Else { 108 | 109 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Executing installation of SSMS version $Version" 110 | Start-Process -FilePath $OutFile -ArgumentList "/Install /Quiet" -NoNewWindow -Wait -PassThru 111 | 112 | } # End If Else 113 | 114 | } # End Function Install-SSMS 115 | -------------------------------------------------------------------------------- /Install-SccmAgent.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This cmdlet is used to install the SCCM Agent or Reinstall the SCCM agent on a local machine 4 | 5 | 6 | .DESCRIPTION 7 | Install the SCCM agent or reinstall the SCCM agent. This will require you to have a location to install the ccmsetup.exe file from 8 | 9 | 10 | .PARAMETER FilePath 11 | Set the aboslute path to the ccmsetup.exe file you want to use to install the SCCM Agent 12 | 13 | .PARAMETER SiteCode 14 | Define the Site Code for your SCCM server that should be used during the ccmsetup.exe installation 15 | 16 | .PARAMETER Destination 17 | Define the destination directory to save your ccmsetup.exe file too 18 | 19 | .PARAMETER ReInstall 20 | Set this parameter when you want to reinstall the SCCM Agent locally on a machine 21 | 22 | 23 | .EXAMPLE 24 | Install-SccmAgent -FilePath \\sccmserver\D$\Installer\ccmsetup.exe -Destination $env:TEMP -SiteCode OBP 25 | # This example copies ccmsetup.exe to your users temp directory and install the SCCM Agent using site code OBP 26 | 27 | .EXAMPLE 28 | Install-SccmAgent -FilePath \\sccmserver\D$\Installer\ccmsetup.exe -SiteCode OBP -ReInstall 29 | # This example copies ccmsetup.exe to your Downloads directory and uninstalls, waits 15 minutes then reinstalls the SCCM agent using site code OBP 30 | 31 | 32 | .INPUTS 33 | None 34 | 35 | 36 | .OUTPUTS 37 | None 38 | 39 | 40 | .NOTES 41 | Author: Robert H. Osborne 42 | Alias: tobor 43 | Contact: rosborne@osbornepro.com 44 | 45 | 46 | .LINK 47 | https://github.com/tobor88 48 | https://github.com/OsbornePro 49 | https://www.powershellgallery.com/profiles/tobor 50 | https://osbornepro.com 51 | https://writeups.osbornepro.com 52 | https://btpssecpack.osbornepro.com 53 | https://www.powershellgallery.com/profiles/tobor 54 | https://www.hackthebox.eu/profile/52286 55 | https://www.linkedin.com/in/roberthosborne/ 56 | https://www.credly.com/users/roberthosborne/badges 57 | #> 58 | Function Install-SccmAgent { 59 | [CmdletBinding()] 60 | param( 61 | [Parameter( 62 | Position=0, 63 | Mandatory=$True, 64 | ValueFromPipeline=$False, 65 | HelpMessage="Enter the absolute path to the ccmsetup.exe file you wish to install. EXAMPLE: C:\Temp\ccmsetup.exe : " 66 | )] # End Parameter 67 | [ValidateScript({[System.IO.File]::Exists($_)})] 68 | [String]$FilePath, 69 | 70 | [Parameter( 71 | Position=1, 72 | Mandatory=$True, 73 | ValueFromPipeline=$False, 74 | HelpMessage="Enter the site code to use when install the ccmsetup.exe file EXAMPLE: ABC : " 75 | )] # End Parameter 76 | [String]$SiteCode, 77 | 78 | [Parameter( 79 | Position=2, 80 | Mandatory=$False, 81 | ValueFromPipeline=$False, 82 | HelpMessage="Enter the absolute path to the directory you wish to copy ccmsetup.exe too. EXAMPLE: C:\Temp : " 83 | )] # End Parameter 84 | [ValidateScript({[System.IO.Directory]::Exists($_)})] 85 | [String]$Destination = "$env:USERPROFILE\Downloads", 86 | 87 | [Parameter( 88 | Mandatory=$False 89 | )] # End Parameter 90 | [Switch][Bool]$ReInstall 91 | ) # End param 92 | 93 | Write-Verbose "Copying installation file to $env:COMPUTERNAME" 94 | $FileName = $FilePath.Split("\")[-1] 95 | $Source = $FilePath.Replace("\$($FileName)","") 96 | 97 | robocopy $Source $Destination $FileName 98 | 99 | If ($ReInstall.IsPresent) { 100 | 101 | Write-Verbose "Uninstalling the SCCM Agent on $env:COMPUTERNAME" 102 | Start-Process -FilePath "$Destination\ccmsetup.exe" -ArgumentList @("/uninstall") -NoNewWindow -Wait 103 | 104 | Start-Sleep -Seconds 300 105 | 106 | } # End If 107 | 108 | Write-Verbose "Installing the SCCM Agent on $env:COMPUTERNAME" 109 | Start-Process -FilePath "$Destination\ccmsetup.exe" -ArgumentList @("SMSSITECODE=$SiteCode") -NoNewWindow -Wait 110 | 111 | } # End Function Install-SccmAgent 112 | -------------------------------------------------------------------------------- /Install-Signal.ps1: -------------------------------------------------------------------------------- 1 | Function Install-Signal { 2 | <# 3 | .SYNOPSIS 4 | This cmdlet is used to install/update Signal for Windows. It can also be used to simply download the installer 5 | 6 | 7 | .DESCRIPTION 8 | Download the lates Signal installed for Windows, verify that hash and install the file 9 | 10 | 11 | .PARAMETER OutFile 12 | Define where to save the installer file. Default location is your Temp directory 13 | 14 | .PARAMETER DownloadOnly 15 | Switch parameter to specify you only want to download the installer 16 | 17 | .PARAMETER TryTLSv13 18 | Switch parameter that tells PowerShell to try download file using TLSv1.3. This seems to fail as of 3/28/2023 due to 1.3 being so new 19 | 20 | 21 | .EXAMPLE 22 | Install-Signal 23 | # This example downloads the Signal installer and verifies the checksum before installing it 24 | 25 | .EXAMPLE 26 | Install-Signal -OutFile "$env:TEMP\SignalClientx64.exe" 27 | # This example downloads the Signal installer and verifies the checksum before installing it 28 | 29 | .EXAMPLE 30 | Install-Signal -OutFile "$env:TEMP\SignalClientx64.exe" -DownloadOnly 31 | # This example downloads the Signal installer and verifies the checksum 32 | 33 | 34 | .NOTES 35 | Author: Robert H. Osborne 36 | Alias: tobor 37 | Contact: rosborne@osbornepro.com 38 | 39 | 40 | .LINK 41 | https://github.com/tobor88 42 | https://github.com/osbornepro 43 | https://www.powershellgallery.com/profiles/tobor 44 | https://osbornepro.com 45 | https://writeups.osbornepro.com 46 | https://encrypit.osbornepro.com 47 | https://btpssecpack.osbornepro.com 48 | https://www.powershellgallery.com/profiles/tobor 49 | https://www.hackthebox.eu/profile/52286 50 | https://www.linkedin.com/in/roberthosborne/ 51 | https://www.credly.com/users/roberthosborne/badges 52 | 53 | 54 | .INPUTS 55 | None 56 | 57 | 58 | .OUTPUTS 59 | System.Management.Automation.PSObject 60 | #> 61 | [OutputType([System.Management.Automation.PSObject])] 62 | [CmdletBinding()] 63 | param( 64 | [Parameter( 65 | Position=0, 66 | Mandatory=$False 67 | )] # End Parameter 68 | [ValidateScript({$_ -like "*.exe"})] 69 | [String]$OutFile = "$env:TEMP\SignalSetup.exe", 70 | 71 | [Parameter( 72 | Mandatory=$False 73 | )] # End Parameter 74 | [Switch]$DownloadOnly, 75 | 76 | [Parameter( 77 | Mandatory=$False 78 | )] # End Parameter 79 | [Switch]$TryTLSv13 80 | ) # End param 81 | 82 | $TlsVersion = "TLSv1.2" 83 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 84 | If ($TryTLSv13.IsPresent) { 85 | 86 | $TlsVersion = "TLSv1.3" 87 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls13 88 | 89 | } # End If 90 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') utilizing $TlsVersion" 91 | 92 | $Uri = 'https://api.github.com/repos/signalapp/Signal-Desktop/releases/latest' 93 | $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 94 | 95 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading Signal from GitHub" 96 | Try { 97 | 98 | $GetLinks = Invoke-RestMethod -Uri $Uri -Method GET -UseBasicParsing -UserAgent $UserAgent -ContentType 'application/json; charset=utf-8' -Verbose:$False 99 | $Version = ($GetLinks.html_url.Split('/')[-1]).Replace("v", "") 100 | $DownloadLink = "https://updates.signal.org/desktop/signal-desktop-win-$($Version).exe" 101 | 102 | } Catch { 103 | 104 | Throw $Error[0] 105 | 106 | } # End Try Catch Catch 107 | 108 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading Signal" 109 | Invoke-WebRequest -UseBasicParsing -Uri $DownloadLink -UserAgent $UserAgent -OutFile $OutFile -ContentType 'application/octet-stream' -Verbose:$False | Out-Null 110 | 111 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully verified hash of newly downloaded file for Signal version $Version" 112 | If ($DownloadOnly.IsPresent -and (Test-Path -Path $OutFile)) { 113 | 114 | Write-Output -InputObject "[*] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully downloaded file and verified hash.`n[i] File saved to $OutFile" 115 | 116 | } Else { 117 | 118 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Executing installation of Signal version $Version" 119 | Start-Process -FilePath $OutFile -ArgumentList @('/S') -NoNewWindow -Wait -PassThru 120 | 121 | } # End If Else 122 | 123 | } # End Function Install-Signal 124 | -------------------------------------------------------------------------------- /Install-VLC.ps1: -------------------------------------------------------------------------------- 1 | Function Install-VLC { 2 | <# 3 | .SYNOPSIS 4 | This cmdlet is used to install/update VLC for Windows. It can also be used to simply download the installer 5 | 6 | 7 | .DESCRIPTION 8 | Download the lates VLC installed for Windows, verify that hash and install the file 9 | 10 | 11 | .PARAMETER OutFile 12 | Define where to save the installer file. Default location is your Temp directory 13 | 14 | .PARAMETER DownloadOnly 15 | Switch parameter to specify you only want to download the installer 16 | 17 | .PARAMETER TryTLSv13 18 | Switch parameter that tells PowerShell to try download file using TLSv1.3. This seems to fail as of 3/28/2023 due to 1.3 being so new 19 | 20 | 21 | .EXAMPLE 22 | Install-VLC 23 | # This example downloads the VLC installer and verifies the checksum before installing it 24 | 25 | .EXAMPLE 26 | Install-VLC -OutFile "$env:TEMP\vlc-3.0.18-win64.exe" 27 | # This example downloads the VLC installer and verifies the checksum before installing it 28 | 29 | .EXAMPLE 30 | Install-VLC -OutFile "$env:TEMP\vlc-3.0.18-win64.exe" -DownloadOnly 31 | # This example downloads the VLC installer and verifies the checksum 32 | 33 | 34 | .NOTES 35 | Author: Robert H. Osborne 36 | Alias: tobor 37 | Contact: rosborne@osbornepro.com 38 | 39 | 40 | .LINK 41 | https://github.com/tobor88 42 | https://github.com/osbornepro 43 | https://www.powershellgallery.com/profiles/tobor 44 | https://osbornepro.com 45 | https://writeups.osbornepro.com 46 | https://encrypit.osbornepro.com 47 | https://btpssecpack.osbornepro.com 48 | https://www.powershellgallery.com/profiles/tobor 49 | https://www.hackthebox.eu/profile/52286 50 | https://www.linkedin.com/in/roberthosborne/ 51 | https://www.credly.com/users/roberthosborne/badges 52 | 53 | 54 | .INPUTS 55 | None 56 | 57 | 58 | .OUTPUTS 59 | System.Management.Automation.PSObject 60 | #> 61 | [OutputType([System.Management.Automation.PSObject])] 62 | [CmdletBinding()] 63 | param( 64 | [Parameter( 65 | Position=0, 66 | Mandatory=$False 67 | )] # End Parameter 68 | [ValidateScript({$_ -like "*.exe"})] 69 | [String]$OutFile = "$env:TEMP\vlc-version-win64.exe", 70 | 71 | [Parameter( 72 | Mandatory=$False 73 | )] # End Parameter 74 | [Switch]$DownloadOnly, 75 | 76 | [Parameter( 77 | Mandatory=$False 78 | )] # End Parameter 79 | [Switch]$TryTLSv13 80 | ) # End param 81 | 82 | $TlsVersion = "TLSv1.2" 83 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 84 | If ($TryTLSv13.IsPresent) { 85 | 86 | $TlsVersion = "TLSv1.3" 87 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls13 88 | 89 | } # End If 90 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') utilizing $TlsVersion" 91 | 92 | $Uri = 'https://www.videolan.org/vlc/download-windows.html' 93 | $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 94 | 95 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Getting VLC download link from GitHub" 96 | Try { 97 | 98 | $GetLinks = Invoke-WebRequest -Uri $Uri -Method GET -UseBasicParsing -UserAgent $UserAgent -ContentType 'text/html' -Verbose:$False 99 | $CheckSumLink = "https:" + $($GetLinks.Links | Where-Object -FilterScript { $_.href -like "*//get.videolan.org*" -and $_.outerHTML -like "*win64.exe*" } | Select-Object -ExpandProperty href -First 1) 100 | $Version = $CheckSumLink.Split('-')[-2] 101 | $DownloadLink = "https://mirrors.ocf.berkeley.edu/videolan-ftp/vlc/$($Version)/win64/vlc-$($Version)-win64.exe" 102 | 103 | } Catch { 104 | 105 | Throw $Error[0] 106 | 107 | } # End Try Catch Catch 108 | 109 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading VLC" 110 | Invoke-WebRequest -UseBasicParsing -Uri $DownloadLink -UserAgent $UserAgent -OutFile $OutFile -ContentType 'application/octet-stream' -Verbose:$False | Out-Null 111 | $FileHash = (Get-FileHash -Path $OutFile -Algorithm SHA256).Hash.ToLower() 112 | $CheckSum = ((Invoke-RestMethod -UseBasicParsing -Uri $CheckSumLink -UserAgent $UserAgent -ContentType 'text/html; charset=UTF-8' -Method GET -Verbose:$False).Split("`n") | Where-Object -FilterScript { $_ -like "*Display Checksum*" }).Split(':')[-1].Split('<')[0].Trim() 113 | 114 | If ($FileHash -eq $CheckSum) { 115 | 116 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully verified hash of newly downloaded file for VLC version $Version" 117 | If ($DownloadOnly.IsPresent -and (Test-Path -Path $OutFile)) { 118 | 119 | Write-Output -InputObject "[*] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully downloaded file and verified hash.`n[i] File saved to $OutFile" 120 | 121 | } Else { 122 | 123 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Executing installation of VLC version $Version" 124 | Move-Item -Path $OutFile -Destination $OutFile.Replace("version", $Version) -Force -Confirm:$False 125 | Start-Process -FilePath $OutFile.Replace("version", $Version) -ArgumentList @('/S') -NoNewWindow -Wait -PassThru 126 | 127 | } # End If Else 128 | 129 | } Else { 130 | 131 | Throw "[x] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Checsum value does not match the VLC sha256 hash of the downloaded file" 132 | 133 | } # End If Else 134 | 135 | } # End Function Install-VLC 136 | -------------------------------------------------------------------------------- /Install-VSCode.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 3.0 2 | Function Install-VSCode { 3 | <# 4 | .SYNOPSIS 5 | This cmdlet is used to install/update VSCode on a machine. It can also be used to simply download the installer 6 | 7 | 8 | .DESCRIPTION 9 | Download the lates VSCode installed for Windows, verify that hash and install the file 10 | 11 | 12 | .PARAMETER OutFile 13 | Define where to save the installer file. Default location is your Temp directory 14 | 15 | .PARAMETER DownloadOnly 16 | Switch parameter to specify you only want to download the installer 17 | 18 | .PARAMETER TryTLSv13 19 | Switch parameter that tells PowerShell to try download file using TLSv1.3. This seems to fail as of 3/28/2023 due to 1.3 being so new 20 | 21 | 22 | .EXAMPLE 23 | Install-VSCode 24 | # This example downloads the VSCode installer and verifies the checksum before installing it 25 | 26 | .EXAMPLE 27 | Install-VSCode -OutFile "$env:TEMP\PowerShell-version-win-x64.msi" 28 | # This example downloads the VSCode installer and verifies the checksum before installing it 29 | 30 | .EXAMPLE 31 | Install-VSCode -OutFile "$env:TEMP\PowerShell-version-win-x64.msi" -DownloadOnly 32 | # This example downloads the FileZilla installer and verifies the checksum 33 | 34 | 35 | .NOTES 36 | Author: Robert H. Osborne 37 | Alias: tobor 38 | Contact: rosborne@osbornepro.com 39 | 40 | 41 | .LINK 42 | https://code.visualstuido.com.com/tobor88 43 | https://code.visualstuido.com.com/osbornepro 44 | https://www.powershellgallery.com/profiles/tobor 45 | https://osbornepro.com 46 | https://writeups.osbornepro.com 47 | https://encrypit.osbornepro.com 48 | https://btpssecpack.osbornepro.com 49 | https://www.powershellgallery.com/profiles/tobor 50 | https://www.hackthebox.eu/profile/52286 51 | https://www.linkedin.com/in/roberthosborne/ 52 | https://www.credly.com/users/roberthosborne/badges 53 | 54 | 55 | .INPUTS 56 | None 57 | 58 | 59 | .OUTPUTS 60 | System.Management.Automation.PSObject 61 | #> 62 | [OutputType([System.Management.Automation.PSObject])] 63 | [CmdletBinding()] 64 | param( 65 | [Parameter( 66 | Position=0, 67 | Mandatory=$False 68 | )] # End Parameter 69 | [ValidateScript({$_ -like "*.exe"})] 70 | [String]$OutFile = "$env:TEMP\vscode-setup-win.exe", 71 | 72 | [Parameter( 73 | Mandatory=$False 74 | )] # End Parameter 75 | [Switch]$DownloadOnly, 76 | 77 | [Parameter( 78 | Mandatory=$False 79 | )] # End Parameter 80 | [Switch]$TryTLSv13 81 | ) # End param 82 | 83 | $TlsVersion = "TLSv1.2" 84 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 85 | If ($TryTLSv13.IsPresent) { 86 | 87 | $TlsVersion = "TLSv1.3" 88 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls13 89 | 90 | } # End If 91 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') utilizing $TlsVersion" 92 | 93 | #$CheckSumLink = 'https://code.visualstudio.com/Download' #JavaScript is preventing ability to obtain. Requires more research 94 | $DownloadLink = 'https://code.visualstudio.com/sha/download?build=stable&os=win32-x64-user' 95 | $UserAgent = "wget" 96 | 97 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading VSCode from code.visualstuido.com" 98 | Try { 99 | 100 | #$CheckSum = Invoke-RestMethod -Uri $CheckSumLink -Method GET -UseBasicParsing -UserAgent "wget" -ContentType 'text/html; charset=utf-8' -Verbose:$False 101 | Invoke-WebRequest -Uri $DownloadLink -UseBasicParsing -UserAgent $UserAgent -OutFile $OutFile -Method GET -ContentType 'application/octet-stream' -Verbose:$False | Out-Null 102 | 103 | } Catch { 104 | 105 | Throw $Error[0] 106 | 107 | } # End Try Catch Catch 108 | 109 | #$FileHash = (Get-FileHash -Path $OutFile -Algorithm SHA256).Hash.ToLower() 110 | #$CheckSum = ($GetLinks.body.Split("-") | Where-Object -FilterScript { $_ -like "*$FileHash*" } | Out-String).Trim().ToLower() 111 | 112 | #If ($FileHash -eq $CheckSum) { 113 | 114 | # Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully verified hash of newly downloaded file for VSCode" 115 | If ($DownloadOnly.IsPresent -and (Test-Path -Path $OutFile)) { 116 | 117 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully downloaded file and verified hash.`n[i] File saved to $OutFile" 118 | 119 | } Else { 120 | 121 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Executing installation of VSCode" 122 | Start-Process -FilePath $OutFile -ArgumentList @('/FORCECLOSEAPPLICATIONS', "/LANG=$PSUICulture", '/VERYSILENT') -NoNewWindow -Wait -PassThru 123 | 124 | } # End If Else 125 | 126 | #} Else { 127 | 128 | # Throw "[x] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Failed to validate hash of newly downloaded file for VSCode" 129 | 130 | #} # End If Else 131 | 132 | } # End Function Install-VSCode 133 | -------------------------------------------------------------------------------- /Install-WinRAR.ps1: -------------------------------------------------------------------------------- 1 | Function Install-WinRAR { 2 | <# 3 | .SYNOPSIS 4 | This cmdlet is used to install/update WinRAR for Windows. It can also be used to simply download the installer 5 | 6 | 7 | .DESCRIPTION 8 | Download the lates WinRAR installed for Windows, verify that hash and install the file 9 | 10 | 11 | .PARAMETER OutFile 12 | Define where to save the installer file. Default location is your Temp directory 13 | 14 | .PARAMETER DownloadOnly 15 | Switch parameter to specify you only want to download the installer 16 | 17 | .PARAMETER TryTLSv13 18 | Switch parameter that tells PowerShell to try download file using TLSv1.3. This seems to fail as of 3/28/2023 due to 1.3 being so new 19 | 20 | 21 | .EXAMPLE 22 | Install-WinRAR 23 | # This example downloads the WinRAR installer and verifies the checksum before installing it 24 | 25 | .EXAMPLE 26 | Install-WinRAR -OutFile "$env:TEMP\WinRAR-Installer.exe" 27 | # This example downloads the WinRAR installer and verifies the checksum before installing it 28 | 29 | .EXAMPLE 30 | Install-WinRAR -OutFile "$env:TEMP\WinRAR-Installer.exe" -DownloadOnly 31 | # This example downloads the WinRAR installer and verifies the checksum 32 | 33 | 34 | .NOTES 35 | Author: Robert H. Osborne 36 | Alias: tobor 37 | Contact: rosborne@osbornepro.com 38 | 39 | 40 | .LINK 41 | https://github.com/tobor88 42 | https://github.com/osbornepro 43 | https://www.powershellgallery.com/profiles/tobor 44 | https://osbornepro.com 45 | https://writeups.osbornepro.com 46 | https://encrypit.osbornepro.com 47 | https://btpssecpack.osbornepro.com 48 | https://www.powershellgallery.com/profiles/tobor 49 | https://www.hackthebox.eu/profile/52286 50 | https://www.linkedin.com/in/roberthosborne/ 51 | https://www.credly.com/users/roberthosborne/badges 52 | 53 | 54 | .INPUTS 55 | None 56 | 57 | 58 | .OUTPUTS 59 | System.Management.Automation.PSObject 60 | #> 61 | [OutputType([System.Management.Automation.PSObject])] 62 | [CmdletBinding()] 63 | param( 64 | [Parameter( 65 | Position=0, 66 | Mandatory=$False 67 | )] # End Parameter 68 | [ValidateScript({$_ -like "*.exe"})] 69 | [String]$OutFile = "C:\Windows\Temp\winrar-x64-version.exe", 70 | 71 | [Parameter( 72 | Mandatory=$False 73 | )] # End Parameter 74 | [Switch]$DownloadOnly, 75 | 76 | [Parameter( 77 | Mandatory=$False 78 | )] # End Parameter 79 | [Switch]$TryTLSv13 80 | ) # End param 81 | 82 | $TlsVersion = "TLSv1.2" 83 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 84 | If ($TryTLSv13.IsPresent) { 85 | 86 | $TlsVersion = "TLSv1.3" 87 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls13 88 | 89 | } # End If 90 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') utilizing $TlsVersion" 91 | 92 | $OutFile = $OutFile.Replace("version",$WrVersion) 93 | $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 94 | $WrVersion = (((Invoke-WebRequest -Uri https://www.rarlab.com/ -UseBasicParsing -UserAgent $UserAgent -Method GET -Verbose:$False).Links | Where-Object -FilterScript { $_.outerHTML -like "*/rar/winrar-x64-*" }).href.Split('=').Split('.') | Where-Object -FilterScript { $_ -match "(.*)\d{1,6}$"}).Split('-')[-1] 95 | $DownloadLink = "https://rarlab.com/rar/winrar-x64-$WrVersion.exe" 96 | 97 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading WinRAR version $WrVersion" 98 | Try { 99 | 100 | (New-Object -TypeName System.Net.WebCLient).DownloadFile("$DownloadLink", "$OutFile") 101 | 102 | } Catch [System.Net.WebException] { 103 | 104 | If ($Error[0] -like "*Request forbidden by administrative rules.*") { 105 | 106 | Invoke-WebRequest -Uri $DownloadLink -UseBasicParsing -Method GET -ContentType 'application/octet-stream' -UserAgent $UserAgent -OutFile $OutFile -Verbose:$False -ErrorAction Stop | Out-Null 107 | 108 | } Else { 109 | 110 | Throw $Error[0] 111 | 112 | } # End If Else 113 | 114 | } Catch { 115 | 116 | Throw $Error[0] 117 | 118 | } # End Try Catch Catch 119 | 120 | Write-Warning -Message "[!] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') WinRAR does NOT offer a checksum value to verify a files integrity with. Use 7Zip it is way better" 121 | If ($DownloadOnly.IsPresent -and (Test-Path -Path $OutFile)) { 122 | 123 | Write-Output -InputObject "[*] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully downloaded WinRAR file and verified hash.`n[i] File saved to $OutFile" 124 | 125 | } Else { 126 | 127 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Executing installation of WinRAR version $WrVersion" 128 | Start-Process -FilePath $OutFile -ArgumentList @('/S') -NoNewWindow -Wait -PassThru -ErrorAction Stop 129 | 130 | } # End If Else 131 | 132 | } # End Function Install-WinRAR 133 | -------------------------------------------------------------------------------- /Install-WinSCP.ps1: -------------------------------------------------------------------------------- 1 | Function Install-WinSCP { 2 | <# 3 | .SYNOPSIS 4 | This cmdlet is used to install/update WinSCP on a machine. It can also be used to simply download the installer 5 | 6 | 7 | .DESCRIPTION 8 | Download the lates WinSCP installed for Windows, verify that hash and instal the file 9 | 10 | 11 | .PARAMETER OutFile 12 | Define where to save the installer file. Default location is your Temp directory 13 | 14 | .PARAMETER DownloadOnly 15 | Switch parameter to specify you only want to download the installer 16 | 17 | .PARAMETER TryTLSv13 18 | Switch parameter that tells PowerShell to try download file using TLSv1.3. This seems to fail as of 3/28/2023 due to 1.3 being so new 19 | 20 | 21 | .EXAMPLE 22 | Install-WinSCP 23 | # This example downloads the WinSCP installer and verifies the checksum before installing it 24 | 25 | .EXAMPLE 26 | Install-WinSCP -OutFile "$env:TEMP\WinSCP-Version-Setup.exe" 27 | # This example downloads the WinSCP installer and verifies the checksum before installing it 28 | 29 | .EXAMPLE 30 | Install-WinSCP -OutFile "$env:TEMP\WinSCP-Version-Setup.exe" -DownloadOnly 31 | # This example downloads the WinSCP installer and verifies the checksum 32 | 33 | 34 | .NOTES 35 | Author: Robert H. Osborne 36 | Alias: tobor 37 | Contact: rosborne@osbornepro.com 38 | 39 | 40 | .LINK 41 | https://github.com/tobor88 42 | https://github.com/osbornepro 43 | https://www.powershellgallery.com/profiles/tobor 44 | https://osbornepro.com 45 | https://writeups.osbornepro.com 46 | https://encrypit.osbornepro.com 47 | https://btpssecpack.osbornepro.com 48 | https://www.powershellgallery.com/profiles/tobor 49 | https://www.hackthebox.eu/profile/52286 50 | https://www.linkedin.com/in/roberthosborne/ 51 | https://www.credly.com/users/roberthosborne/badges 52 | 53 | 54 | .INPUTS 55 | None 56 | 57 | 58 | .OUTPUTS 59 | System.Management.Automation.PSObject 60 | #> 61 | [OutputType([System.Management.Automation.PSObject])] 62 | [CmdletBinding()] 63 | param( 64 | [Parameter( 65 | Position=0, 66 | Mandatory=$False, 67 | ValueFromPipeline=$False)] # End Parameter 68 | [ValidateScript({$_ -like "*.exe"})] 69 | [String]$OutFile = "$env:TEMP\WinSCP-Version-Setup.exe", 70 | 71 | [Parameter( 72 | Mandatory=$False)] # End Parameter 73 | [Switch]$DownloadOnly, 74 | 75 | [Parameter( 76 | Mandatory=$False)] # End Parameter 77 | [Switch]$TryTLSv13 78 | ) # End param 79 | 80 | $TlsVersion = "TLSv1.2" 81 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 82 | If ($TryTLSv13.IsPresent) { 83 | 84 | $TlsVersion = "TLSv1.3" 85 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls13 86 | 87 | } # End If 88 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') utilizing $TlsVersion" 89 | 90 | $DLUserAgent = "Wget" 91 | $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 92 | $DlUrl = 'https://winscp.net/eng/download.php' 93 | $Version = ((Invoke-WebRequest -Uri $DlUrl -UseBasicParsing -Method GET -UserAgent $UserAgent -ErrorAction Stop -Verbose:$False).Links | Where-Object -FilterScript { $_.outerHTML -like "*List of all changes*" }).href.Split('=')[-1] 94 | $Uri = "https://winscp.net/download/WinSCP-$Version`-Setup.exe" 95 | 96 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading WinSCP from their website" 97 | Try { 98 | 99 | Invoke-WebRequest -Uri $Uri -UseBasicParsing -Method GET -UserAgent $DLUserAgent -OutFile $OutFile -ContentType 'application/octet-stream' -Verbose:$False | Out-Null 100 | $CheckSum = (((Invoke-WebRequest -Uri $Uri -UseBasicParsing -Method GET -UserAgent $UserAgent -Verbose:$False).Content).Split("`n") | Select-String -Pattern "SHA-256:").ToString().Trim().Replace('','').Split(" ")[-1] 101 | 102 | } Catch { 103 | 104 | Throw $Error[0] 105 | 106 | } # End Try Catch Catch 107 | 108 | $FileHash = (Get-FileHash -Path $OutFile -Algorithm SHA256).Hash.ToLower() 109 | If ($FileHash -eq $CheckSum) { 110 | 111 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully verified hash of newly downloaded file for WinSCP" 112 | If ($DownloadOnly.IsPresent -and (Test-Path -Path $OutFile)) { 113 | 114 | Write-Output -InputObject "[*] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully downloaded file and verified hash.`n[i] File saved to $OutFile" 115 | 116 | } Else { 117 | 118 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Executing installation of WinSCP" 119 | Start-Process -FilePath $OutFile -ArgumentList @('/VERYSILENT', '/ALLUSERS' ,'NORESTART') -NoNewWindow -Wait -PassThru -ErrorAction Stop 120 | 121 | } # End If Else 122 | 123 | } Else { 124 | 125 | Throw "[x] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Failed to validate hash of newly downloaded file for WinSCP" 126 | 127 | } # End If Else 128 | 129 | } # End Function Install-WinSCP 130 | -------------------------------------------------------------------------------- /Install-WinSCPNetAssembly.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 3.0 2 | Function Install-WinSCPNetAssembly { 3 | <# 4 | .SYNOPSIS 5 | This cmdlet is used to install/update WinSCP NET Assembly DLL on a machine. It can also be used to simply download the installer 6 | 7 | 8 | .DESCRIPTION 9 | Download the lates WinSCP installed for Windows, verify that hash and instal the file 10 | 11 | 12 | .PARAMETER OutFile 13 | Define where to save the NET assembly zip file. Default location is your Temp directory 14 | 15 | .PARAMETER DownloadOnly 16 | Switch parameter to specify you only want to download the installer 17 | 18 | .PARAMETER TryTLSv13 19 | Switch parameter that tells PowerShell to try download file using TLSv1.3. This seems to fail as of 3/28/2023 due to 1.3 being so new 20 | 21 | 22 | .EXAMPLE 23 | Install-WinSCPNetAssembly 24 | # This example downloads the WinSCP automation and verifies the checksum before installing it 25 | 26 | .EXAMPLE 27 | Install-WinSCPNetAssembly -OutFile "$env:TEMP\WinSCP-Version-Automation.zip" 28 | # This example downloads the WinSCP automation and verifies the checksum before installing it 29 | 30 | .EXAMPLE 31 | Install-WinSCPNetAssembly -OutFile "$env:TEMP\WinSCP-Version-Automation.zip" -DownloadOnly 32 | # This example downloads the WinSCP automation and verifies the checksum 33 | 34 | 35 | .NOTES 36 | Author: Robert Osborne 37 | Contact: rosborne@vinebrooktech.com 38 | 39 | 40 | .LINK 41 | https://www.vinebrooktech.com 42 | 43 | 44 | .INPUTS 45 | None 46 | 47 | 48 | .OUTPUTS 49 | System.Management.Automation.PSObject 50 | #> 51 | [OutputType([System.Management.Automation.PSObject])] 52 | [CmdletBinding()] 53 | param( 54 | [Parameter( 55 | Position=0, 56 | Mandatory=$False 57 | )] # End Parameter 58 | [ValidateScript({$_ -like "*.zip"})] 59 | [String]$OutFile = "$env:TEMP\WinSCP-Version-Automation.zip", 60 | 61 | [Parameter( 62 | Position=1, 63 | Mandatory=$False 64 | )] # End Parameter 65 | [String]$DestinationPath = "$env:ProgramData\WinSCP", 66 | 67 | [Parameter( 68 | Mandatory=$False 69 | )] # End Parameter 70 | [Switch]$DownloadOnly, 71 | 72 | [Parameter( 73 | Mandatory=$False 74 | )] # End Parameter 75 | [Switch]$TryTLSv13 76 | ) # End param 77 | 78 | $TlsVersion = "TLSv1.2" 79 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 80 | If ($TryTLSv13.IsPresent) { 81 | 82 | $TlsVersion = "TLSv1.3" 83 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls13 84 | 85 | } # End If 86 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') utilizing $TlsVersion" 87 | 88 | $DLUserAgent = "Wget" 89 | $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 90 | $DlUrl = 'https://winscp.net/eng/download.php' 91 | $Version = ((Invoke-WebRequest -Uri $DlUrl -UseBasicParsing -Method GET -UserAgent $UserAgent -ErrorAction Stop -Verbose:$False).Links | Where-Object -FilterScript { $_.outerHTML -like "*List of all changes*" }).href.Split('=')[-1] 92 | $Uri = "https://winscp.net/download/WinSCP-$Version`-Automation.zip" 93 | 94 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Downloading WinSCP NET Assembly from their website" 95 | Try { 96 | 97 | Invoke-WebRequest -Uri $Uri -UseBasicParsing -Method GET -UserAgent $DLUserAgent -OutFile $OutFile -ContentType 'application/octet-stream' -Verbose:$False | Out-Null 98 | $CheckSum = (((Invoke-WebRequest -Uri $Uri -UseBasicParsing -Method GET -UserAgent $UserAgent -Verbose:$False).Content).Split("`n") | Select-String -Pattern "SHA-256:").ToString().Trim().Replace('','').Split(" ")[-1] 99 | 100 | } Catch { 101 | 102 | Throw $Error[0] 103 | 104 | } # End Try Catch Catch 105 | 106 | $FileHash = (Get-FileHash -Path $OutFile -Algorithm SHA256).Hash.ToLower() 107 | If ($FileHash -eq $CheckSum) { 108 | 109 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully verified hash of newly downloaded file for WinSCP" 110 | If ($DownloadOnly.IsPresent -and (Test-Path -Path $OutFile)) { 111 | 112 | Write-Output -InputObject "[*] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Successfully downloaded file and verified hash.`n[i] File saved to $OutFile" 113 | 114 | } Else { 115 | 116 | Write-Verbose -Message "[v] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Extracting zip archive to $DestinationPath" 117 | Expand-Archive -Path $OutFile -DestinationPath $DestinationPath -Force -Confirm:$False -Verbose:$False 118 | 119 | } # End If Else 120 | 121 | } Else { 122 | 123 | Throw "[x] $(Get-Date -Format 'MM-dd-yyyy hh:mm:ss') Failed to validate hash of newly downloaded file for WinSCP" 124 | 125 | } # End If Else 126 | 127 | } # End Function Install-WinSCPNetAssembly 128 | -------------------------------------------------------------------------------- /Invoke-MissingUpdateInstallation.ps1: -------------------------------------------------------------------------------- 1 | Function Invoke-MissingUpdateInstallation { 2 | <# 3 | .SYNOPSIS 4 | This cmdlet is used to install missing Windows and 3rd Party Application updates that are approved in SCCMs Software Center. You can specify a retry count for updates that fail the first time or two. This uses CIM connections to accomplish the task 5 | 6 | 7 | .DESCRIPTION 8 | This cmdlet can be run locally on a machine to look for and install any approved SCCM server approved updates. This allows you to attempt multiple times to install an update since the first attempt will seomtimes fail 9 | 10 | 11 | .PARAMETER ComputerName 12 | Define remote computer(s) you wish to install missing updates on 13 | 14 | .PARAMETER KBs 15 | Define the specific KBs you wish to install 16 | 17 | .PARAMETER Credential 18 | Define the credentials that should be used to remotely connect to devices using CIM sessions with WinRM 19 | 20 | .PARAMETER Seconds 21 | Define the number of seconds to wait in between retry attempts 22 | 23 | .PARAMETER RetryCount 24 | Define the number of times to retry and installation before giving up on it 25 | 26 | .PARAMETER UseSSL 27 | Build CIM Sessions using WinRM over HTTPS 28 | 29 | 30 | .EXAMPLE 31 | Invoke-MissingUpdateInstallation 32 | # This example attempts to install any missing SCCM approved updates on the local device. It retries failed updates twice with 90 second intervals bewteen attempts 33 | 34 | .EXAMPLE 35 | Invoke-MissingUpdateInstallation -ComputerName DC01.domain.com,FS01.domain.com,DHCP.domain.com -UseSSL -Credential $LiveCred -Seconds 45 -RetryCount 1 36 | # This example installs missing updates on the 3 defined remote machines over a WinRM over HTTPS CIM session. If an attempt fails it will wait 45 seconds and retry once more before moving on to the next update check 37 | 38 | 39 | .INPUTS 40 | System.String ComputerName 41 | 42 | .OUTPUTS 43 | PSCustomObject 44 | 45 | 46 | .NOTES 47 | Author: Robert H. Osborne 48 | Alias: tobor 49 | Contact: rosborne@osbornepro.com 50 | 51 | 52 | .LINK 53 | https://github.com/tobor88 54 | https://github.com/OsbornePro 55 | https://www.powershellgallery.com/profiles/tobor 56 | https://osbornepro.com 57 | https://writeups.osbornepro.com 58 | https://btpssecpack.osbornepro.com 59 | https://www.powershellgallery.com/profiles/tobor 60 | https://www.hackthebox.eu/profile/52286 61 | https://www.linkedin.com/in/roberthosborne/ 62 | https://www.credly.com/users/roberthosborne/badges 63 | #> 64 | [CmdletBinding(DefaultParameterSetName="Local")] 65 | param( 66 | [Parameter( 67 | ParameterSetName="Remote", 68 | Position=0, 69 | Mandatory=$True, 70 | ValueFromPipeline=$True, 71 | ValueFromPipelineByPropertyName=$True)] # End Parameter 72 | [Parameter( 73 | ParameterSetName="Local", 74 | Position=0, 75 | Mandatory=$False, 76 | ValueFromPipeline=$True, 77 | ValueFromPipelineByPropertyName=$True)] # End Parameter 78 | [String[]]$ComputerName = "$env:COMPUTERNAME.$((Get-CimInstance -ClassName Win32_ComputerSystem).Domain)", 79 | 80 | [Parameter( 81 | Mandatory=$False, 82 | Position=1, 83 | ValueFromPipeline=$False 84 | )] # End Parameter 85 | [String[]]$KBs, 86 | 87 | [ValidateNotNull()] 88 | [System.Management.Automation.PSCredential] 89 | [System.Management.Automation.Credential()] 90 | [Parameter(ParameterSetName="Remote")] 91 | $Credential = [System.Management.Automation.PSCredential]::Empty, 92 | 93 | [Parameter( 94 | Mandatory=$False, 95 | ValueFromPipeline=$False 96 | )] # End Parameter 97 | [Int32]$Seconds = 90, 98 | 99 | [Parameter( 100 | Mandatory=$False, 101 | ValueFromPipeline=$False 102 | )] # End Parameter 103 | [Int32]$RetryCount = 3, 104 | 105 | [Parameter( 106 | ParameterSetName="Remote", 107 | Mandatory=$False)] # End Parameter 108 | [Switch][Bool]$UseSSL 109 | ) # End param 110 | 111 | BEGIN { 112 | 113 | $Return = @() 114 | $NotReachable = @() 115 | 116 | $ConfirmSSL = $False 117 | If ($UseSSL.IsPresent) { 118 | 119 | $ConfirmSSL = $True 120 | 121 | } # End If 122 | 123 | } PROCESS { 124 | 125 | If ($PSCmdlet.ParameterSetName -eq "Remote") { 126 | 127 | Write-Verbose "Builindg CIM Sessions for $ComputerName" 128 | $CIMSession = New-CimSession -ComputerName $ComputerName -Credential $Credential -SessionOption (New-CIMSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck -UseSsl:$ConfirmSSL) -ErrorAction SilentlyContinue 129 | $CIMConnections = (Get-CimSession).ComputerName 130 | ForEach ($C in $ComputerName) { 131 | 132 | If ($C -notin $CIMConnections) { 133 | 134 | $NotReachable += $C 135 | 136 | } # End If 137 | 138 | } # End ForEach 139 | 140 | } # End If 141 | 142 | Write-Verbose "Getting the missing updates from SCCM clients" 143 | If ($CIMSession) { 144 | 145 | Write-Output "[*] Getting missing updates on $ComputerName" 146 | [CimInstance[]]$MissingUpdates = Get-CimInstance -CimSession $CIMSession -NameSpace "Root\CCM\ClientSDK" -ClassName "CCM_SoftwareUpdate" -Filter "ComplianceState=0" -ErrorAction Stop 147 | 148 | } Else { 149 | 150 | Write-Output "[*] Getting Missing updates on $env:COMPUTERNAME" 151 | [CimInstance[]]$MissingUpdates = Get-CimInstance -NameSpace "Root\CCM\ClientSDK" -ClassName "CCM_SoftwareUpdate" -Filter "ComplianceState=0" 152 | 153 | } # End If Else 154 | 155 | 156 | If ($Null -eq $MissingUpdates) { 157 | 158 | Write-Output "[*] No missing updates found." 159 | 160 | } Else { 161 | 162 | If ($PSBoundParameters.ContainsKey('KBs')) { 163 | 164 | [CimInstance[]]$MissingUpdates = $MissingUpdates | Where-Object -FilterScript { $_.ArticleID -in $KBs.Replace("KB","") } 165 | 166 | } # End If 167 | 168 | Write-Output "[*] Installing the below missing updates: `n$($MissingUpdates | Select-Object -ExpandProperty ArticleID -Unique)" 169 | If ($CIMSession) { 170 | 171 | Invoke-CimMethod -CimSession $CIMSession -Namespace "Root\CCM\ClientSDK" -ClassName "CCM_SoftwareUpdatesManager" -MethodName InstallUpdates -Arguments @{ CCMUpdates=[CimInstance[]]$MissingUpdates} -ErrorAction SilentlyContinue | Out-Null 172 | 173 | } Else { 174 | 175 | Invoke-CimMethod -Namespace "Root\CCM\ClientSDK" -ClassName "CCM_SoftwareUpdatesManager" -MethodName InstallUpdates -Arguments @{ CCMUpdates=[CimInstance[]]$MissingUpdates} -ErrorAction SilentlyContinue | Out-Null 176 | 177 | } # End If Else 178 | 179 | ForEach ($C in $ComputerName) { 180 | 181 | ForEach ($MissingUpdate in $MissingUpdates) { 182 | 183 | $State = $MissingUpdate | Select-Object -ExpandProperty EvaluationState 184 | Switch ($State) { 185 | 186 | '0' { $JobState = "ciJobStateNone" } 187 | '1' { $JobState = "ciJobStateAvailable" } 188 | '2' { $JobState = "ciJobStateSubmitted" } 189 | '3' { $JobState = "ciJobStateDetecting" } 190 | '4' { $JobState = "ciJobStatePreDownload" } 191 | '5' { $JobState = "ciJobStateDownloading" } 192 | '6' { $JobState = "ciJobStateWaitInstall" } 193 | '7' { $JobState = "ciJobStateInstalling" } 194 | '8' { $JobState = "ciJobStatePendingSoftReboot" } 195 | '9' { $JobState = "ciJobStatePendingHardReboot" } 196 | '10' { $JobState = "ciJobStateWaitReboot" } 197 | '11' { $JobState = "ciJobStateVerifying" } 198 | '12' { $JobState = "ciJobStateInstallComplete" } 199 | '13' { $JobState = "ciJobStateError" } 200 | '14' { $JobState = "ciJobStateWaitServiceWindow" } 201 | '15' { $JobState = "ciJobStateWaitUserLogon" } 202 | '16' { $JobState = "ciJobStateWaitUserLogoff" } 203 | '17' { $JobState = "ciJobStateWaitJobUserLogon" } 204 | '18' { $JobState = "ciJobStateWaitUserReconnect" } 205 | '19' { $JobState = "ciJobStatePendingUserLogoff" } 206 | '20' { $JobState = "ciJobStatePendingUpdate" } 207 | '21' { $JobState = "ciJobStateWaitingRetry" } 208 | '22' { $JobState = "ciJobStateWaitPresModeOff" } 209 | '23' { $JobState = "ciJobStateWaitForOrchestration" } 210 | 211 | } # End Switch 212 | 213 | $Return += New-Object -TypeName PSCustomObject -Property @{ 214 | JobState=$JobState; 215 | ComputerName=$C; 216 | Update=$MissingUpdate.Name; 217 | PercentComplete=$MissingUpdate.PercentComplete; 218 | ArticleId=$MissingUpdate.ArticleID; 219 | ComplianceState=$MissingUpdate.ComplianceState; 220 | Deadline=$MissingUpdate.Deadline; 221 | UpdateID=$MissingUpdate.UpdateID; 222 | } # End New-Object -Property 223 | 224 | } # End ForEach 225 | 226 | } # End ForEach 227 | 228 | $NotReachable | ForEach-Object { 229 | 230 | $Return += New-Object -TypeName PSCustomObject -Property @{ 231 | JobState="CIM Session could not be created"; 232 | ComputerName=$_; 233 | Update="CIM Session could not be created"; 234 | PercentComplete="CIM Session could not be created"; 235 | ArticleId="CIM Session could not be created"; 236 | ComplianceState="CIM Session could not be created"; 237 | Deadline="CIM Session could not be created"; 238 | UpdateID="CIM Session could not be created"; 239 | } # End New-Object -Property 240 | 241 | } # End ForEach 242 | 243 | Write-Output "[*] Waiting $Seconds seconds for updates to reach an in progress related status" 244 | Start-Sleep -Seconds $Seconds 245 | 246 | $Result = $True 247 | $Counter = 0 248 | While ($Result -eq $True -or $Counter -ne $RetryCount) { 249 | 250 | If ($CIMSession) { 251 | 252 | $CCMUpdate = Get-CimInstance -CimSession $CIMSession -Namespace "Root\CCM\ClientSDK" -ClassName "CCM_SoftwareUpdate" -ErrorAction SilentlyContinue 253 | 254 | } Else { 255 | 256 | $CCMUpdate = Get-CimInstance -Namespace "Root\CCM\ClientSDK" -ClassName "CCM_SoftwareUpdate" 257 | 258 | } # End If Else 259 | 260 | [Array]$UniqueStatus = $CCMUpdate | Sort-Object -Property EvalutationState -Unique 261 | If ([Array]$UniqueStatus.EvaluationState -Contains 13 -or $UniqueStatus -Contains 21) { 262 | 263 | $RetryUpdate = $CCMUpdate | Where-Object -FilterScript { $_.EvalutationState -eq 13 -or $_.EvaluationState -eq 21 } 264 | $RetryCIM = $CIMSession | Where-Object -FilterScript { $_.ComputerName -in $RetryUpdate.ComputerName } 265 | 266 | Write-Output "[*] Retrying one last time the installation attempt of the missing updates" 267 | Invoke-CimMethod -ComputerName $RetryCIM -Namespace "Root\CCM\ClientSDK" -ClassName "CCM_SoftwareUpdatesManager" -MethodName InstallUpdates -Arguments @{ CCMUpdates=[CimInstance[]]$MissingUpdates} -ErrorAction SilentlyContinue | Out-Null 268 | 269 | Write-Output "[*] Waiting $Seconds Seconds for update to start" 270 | Start-Sleep -Seconds $Seconds 271 | 272 | } # End If 273 | 274 | $Result = If (@($CCMUpdate | Where-Object -FilterScript { $_.EvaluationState -eq 2 -or $_.EvaluationState -eq 3 -or $_.EvaluationState -eq 4 -or $_.EvaluationState -eq 5 -or $_.EvaluationState -eq 6 -or $_.EvaluationState -eq 7 -or $_.EvaluationState -eq 11 }).length -ne 0) { 275 | 276 | $True 277 | 278 | } Else { 279 | 280 | $False 281 | 282 | } # End If Else 283 | 284 | Start-Sleep -Seconds 5 285 | $Counter++ 286 | 287 | } # End While 288 | 289 | If ($CIMSession) { 290 | 291 | Write-Verbose "Closing CIM Sessions" 292 | Remove-CimSession -CimSession $CIMSession -Confirm:$False -ErrorAction SilentlyContinue 293 | 294 | } # End If 295 | 296 | } # End If Else 297 | 298 | } END { 299 | 300 | Return $Return 301 | 302 | } # End B P E 303 | 304 | } # End Function Invoke-MissingUpdateInstallation 305 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 tobor 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Windows Updates 2 | 3 | This repository contains a collection of PowerShell cmdlets that are useful in updating Windows and troubleshooting issues. Updates that deal with SCCM are also included. 4 | 5 | 6 | ## Cmdlet List 7 | 8 | - **Add-CMSystemDiscoveryMethodContainer** (*Adds new LDAP containers to query to the SCCM servers system discovery filter*) 9 | - **Clear-GpoRegistrySettings.ps1** (*Fix failed Windows Updates caused by policy errors*) 10 | - **Get-ComponentDescription** (*Return descriptino of log file based on component name*) 11 | - **Get-KBDownloadLink.ps1** (*Returns a download link for the defined KB article ID for the current OS version and architecture or defined version and architecture*) 12 | - **Get-KnownIssuesWindowsUpdates.ps1** (*Returns information on the latest months Windows patching issues*) 13 | - **Get-MissingDeviceUpdate.ps1** (*Return information on missing updates or approved missing SCCM updates*) 14 | - **Get-SccmSoftwareUpdateStatus.ps1** (*Return device in SCCM matching a certain status such as Error or Unknown*) 15 | - **Get-WindowsUpdateError.ps1** (*Save a log file to your desktop containing logs on Windows Updates*) 16 | - **Get-WindowsUpdateErrorCode.ps1** (*Return the error code reason for failed Windows Updates, save log files to desktop, and option to run troubleshooter*) 17 | - **Get-UpdateHistory.p1** (*Returns information on the history of Windows Updates*) 18 | - **Install-7Zip.ps1** (*Install or update 7Zip. I have not found a checksum to use for verification*) 19 | - **Install-AzureCLI.ps1** (*Install or update the Azure CLI. I have not found a checksum to use for verification*) 20 | - **Install-AzureStorageExplorer.ps1** (*Install or update the Azure Storage Explorer. I have not found a checksum to use for verification*) 21 | - **Install-CherryTree.ps1** (*Install or update CherryTree after verifying checksum*) 22 | - **Install-DrawIO.ps1** (*Install or update Draw.io after verifying checksum*) 23 | - **Install-FileZilla.ps1** (*Install or update FileZilla after verifying checksum*) 24 | - **Install-GitForWindows.ps1** (*Install or update Git for Windows after verifying checksum*) 25 | - **Install-KeePass.ps1** (*Install or update KeePass after verifying checksum*) 26 | - **Install-NodeJS.ps1** (*Install or update NodeJS after verifying checksum*) 27 | - **Install-NotepadPlusPlus.ps1** (*Install or update Notepad++ after verifying checksum*) 28 | - **Install-PowerShellCore.ps1** (*Install or update PowerShell Core after verifying checksum*) 29 | - **Install-Putty.ps1** (*Download and install Putty and verifiy checksum*) 30 | - **Install-RemoteDesktopManager.ps1** (*Download and install Remote Desktop Manager*) 31 | - **Install-SccmAgent.ps1** (*Install or reinstall the SCCM Agent on a device*) 32 | - **Install-Signal.ps1** (*Install or update Signal after verifying checksum*) 33 | - **Install-SSMS.ps1** (*Installs or updates SSMS. No checksum value that can be verified*) 34 | - **Install-VLC.ps1** (*Install or update VLC after verifying checksum*) 35 | - **Install-VSCode.ps1** (*Install or update Visual Studio Code. Unable to verify checksum automatically yet*) 36 | - **Install-WinRAR.ps1** (*Install or update WinRAR. They do not offer a checksum. Use 7Zip its better*) 37 | - **Install-WinSCP.ps1** (*Install or update WinSCP after verifying checksum*) 38 | - **Install-WinSCPNETAssembly.ps1** (*Download the WinSCP DLL required for writing PowerShell scripts with NET assembly. Checksum gets verified*) 39 | - **Invoke-MissingUpdateInstallation.ps1** (*Installs SCCM approved missing updates ona device*) 40 | - **Remove-CMSystemDiscoveryMethodContainer** (*Removes LDAP containers from query on the SCCM servers system discovery filter*) 41 | - **Remove-WindowsUpdate.ps1** (*Uninstall a Windows Update by KB number on a remote or local device*) 42 | - **Repair-WindowsUpdate.ps1** (*Stops Windows Update related services and renames directory locations which fixes 90% of all update issues in my experience*) 43 | - **Reset-SccmAgent.ps1** (*Delete the SCCM cache files and restart the service*) 44 | - **Update-Windows.ps1** (*Install any missing Windows Updates*) 45 | 46 | 47 | ### I am merely a contributor to the Update-Windows script. 48 | 49 | __REFERENCE:__ HERE 50 | __REFERENCE:__ HERE. 51 | 52 | I have added some functionality and improved them wherever I saw fit. 53 | 54 | If you make any changes or find a better way to do something feel free to send it to me so I have it too. :) 55 | -------------------------------------------------------------------------------- /Remove-CMSystemDiscoveryMethodContainer.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 3.0 2 | Function Remove-CMSystemDiscoveryMethodContainer { 3 | <# 4 | .SYNOPSIS 5 | Remove an Organizational Units (OU) by distinguished name from Active Directory System Discovery components in ConfigMgr 6 | 7 | 8 | .DESCRIPTION 9 | This cmdlet uses the distinguished name defined in -SearchBase to remove the System Discovery method on an SCCM server 10 | 11 | 12 | .PARAMETER SiteServer 13 | SCCM Site Server to connect too 14 | 15 | .PARAMETER UseSSL 16 | Creates CIM session to SCCM server using SSL (WinRM over HTTPS) 17 | 18 | .PARAMETER SkipCACheck 19 | Skip Certificate authority trust check on WinRM connnection 20 | 21 | .PARAMETER SkipCNCheck 22 | Skip verifying the CN/subject name on the WinRM certificate 23 | 24 | .PARAMETER SkipRevocationCheck 25 | Skip checking certificate revocation for WinRM connections 26 | 27 | .PARAMETER SearchBase 28 | Define the LDAP container OU path to new domains being added to System Discovery 29 | 30 | .PARAMETER Credential 31 | Enter credentials to authenticate to the SCCM server 32 | 33 | 34 | .EXAMPLE 35 | Remove-CMSystemDiscoveryMethodContainer -SiteServer sccm-server.domain.com -SearchBase "DC=domain,DC=com" 36 | # This example adds the domain.com LDAP search base filter to the domain System Discovery method on the sccm-server.domain.com SCCM server 37 | 38 | .EXAMPLE 39 | Remove-CMSystemDiscoveryMethodContainer -SiteServer sccm-server.domain.com -UseSSL -SkipCACheck -SkipCNCheck -SkipRevocationCheck -SearchBase "LDAP:\\DC=domain,DC=com" 40 | # This example adds the domain.com LDAP search base filter to the domain System Discovery method on the sccm-server.domain.com SCCM server 41 | 42 | 43 | .NOTES 44 | Author: Robert H. Osborne 45 | Alias: tobor 46 | Contact: info@osbornerpo.com 47 | 48 | 49 | .INPUTS 50 | None 51 | 52 | 53 | .OUTPUTS 54 | None 55 | #> 56 | [CmdletBinding( 57 | SupportsShouldProcess=$True, 58 | ConfirmImpact="Medium" 59 | )] # End CmdletBinding 60 | param( 61 | [Parameter( 62 | Mandatory=$True, 63 | ValueFromPipeline=$False, 64 | HelpMessage="Site server where the SMS Provider is installed.")] # End Parameter 65 | [ValidateNotNullOrEmpty()] 66 | [String]$SiteServer, 67 | 68 | [Parameter( 69 | Mandatory=$False 70 | )] # End Parameter 71 | [Switch]$UseSSL, 72 | 73 | [Parameter( 74 | Mandatory=$False 75 | )] # End Parameter 76 | [Switch]$SkipCACheck, 77 | 78 | [Parameter( 79 | Mandatory=$False 80 | )] # End Parameter 81 | [Switch]$SkipCNCheck, 82 | 83 | [Parameter( 84 | Mandatory=$False 85 | )] # End Parameter 86 | [Switch]$SkipRevocationCheck, 87 | 88 | [Parameter( 89 | Mandatory=$True, 90 | ValueFromPipeline=$True, 91 | ValueFromPipelineByPropertyName=$False, 92 | HelpMessage="Specify the Active Directory Search Base `nEXAMPLE: DC=domain,DC=com : ")] # End Parameter 93 | [ValidateScript({$_ -like "*DC=*,DC=*"})] 94 | [String]$SearchBase, 95 | 96 | [ValidateNotNull()] 97 | [System.Management.Automation.PSCredential] 98 | [System.Management.Automation.Credential()] 99 | $Credential = [System.Management.Automation.PSCredential]::Empty 100 | ) # End param 101 | 102 | BEGIN { 103 | 104 | $ComponentName = "SMS_AD_SYSTEM_DISCOVERY_AGENT" 105 | Try { 106 | 107 | Write-Verbose -Message "Determining Site Code for Site server: '$($SiteServer)'" 108 | $CIMSession = New-CimSession -Credential $Credential -ComputerName $SiteServer -SessionOption (New-CimSessionOption -UseSSL:$UseSSL.IsPresent -SkipCACheck:$SkipCACheck.IsPresent -SkipCNCheck:$SkipCNCheck.IsPresent -SkipRevocationCheck:$SkipReovcationCheck.IsPresent -Verbose:$False) -Verbose:$False 109 | $SiteCodeObjects = Get-CimInstance -CimSession $CIMSession -Namespace "Root\SMS" -ClassName SMS_ProviderLocation -ErrorAction Stop 110 | 111 | ForEach ($SiteCodeObject in $SiteCodeObjects) { 112 | 113 | If ($SiteCodeObject.ProviderForLocalSite -eq $True) { 114 | 115 | $SiteCode = $SiteCodeObject.SiteCode 116 | Write-Verbose -Message "Site Code: $($SiteCode)" 117 | Break 118 | 119 | } # End If 120 | 121 | } # End ForEach 122 | 123 | } Catch [System.UnauthorizedAccessException] { 124 | 125 | Throw "[x] Access denied" 126 | 127 | } Catch [System.Exception] { 128 | 129 | Throw "[x] Unable to determine Site Code" 130 | 131 | } # End Try Catch Catch 132 | 133 | If ($SearchBase -notlike "LDAP://*") { 134 | 135 | $SearchBase = "LDAP://$($SearchBase)" 136 | 137 | } # End If 138 | 139 | } PROCESS { 140 | 141 | Write-Verbose -Message "Determining the existing containers for selected Discovery Method" 142 | Try { 143 | 144 | $DiscoveryContainerList = New-Object -TypeName System.Collections.ArrayList 145 | $DiscoveryComponent = Get-WmiObject -Class SMS_SCI_Component -Namespace "Root\SMS\Site_$($SiteCode)" -ComputerName $SiteServer -Filter "ComponentName like '$($ComponentName)'" -Credential $Credential -ErrorAction Stop -Verbose:$False 146 | $DiscoveryPropListADContainer = $DiscoveryComponent.PropLists | Where-Object -FilterScript { $_.PropertyListName -like "AD Containers" } 147 | 148 | } Catch [System.Exception] { 149 | 150 | Throw "[x] Unable to determine existing discovery method component properties" 151 | 152 | } # End Catch 153 | 154 | Try { 155 | 156 | Write-Verbose -Message "Attempting to save changes made to the $($ComponentName) component PropList" 157 | $LdapLocations = ($DiscoveryPropListADContainer.Values | Select-String -Pattern "LDAP:\\*" | Out-String).Trim().Split([System.Environment]::NewLine) | Where-Object -FilterScript { $_ -notlike $SearchBase -and $_ -notlike "" } 158 | $DiscoveryContainerList.AddRange(@($($LdapLocations | ForEach-Object { $_; 0; 1} )))) 159 | $DiscoveryPropListADContainer.Values = $DiscoveryContainerList 160 | If ($PSCmdlet.ShouldProcess($DiscoveryComponent.Put())) { 161 | 162 | $DiscoveryComponent.Put() | Out-Null 163 | 164 | } # End If 165 | 166 | } Catch { 167 | 168 | Throw "[x] Unable to save changes made to $($ComponentName) component" 169 | 170 | } # End Try Catch 171 | 172 | } END { 173 | 174 | If ($CIMSession) { 175 | 176 | Remove-CimSession -CimSession $CIMSession -Confirm:$False -WhatIf:$False -Verbose:$False 177 | 178 | } # End If 179 | 180 | } # End END 181 | 182 | } # End Function Remove-CMSystemDiscoveryMethodContainer 183 | -------------------------------------------------------------------------------- /Remove-WindowsUpdate.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This cmdlet is for uninstalling a Windows Update. 4 | This can remove multiple hot fixes and it can remove hot fixes from an array of remote computers. 5 | 6 | 7 | .DESCRIPTION 8 | Cmdlet that is used to remove a speficied Windows Update or Updatesfrom a local computer or a remote host or hosts. 9 | A list of computer names can be piped to this function by property name. 10 | 11 | 12 | .PARAMETER HotFixID 13 | Specifies the hotfix IDs that this cmdlet gets. 14 | 15 | .PARAMETER ComputerName 16 | Specifies a remote computer. The default is the local computer. 17 | 18 | .PARAMETER Restart 19 | Indicates you wish to perform a restart after removing the update. 20 | 21 | .EXAMPLE 22 | Remove-WindowsUpdate -HotFixID "4556799" 23 | # This examples uninstalls 4556799 from the local computer if it is installed. 24 | 25 | .EXAMPLE 26 | Remove-WindowsUpdate "KB4556799" 27 | # This examples also uninstalls HotFix KB4556799 from the local computer. 28 | 29 | .EXAMPLE 30 | Remove-WindowsUpdate -HotFixID "KB4556799" -ComputerName 10.10.10.120 -Restart 31 | # This examples uninstalls HotFix KB4556799 from a remote computer at 10.10.10.120 and if a restart is needed allows it to restart. 32 | 33 | .EXAMPLE 34 | Remove-WindowsUpdate "KB4556799" 10.10.10.120 35 | # This examples also uninstalls HotFix KB4556799 from a remote computer at 10.10.10.120. 36 | 37 | 38 | .NOTES 39 | Author: Robrt H. Osborne 40 | Alias: tobor 41 | Contact: rosborne@osbornepro.com 42 | 43 | 44 | .INPUTS 45 | System.String 46 | You can pipe computer names to this cmdlet.. 47 | In Windows PowerShell 2.0, the ComputerName parameter takes input from the pipeline only by property name. 48 | In Windows PowerShell 3.0, the ComputerName parameter takes input from the pipeline by value. 49 | 50 | 51 | .OUTPUTS 52 | None, System.Management.Automation.RemotingJob 53 | This cmdlet returns a job object, if you specify the AsJob parameter. Otherwise, it does not generate any output. 54 | 55 | 56 | .LINK 57 | https://github.com/tobor88 58 | https://github.com/osbornepro 59 | https://www.powershellgallery.com/profiles/tobor 60 | https://osbornepro.com 61 | https://writeups.osbornepro.com 62 | https://btpssecpack.osbornepro.com 63 | https://www.powershellgallery.com/profiles/tobor 64 | https://www.hackthebox.eu/profile/52286 65 | https://www.linkedin.com/in/roberthosborne/ 66 | https://www.credly.com/users/roberthosborne/badges 67 | #> 68 | Function Remove-WindowsUpdate { 69 | [CmdletBinding()] 70 | param( 71 | [Parameter( 72 | Mandatory=$True, 73 | Position=0, 74 | ValueFromPipeline=$False, 75 | HelpMessage="Enter the Windows Update KB number(s) you wish to uninstall. Separate multiple values with a comma.`nExample: KB4556799','KB4556798' (4556799 is also acceptable) `n")] # End Paramater 76 | [String[]]$HotFixID, 77 | 78 | [Parameter( 79 | Mandatory=$False, 80 | Position=1, 81 | ValueFromPipeline=$True, 82 | ValueFromPipelineByPropertyName=$True, 83 | HelpMessage="Enter the name or names of the remote compute you wish to uninstall. Separate multiple values with a comma. `nExample: 'Comp1.domain.com','Comp2','10.10.10.123'`n")] # End Paramater 84 | [ValidateNotNullOrEmpty()] 85 | [String[]]$ComputerName, 86 | 87 | [Parameter( 88 | Mandatory=$False, 89 | ValueFromPipeline=$False)] 90 | [ValidateNotNull()] 91 | [System.Management.Automation.PSCredential] 92 | [System.Management.Automation.Credential()] 93 | $Credential = [System.Management.Automation.PSCredential]::Empty, 94 | 95 | [Parameter( 96 | Mandatory=$False)] 97 | [Switch][Bool]$Restart 98 | ) # End param 99 | 100 | BEGIN { 101 | 102 | If ($ComputerName) { 103 | 104 | For ($i = 0; $i -lt $ComputerName.Count ; $i++) { 105 | 106 | ForEach ($Computer in $ComputerName) { 107 | 108 | Write-Verbose "[*] Testing specified $Computer is reachable" 109 | If (Test-Connection -ComputerName $Computer -Count 2 -BufferSize 32 -Quiet -ErrorAction Inquire) { 110 | 111 | Write-Verbose "[*] $Computer is reachable" 112 | If ($Null -eq $Credential) { 113 | 114 | $Credential = Get-Credential -Message "Administrator Credentials are required to execute commands on remote hosts" -Username ($env:USERNAME + "@" + $env:USERDNSDOMAIN) 115 | 116 | } # End If 117 | 118 | New-Variable -Name "Session$i" -Value (New-PsSession -ComputerName $Computer -Credential $Credential -Name $Computer -EnableNetworkAccess -Port 5985) 119 | 120 | } # End If 121 | 122 | } # End ForEach 123 | 124 | } # End For 125 | 126 | } # End If 127 | 128 | } # End BEGIN 129 | PROCESS { 130 | 131 | If ($ComputerName) { 132 | 133 | For ($n = 0; $n -lt $ComputerName.Count; $n++) { 134 | 135 | ForEach ($C in $ComputerName) { 136 | 137 | Write-Verbose "[*] Starting connection to $C" 138 | Invoke-Command -Session (Get-Variable -Name "Session$n").Value -ArgumentList $HotFixID -ScriptBlock { 139 | param([array]$HotFixID) 140 | 141 | Write-Output "[*] $env:COMPUTERNAME: Getting list of installed patches" 142 | $PatchList = Get-CimInstance -ClassName "Win32_QuickFixEngineering" -Namespace "root\cimv2" 143 | 144 | ForEach ($HotFix in $HotFixID) { 145 | 146 | $Patch = $PatchList | Where-Object { $_.HotFixID -like "$HotFix" } 147 | Write-Output "[*] $Patch will be removed from $env:COMPUTERNAME" 148 | 149 | If (!($Patch)) { 150 | 151 | Write-Output "[!] $env:COMPUTERNAME: The Windows Update KB number you defined is not installed on $env:COMPUTERNAME. Below is a table of installed patches: " 152 | Remove-Variable -Name "Patch" 153 | 154 | $PatchList 155 | 156 | } # End If 157 | Else { 158 | 159 | Write-Output "[*] $env:COMPUTERNAME: $HotFix is installed on $env:COMPUTERNAME, continuing uninstallation" 160 | $KBNumber = $Patch.HotfixId.Replace("KB", "") | Out-String 161 | 162 | If ($Restart.IsPresent) { 163 | 164 | Write-Output "[*] $env:COMPUTERNAME: Restart switch parameter is defined. You will be prompted to restart." 165 | cmd /c wusa /uninstall /kb:$KBNumber /promptrestart /log 166 | 167 | } # End If 168 | Else { 169 | 170 | cmd /c echo y | wusa /uninstall /kb:$KBNumber /norestart /log 171 | 172 | } # End Else 173 | 174 | While (@(Get-Process wusa -ErrorAction SilentlyContinue).Count -ne 0) { 175 | 176 | Start-Sleep -Seconds 10 177 | Write-Output "[*] $env:COMPUTERNAME: Waiting for update removal to finish. Please wait..." 178 | 179 | } # End While 180 | 181 | } # End Else 182 | 183 | } # End ForEach 184 | 185 | } # End Invoke-Command 186 | 187 | Write-Output "[*] Finished removing updates from $C" 188 | 189 | } # End ForEach 190 | 191 | } # End For 192 | 193 | } # End If 194 | Else { 195 | 196 | Write-Verbose "[*] $env:COMPUTERNAME: Getting list of installed patches" 197 | $PatchList = Get-CimInstance -ClassName "Win32_QuickFixEngineering" -Namespace "root\cimv2" 198 | 199 | ForEach ($HotFix in $HotFixID) { 200 | 201 | $Patch = $PatchList | Where-Object { $_.HotFixID -like "$HotFix" } 202 | If (!($Patch)) { 203 | 204 | Write-Output "[!] $env:COMPUTERNAME: The Windows Update KB number you defined is not installed on $env:COMPUTERNAME. Below is a table of installed patches: " 205 | Remove-Variable -Name "Patch" 206 | 207 | $PatchList 208 | 209 | } # End If 210 | Else { 211 | 212 | $KBNumber = $Patch.HotfixId.Replace("KB", "") | Out-String 213 | If ($Restart.IsPresent) { 214 | 215 | Write-Output "[*] $env:COMPUTERNAME: Restart switch parameter is defined. You will be prompted to restart." 216 | cmd /c wusa /uninstall /kb:$KBNumber /promptrestart /log 217 | 218 | } # End If 219 | Else { 220 | 221 | cmd /c wusa /uninstall /kb:$KBNumber /norestart /log 222 | 223 | } # End Else 224 | 225 | While (@(Get-Process wusa -ErrorAction SilentlyContinue).Count -ne 0) { 226 | 227 | Start-Sleep -Seconds 10 228 | Write-Output "[*] Waiting for update removal to finish. Please wait..." 229 | 230 | } # End While 231 | 232 | Write-Output "[*] Update removal has completed" 233 | 234 | } # End Else 235 | 236 | } # End ForEach 237 | 238 | } # End Else 239 | 240 | } # End PROCESS 241 | END { 242 | 243 | If (Get-PsSession) { 244 | 245 | Write-Verbose "[*] Closing connection to remote computers." 246 | Remove-PsSession * 247 | 248 | } # End If 249 | 250 | } # End END 251 | 252 | } # End Function Remove-WindowsUpdate 253 | -------------------------------------------------------------------------------- /Repair-WindowsUpdate.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This cmdlet is used to perform a typical repair operation for Windows Updates that are stuck in a Retry Fail cycle 4 | 5 | 6 | .DESCRIPTION 7 | Performs actions that typicall repair Windows Updates that fail to install 8 | 9 | 10 | .PARAMETER ServiceName 11 | Define the services to stop that allow you to renamed the defined files 12 | 13 | .PARAMETER Path 14 | Define the path(s) to directories to rename that will allow windows update to try downloading and installing updates again 15 | 16 | 17 | .EXAMPLE 18 | Repair-WindowsUpdate -Path "C:\Windows\SoftwareDistribution","C:\Windows\System32\catroot2" 19 | # Stops the services cryptsvc,wuauserv,bits,msiserver and renames the Windows Update directories C:\Windows\SoftwareDistribution and C:\Windows\System32\catroot2 before restarting the computer 20 | 21 | .EXAMPLE 22 | Repair-WindowsUpdate 23 | # Stops the services cryptsvc,wuauserv,bits,msiserver and renames the Windows Update directories C:\Windows\SoftwareDistribution and C:\Windows\System32\catroot2 before restarting the computer 24 | 25 | 26 | .NOTES 27 | Author: Robrt H. Osborne 28 | Alias: tobor 29 | Contact: rosborne@osbornepro.com 30 | 31 | 32 | .INPUTS 33 | None 34 | 35 | 36 | .OUTPUTS 37 | None 38 | 39 | 40 | .LINK 41 | https://github.com/tobor88 42 | https://gitlab.com/tobor88 43 | https://www.powershellgallery.com/profiles/tobor 44 | https://osbornepro.com 45 | https://writeups.osbornepro.com 46 | https://btpssecpack.osbornepro.com 47 | https://www.powershellgallery.com/profiles/tobor 48 | https://www.hackthebox.eu/profile/52286 49 | https://www.linkedin.com/in/roberthosborne/ 50 | https://www.credly.com/users/roberthosborne/badges 51 | #> 52 | Function Repair-WindowsUpdate { 53 | [CmdletBinding(SupportsShouldProcess)] 54 | param( 55 | [Parameter( 56 | Position=0, 57 | Mandatory=$False, 58 | ValueFromPipeline=$False)] # End Parameter 59 | [ValidateScript({Get-Service -Name $_})] 60 | [String[]]$Services = @("cryptsvc","wuauserv","bits","msiserver"), 61 | 62 | [Parameter( 63 | Position=1, 64 | Mandatory=$False, 65 | ValueFromPipeline=$False)] # End Parameter 66 | [ValidateScript({Test-Path -Path $_})] 67 | [String[]]$Path = @("C:\Windows\SoftwareDistribution","C:\Windows\System32\catroot2"), 68 | 69 | [Parameter( 70 | Mandatory=$False)] # End Parameter 71 | [Switch][Bool]$Restart 72 | 73 | ) # End param 74 | 75 | If ($PSCmdlet.ShouldProcess($Path)) { 76 | 77 | Write-Output "[*] Stopping services that use the directories we need renamed" 78 | Stop-Service -Name $Services -Force -Confirm:$False 79 | 80 | ForEach ($P in $Path) { 81 | 82 | If (Test-Path -Path "$($P).bak") { 83 | 84 | Write-Output "[*] Removing the previously backed up directory $($P).bak" 85 | Remove-Item -Path "$($P).bak" -Recurse -Force -Confirm:$False 86 | 87 | } # End If 88 | 89 | Write-Output "[*] Renaming $($P) to $($P).bak" 90 | Try { 91 | 92 | Move-Item -Path $P -Destination "$($P).bak" -Force -Confirm:$False 93 | 94 | } Catch { 95 | 96 | Rename-Item -Path $P -NewName "$($P).bak" -Force -Confirm:$False 97 | 98 | } # End Catch 99 | 100 | If ($Restart.IsPresent) { 101 | 102 | Write-Output "[*] Restarting device, update Windows After the restart" 103 | Restart-Computer -Confirm:$False -Force 104 | 105 | } Else { 106 | 107 | Write-Output "[!] Machine still requires a restart to finish fixing failed update" 108 | 109 | } # End If Else 110 | 111 | } # End ForEach 112 | 113 | } Else { 114 | 115 | # The -WhatIf parameter was used. Simulating requested actions. 116 | Stop-Service -Name $Services -Force -Confirm:$False -WhatIf 117 | 118 | ForEach ($P in $Path) { 119 | 120 | If (Test-Path -Path "$($P).bak") { 121 | 122 | Remove-Item -Path "$($P).bak" -Recurse -Force -WhatIf 123 | 124 | } # End If 125 | 126 | Move-Item -Path $P -Destination "$($P).bak" -WhatIf 127 | 128 | If ($Restart.IsPresent) { 129 | 130 | Restart-Computer -WhatIf 131 | 132 | } # End If 133 | 134 | } # End ForEach 135 | 136 | } # End If Else ShouldProcess 137 | 138 | } # End Function Repair-WindowsUpdate 139 | -------------------------------------------------------------------------------- /Reset-SccmAgent.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This cmdlet is used to clear the SCCM cache and restart the SCCM service which runs all the Actions in Configuration Manager 4 | 5 | 6 | .DESCRIPTION 7 | Clear the SCCM cache and restart the CcmExec service 8 | 9 | 10 | .PARAMETER ServiceName 11 | Define the SCCM service name to restart. Default value is CcmExec 12 | 13 | .PARAMETER Path 14 | Define a path to the SCCM Cache parent directory. Default value is C:\Windows\ccmcache 15 | 16 | 17 | .EXAMPLE 18 | Reset-SccmAgent 19 | # This example restarts the CcmExec service and deletes the cache files in C:\Windows\ccmcache 20 | 21 | .EXAMPLE 22 | Reset-SccmAgent -ServiceName -Path C:\Windows\ccmcache 23 | # This example restarts the CcmExec service and deletes the cache files in C:\Windows\ccmcache 24 | 25 | 26 | .NOTES 27 | Author: Robert H. Osborne 28 | Alias: tobor 29 | Contact: rosborne@osbornepro.com 30 | 31 | 32 | .INPUTS 33 | None 34 | 35 | 36 | .OUTPUTS 37 | None 38 | 39 | 40 | .LINK 41 | https://osbornepro.com 42 | https://btpssecpack.osbornepro.com 43 | https://writeups.osbornepro.com 44 | https://github.com/OsbornePro 45 | https://github.com/tobor88 46 | https://www.powershellgallery.com/profiles/tobor 47 | https://www.hackthebox.eu/profile/52286 48 | https://www.linkedin.com/in/roberthosborne/ 49 | https://www.credly.com/users/roberthosborne/badges 50 | #> 51 | Function Reset-SccmAgent { 52 | [CmdletBinding()] 53 | param( 54 | [Parameter( 55 | Position=0, 56 | Mandatory=$False)] # End Parameter 57 | [ValidateScript({Get-Service -Name $_})] 58 | [String]$ServiceName = 'CcmExec', 59 | 60 | [Parameter( 61 | Position=1, 62 | Mandatory=$False 63 | #HelpMessage="Define the SCCM directory containing cache files EXAMPLE: C:\Windows\ccmcache" 64 | )] # End Parameter 65 | [ValidateScript({Test-Path -Path $_})] 66 | [String]$Path = "C:\Windows\ccmcache" 67 | ) # End param 68 | 69 | Write-Verbose "Restarting the $ServiceName service" 70 | Restart-Service -Name $ServiceName -Force -Confirm:$False -PassThru 71 | 72 | Try { 73 | 74 | Write-Verbose "Deleting the file $Path" 75 | Remove-Item -Path $Path -Recurse -Force -ErrorAction Stop 76 | 77 | } Catch { 78 | 79 | Write-Error $_.Exception.Message 80 | 81 | } # End Catch 82 | 83 | } # End Reset-SccmAgent 84 | -------------------------------------------------------------------------------- /Update-Windows.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Update-Windows is a cmdlet created to update Windows when updates are available. This cmdlet also creates logs of update attempts 4 | System Administrators will be alerted if updates fail. This cmdlet creates a CSV file to be uploaded into a SQL database. 5 | Originally I had this function upload the csv contents into a SQL database. To better coform to PowerShell scripting guidelines I am changing this behavior. 6 | 7 | 8 | .DESCRIPTION 9 | This cmdlet updates windows, logs results, and alerts administrators of failures. 10 | 11 | 12 | .EXAMPLE 13 | Update-Windows 14 | # This example checks for all available Windows Updates and the downloads and installs them logging the results to C:\Windows\Temp\$env:COMPUTERNAME 15 | 16 | 17 | .NOTES 18 | Author: Robert H. Osborne 19 | Alias: tobor 20 | Contact: rosborne@osbornepro.com 21 | 22 | .LINK 23 | https://github.com/tobor88 24 | https://github.com/osbornepro 25 | https://www.powershellgallery.com/profiles/tobor 26 | https://osbornepro.com 27 | https://writeups.osbornepro.com 28 | https://btpssecpack.osbornepro.com 29 | https://www.powershellgallery.com/profiles/tobor 30 | https://www.hackthebox.eu/profile/52286 31 | https://www.linkedin.com/in/roberthosborne/ 32 | https://www.credly.com/users/roberthosborne/badges 33 | #> 34 | Function Update-Windows { 35 | [CmdletBinding()] 36 | param () # End param 37 | 38 | $ErrorActionPreference = "SilentlyContinue" 39 | $Today = Get-Date 40 | $FormattedDate = Get-Date -Format MM.dd.yyyy 41 | $UpdateCollection = New-Object -ComObject Microsoft.Update.UpdateColl 42 | $UpdateSearch = New-Object -ComObject Microsoft.Update.Searcher 43 | $Session = New-Object -ComObject Microsoft.Update.Session 44 | 45 | If ($Error) { 46 | 47 | $Error.Clear() 48 | 49 | } # End If 50 | 51 | Write-Verbose "`n`tInitialising and Checking for Applicable Updates. Please wait ..." 52 | $Result = $UpdateSearch.Search("IsInstalled=0 and Type='Software' and IsHidden=0") 53 | 54 | If ($Result.Updates.Count -EQ 0) { 55 | 56 | Write-Verbose "`t$env:COMPUTERNAME is currently up to date." 57 | 58 | } # End if 59 | Else { 60 | 61 | $ReportFile = "C:\Windows\Temp\$env:COMPUTERNAME\$env:COMPUTERNAME`_Report_$FormattedDate.txt" 62 | If (Test-Path -Path $ReportFile) { 63 | 64 | Write-Verbose "Update attempt was run already today. Previous attempt saved as a .txt.old file. New File is located at the following location. `nLOCATION:$ReportFile" 65 | Rename-Item -Path $ReportFile -NewName ("$ReportFile.old") -Force 66 | 67 | } # End If 68 | Elseif (!(Test-Path -Path "C:\Windows\Temp\$env:COMPUTERNAME")) { 69 | 70 | Write-Verbose "Logging folder previously did not exist and is being created at the below location. `nLOCATION: C:\Windows\Temp\$env:COMPUTERNAME" 71 | New-Item -Path "C:\Windows\Temp\$env:COMPUTERNAME" -ItemType Directory -Force | Out-Null 72 | 73 | } # End Elseif 74 | 75 | New-Item -Path $ReportFile -Type 'File' -Force -Value "#===================================================================#`n# Update Report #`n#===================================================================#" | Out-Null 76 | 77 | Add-Content -Path $ReportFile -Value "`n`nComputer Hostname : $env:COMPUTERNAME`r`nCreation Date : $Today`rReport Directory : C:\Windows\Temp\$env:COMPUTERNAME`r`n" 78 | Add-Content -Path $ReportFile -Value "---------------------------------------------------------------------`nAVAILABLE UPDATES`n---------------------------------------------------------------------`r" 79 | 80 | Write-Verbose "`t Preparing List of Applicable Updates For $env:COMPUTERNAME..." 81 | For ($Counter = 0; $Counter -lt $Result.Updates.Count; $Counter++) { 82 | 83 | $DisplayCount = $Counter + 1 84 | $Update = $Result.Updates.Item($Counter) 85 | $UpdateTitle = $Update.Title 86 | 87 | Add-Content -Path $ReportFile -Value "$DisplayCount.) $UpdateTitle" 88 | 89 | $UpdateResultInfo = New-Object -TypeName System.Management.Automation.PSCustomObject -Property @{ 90 | UpdateTitle = $UpdateTitle 91 | Hostname = $env:COMPUTERNAME 92 | Date = $FormattedDate } # End Property 93 | 94 | New-Variable -Name UpdateResultInfo$Counter -Value $UpdateResultInfo 95 | 96 | } # End For 97 | 98 | $Counter = 0 99 | $DisplayCount = 0 100 | 101 | Write-Verbose "`t Initialising Download of Applicable Updates ..." 102 | Add-Content -Path $ReportFile -Value "`n---------------------------------------------------------------------`nINITIALISING UPDATE DOWNLOADS`n---------------------------------------------------------------------`n" 103 | 104 | $Downloader = $Session.CreateUpdateDownloader() 105 | $UpdatesList = $Result.Updates 106 | 107 | For ($Counter = 0; $Counter -LT $Result.Updates.Count; $Counter++) { 108 | 109 | $UpdateCollection.Add($UpdatesList.Item($Counter)) | Out-Null 110 | $ShowThis = $UpdatesList.Item($Counter).Title 111 | $DisplayCount = $Counter + 1 112 | 113 | Add-Content -Path $ReportFile -Value "$DisplayCount.) Downloading Update: $ShowThis `r" 114 | 115 | $Downloader.Updates = $UpdateCollection 116 | $Track = $Downloader.Download() 117 | 118 | If (($Track.HResult -EQ 0) -AND ($Track.ResultCode -EQ 2)) { 119 | 120 | Add-Content -Path $ReportFile -Value "`tDownload Status: SUCCESS" 121 | 122 | If ($ShowThis -like ((Get-Variable -Name UpdateResultInfo($Counter)).Title)) { 123 | 124 | Add-Member -InputObject (Get-Variable -Name UpdateResultInfo($Counter)) -NotePropertyName "DownloadStatus" -NotePropertyValue 'Successfully Downloaded' 125 | 126 | } # End If 127 | 128 | } # End If 129 | 130 | Else { 131 | 132 | $FailError = $Error[0] 133 | Add-Content -Path $ReportFile -Value "`tDownload Status: FAILED With Error `n`t`t $FailError" 134 | If ($ShowThis -like ((Get-Variable -Name UpdateResultInfo($Counter)).Title)) { 135 | 136 | Add-Member -InputObject (Get-Variable -Name UpdateResultInfo($Counter)) -NotePropertyName "DownloadStatus" -NotePropertyValue $FailError 137 | 138 | } # End If 139 | 140 | $Error.Clear() 141 | Add-content -Path $ReportFile -Value "`r" 142 | 143 | } # End Else 144 | 145 | } # End For 146 | 147 | $Counter = 0 148 | $DisplayCount = 0 149 | 150 | Write-Verbose "`tStarting Installation of Downloaded Updates ..." 151 | Add-Content -Path $ReportFile -Value "---------------------------------------------------------------------`nUPDATE INSTALLATION`n---------------------------------------------------------------------`n" 152 | 153 | $Installer = New-Object -ComObject Microsoft.Update.Installer 154 | 155 | For ($Counter = 0; $Counter -lt $UpdateCollection.Count; $Counter++) { 156 | 157 | $Track = $Null 158 | $DisplayCount = $Counter + 1 159 | $WriteThis = $UpdateCollection.Item($Counter).Title 160 | 161 | Add-Content -Path $ReportFile -Value "$DisplayCount.) Installing Update: $WriteThis `r" 162 | 163 | $Installer.Updates = $UpdateCollection 164 | 165 | Try { 166 | 167 | $Track = $Installer.Install() 168 | 169 | Add-Content -Path $ReportFile -Value " - Update Installation Status: SUCCESS`n" 170 | 171 | If ($WriteThis -like ((Get-Variable -Name UpdateResultInfo($Counter)).Title)) { 172 | 173 | Add-Member -InputObject (Get-Variable -Name UpdateResultInfo($Counter)) -NotePropertyName "InstallStatus" -NotePropertyValue 'Successfully Installed' 174 | 175 | } # End If 176 | 177 | } Catch { 178 | 179 | [System.Exception] 180 | $InstallError = $Error[0] 181 | Add-Content -Path $ReportFile -Value " - Update Installation Status: FAILED With Error `n`t`t$InstallError`r" 182 | 183 | If ($WriteThis -like ((Get-Variable -Name UpdateResultInfo($Counter)).Title)) { 184 | 185 | Add-Member -InputObject (Get-Variable -Name UpdateResultInfo($Counter)) -NotePropertyName "InstallStatus" -NotePropertyValue $InstallError 186 | 187 | } # End If 188 | 189 | $Error.Clear() 190 | 191 | } # End Try Catch 192 | 193 | } # End For 194 | 195 | Add-Content -Path $ReportFile -Value "#===================================================================#`n# END OF REPORT #`n#===================================================================#" 196 | 197 | $Obj = New-Object -TypeName PSCustomObject -Properties @{ 198 | UpdateTitle=$UpdateResultInfo.UpdateTitle 199 | HostName=$UpdateResultInfo.HostName 200 | Date=$UpdateResultInfo.Date 201 | DownloadStatus=$UpdateResultInfo.DownloadStatus 202 | InstallStatus=$UpdateResultInfo.InstallStatus 203 | } # End Properties 204 | 205 | Write-Output $Obj 206 | 207 | } # End Else 208 | 209 | } # End Funtion Update-Windows 210 | --------------------------------------------------------------------------------