Install-DotNet48.ps1
<#PSScriptInfo .VERSION 0.2.3 .GUID 78df1cd1-be65-4ce3-8717-280efb551624 .AUTHOR ADB .COMPANYNAME POS with Logic .COPYRIGHT 2021 ADB .TAGS .LICENSEURI .PROJECTURI .ICONURI .EXTERNALMODULEDEPENDENCIES Deploy-Dotnet48 .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES .DESCRIPTION Deploy .net 4.8 and required dependencies, Updates WMF to 5.1 and installs Universal C runtime #> <# since powershell 2.0 does not have the --% stop parsing, will need to copy installer files to target, echo to a bat file a list of required commands to execute local install #> [CmdletBinding(DefaultParameterSetName = 'Deploy')] param ( [Parameter(Mandatory = $true, HelpMessage = "Enter a target computer name to deploy")] [Alias('Hostname', 'CN')] [string[]]$computername, [parameter(ParameterSetName = 'Deploy', Mandatory = $true)] [string]$share, [Parameter(Mandatory = $true)] [ValidateNotNull()] [System.Management.Automation.PSCredential] [System.Management.Automation.Credential()] [pscredential] $Credential = [System.Management.Automation.PSCredential]::Empty, [Parameter(ParameterSetName = 'Deploy', Mandatory = $false)] [int] [ValidateRange(30, 1000)] $reboot_timeout, [parameter(ParameterSetName = 'check')] [switch]$check ) Write-Verbose "Execution Metadata:" Write-Verbose "User = $($env:userdomain)\$($env:USERNAME)" $id = [System.Security.Principal.WindowsIdentity]::GetCurrent() $IsAdmin = [System.Security.Principal.WindowsPrincipal]::new($id).IsInRole('administrators') Write-Verbose "Is Admin = $IsAdmin" Write-Verbose "Computername = $env:COMPUTERNAME" Write-Verbose "OS = $((Get-CimInstance Win32_Operatingsystem).Caption)" Write-Verbose "Host = $($host.Name)" Write-Verbose "PSVersion = $($PSVersionTable.PSVersion)" Write-Verbose "Runtime = $(Get-Date)" Write-Verbose "[$((get-date).TimeOfDay.ToString()) BEGIN ] Starting: $($MyInvocation.Line)" [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 try { if (! (Get-Module -name deploy-dotnet48 -ListAvailable -ErrorAction Stop)) { Install-Module deploy-dotnet48 -Force -ErrorAction Stop } update-Module -name deploy-dotnet48 -Force -ErrorAction SilentlyContinue Import-Module -name deploy-dotnet48 -Force -ErrorAction Stop } catch { return; } #verify that share exists if (! ($PSBoundParameters.ContainsKey('check'))) { $params += @{ 'UNC' = $share 'verbose' = $VerbosePreference 'test' = $true 'create' = $true } $share = Resolve-UNCProperPath @params } #initialize an array of assets and their properties $assets = [System.Collections.ArrayList]@() $assets += ([PSCustomObject]@{ 'name' = 'Certificate' 'OS' = '*' 'arch' = '*' 'URL' = 'http://media.kaspersky.com/utilities/CorporateUtilities/rootsupd.zip' 'method' = 'webclient' 'pkg' = 'rootsupd.exe' 'pre_process' = $null 'post_precess' = $null 'cmd' = $null 'script' = $null }) $assets += ([PSCustomObject]@{ 'name' = 'PSTools' 'OS' = '*' 'arch' = '*' 'URL' = 'https://download.sysinternals.com/files/PSTools.zip' 'method' = 'Start-BitsTransfer' 'pkg' = 'psexec.exe' 'pre_process' = $null 'post_precess' = $null 'cmd' = $null 'script' = $null }) $assets += ([PSCustomObject]@{ 'Name' = 'dotnet 4.8' 'OS' = '*' 'arch' = '*' 'URL' = 'https://download.visualstudio.microsoft.com/download/pr/014120d7-d689-4305-befd-3cb711108212/0fd66638cde16859462a6243a4629a50/ndp48-x86-x64-allos-enu.exe' 'method' = 'Start-BitsTransfer' 'pkg' = 'ndp48-x86-x64-allos-enu.exe' 'pre_process' = "New-Item -Path C:\TEMP -ItemType Directory -Force | Out-Null ; copy-item -path $("$share" + "ndp48-x86-x64-allos-enu.exe") -destination c:\temp\" 'post_precess' = $null 'cmd' = "$share" + "psexec.exe -acceptEULA -s " + "`"c:\temp\ndp48-x86-x64-allos-enu.exe`" /q /norestart /log C:\Temp\NetFx48.txt" 'script' = $null 'pass' = @" (Invoke-Command -Session `$session -ScriptBlock { Get-ItemProperty -ErrorAction SilentlyContinue -path 'hklm:\SOFTWARE\Microsoft\net Framework setup\ndp\v4\full' -Name version }).version "@ }) $assets += ([PSCustomObject]@{ 'Name' = 'WMF 5.1 Win7 x86' 'OS' = '6.1' 'arch' = '32' 'URL' = 'https://download.microsoft.com/download/6/F/5/6F5FF66C-6775-42B0-86C4-47D41F2DA187/Win7-KB3191566-x86.zip' 'method' = 'Start-BitsTransfer' 'pkg' = 'Win7-KB3191566-x86.msu' 'pre_process' = $null 'post_precess' = $null 'cmd' = $null 'script' = @" Copy-Item -Path $("$share")Win7-KB3191566-x86.msu -Destination c:\temp\ Start-Process 'wusa.exe' -ArgumentList `"c:\temp\Win7-KB3191566-x86.msu /extract:C:\MSU\`" -Wait -PassThru Start-Process dism.exe -ArgumentList `"/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2872035-x86.cab /NoRestart`" -Wait -PassThru Start-Process dism.exe -ArgumentList `"/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2872047-x86.cab /NoRestart`" -Wait -PassThru Start-Process dism.exe -ArgumentList `"/online /add-package /PackagePath:C:\MSU\Windows6.1-KB3033929-x86.cab /NoRestart`" -Wait -PassThru Start-Process dism.exe -ArgumentList `"/online /add-package /PackagePath:C:\MSU\Windows6.1-KB3191566-x86.cab /NoRestart`" -Wait -PassThru Remove-Item C:\MSU -Recurse -Force "@ 'pass' = @" Invoke-Command -Session `$session -ScriptBlock { (`$PSVersionTable).PSVersion.Major } "@ }) $assets += ([PSCustomObject]@{ 'Name' = 'WMF 5.1 Win7 x64' 'OS' = '6.1' 'arch' = '64' 'URL' = 'https://download.microsoft.com/download/6/F/5/6F5FF66C-6775-42B0-86C4-47D41F2DA187/Win7AndW2K8R2-KB3191566-x64.zip' 'method' = 'Start-BitsTransfer' 'pkg' = 'Win7AndW2K8R2-KB3191566-x64.msu' 'pre_process' = $null 'post_precess' = $null 'cmd' = $null 'script' = @" Copy-Item -Path $("$share")Win7AndW2K8R2-KB3191566-x64.msu -Destination C:\temp\ Start-Process 'wusa.exe' -ArgumentList `"c:\temp\Win7AndW2K8R2-KB3191566-x64.msu /extract:C:\MSU\`" -Wait -PassThru Start-Process dism.exe -ArgumentList `"/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2809215-x64.cab /NoRestart`" -Wait -PassThru Start-Process dism.exe -ArgumentList `"/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2872035-x64.cab /NoRestart`" -Wait -PassThru Start-Process dism.exe -ArgumentList `"/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2872047-x64.cab /NoRestart`" -Wait -PassThru Start-Process dism.exe -ArgumentList `"/online /add-package /PackagePath:C:\MSU\Windows6.1-KB3033929-x64.cab /NoRestart`" -Wait -PassThru Start-Process dism.exe -ArgumentList `"/online /add-package /PackagePath:C:\MSU\Windows6.1-KB3191566-x64.cab /NoRestart`" -Wait -PassThru Remove-Item C:\MSU -Recurse -Force "@ 'pass' = @" Invoke-Command -Session `$session -ScriptBlock { (`$PSVersionTable).PSVersion.Major } "@ }) $assets += ([PSCustomObject]@{ 'Name' = 'WMF 5.1 Win 8.1 x64' 'OS' = '6.3' 'arch' = '64' 'URL' = 'https://download.microsoft.com/download/6/F/5/6F5FF66C-6775-42B0-86C4-47D41F2DA187/Win8.1AndW2K12R2-KB3191564-x64.msu' 'method' = 'Start-BitsTransfer' 'pkg' = 'Win8.1AndW2K12R2-KB3191564-x64.msu' 'pre_process' = $null 'post_precess' = $null 'cmd' = $null 'script' = @" Copy-Item -Path $("$share")Win8.1AndW2K12R2-KB3191564-x64.msu -Destination c:\temp\ Start-Process 'wusa.exe' -ArgumentList `"c:\temp\Win8.1AndW2K12R2-KB3191564-x64.msu /extract:C:\MSU\`" -Wait -PassThru Start-Process dism.exe -ArgumentList `"/online /add-package /PackagePath:C:\MSU\WindowsBlue-KB3191564-x64.cab /NoRestart`" -Wait -PassThru Remove-Item C:\MSU -Recurse -Force "@ 'pass' = @" Invoke-Command -Session `$session -ScriptBlock { (`$PSVersionTable).PSVersion.Major } "@ }) $assets += ([PSCustomObject]@{ 'Name' = 'UCRT Win 7 x86' 'OS' = '6.1' 'arch' = '32' 'URL' = 'https://download.microsoft.com/download/3/1/1/311C06C1-F162-405C-B538-D9DC3A4007D1/WindowsUCRT.zip' 'method' = 'Start-BitsTransfer' 'pkg' = 'Windows6.1-KB3118401-x86.msu' 'pre_process' = $null 'post_precess' = $null 'cmd' = $null 'script' = @" Copy-Item -Path $("$share")Windows6.1-KB3118401-x86.msu -Destination c:\temp\ Start-Process 'wusa.exe' -ArgumentList `"c:\temp\Windows6.1-KB3118401-x86.msu /extract:C:\MSU\`" -Wait -PassThru Start-Process dism.exe -ArgumentList `"/online /add-package /PackagePath:C:\MSU\Windows6.1-KB3118401-x86.cab /NoRestart`" -Wait -PassThru Remove-Item C:\MSU -Recurse -Force "@ 'pass' = @" ((Invoke-Command -Session `$session -ScriptBlock { (((Get-Item -ErrorAction SilentlyContinue `$env:windir\system32\ucrtbase_clr0400.dll).VersionInfo).ProductVersion) }) -ge 14.10) -or ((Invoke-Command -session `$session -ScriptBlock { (Test-Path -Path `$env:windir\system32\ucrtbase.dll) }) -eq `$false) "@ }) $assets += ([PSCustomObject]@{ 'Name' = 'UCRT Win 7 x64' 'OS' = '6.1' 'arch' = '64' 'URL' = 'https://download.microsoft.com/download/3/1/1/311C06C1-F162-405C-B538-D9DC3A4007D1/WindowsUCRT.zip' 'method' = 'Start-BitsTransfer' 'pkg' = 'Windows6.1-KB3118401-x64.msu' 'pre_process' = $null 'post_precess' = $null 'cmd' = $null 'script' = @" Copy-Item -Path $("$share")Windows6.1-KB3118401-x86.msu -Destination c:\temp\ Start-Process 'wusa.exe' -ArgumentList `"c:\temp\Windows6.1-KB3118401-x64.msu /extract:C:\MSU\`" -Wait -PassThru Start-Process dism.exe -ArgumentList `"/online /add-package /PackagePath:C:\MSU\Windows6.1-KB3118401-x64.cab /NoRestart`" -Wait -PassThru Remove-Item C:\MSU -Recurse -Force "@ 'pass' = @" ((Invoke-Command -Session `$session -ScriptBlock { (((Get-Item -ErrorAction SilentlyContinue `$env:windir\system32\ucrtbase_clr0400.dll).VersionInfo).ProductVersion) }) -ge 14.10) -or ((Invoke-Command -session `$session -ScriptBlock { (Test-Path -Path `$env:windir\system32\ucrtbase.dll) }) -eq `$false) "@ }) $assets += ([PSCustomObject]@{ 'Name' = 'UCRT Win 8.1 x64' 'OS' = '6.3' 'arch' = '64' 'URL' = 'https://download.microsoft.com/download/3/1/1/311C06C1-F162-405C-B538-D9DC3A4007D1/WindowsUCRT.zip' 'method' = 'Start-BitsTransfer' 'pkg' = 'Windows8.1-KB3118401-x64.msu' 'pre_process' = $null 'post_precess' = $null 'cmd' = $null 'script' = @" Copy-Item -Path $("$share")Windows6.1-KB3118401-x86.msu -Destination c:\temp\ Start-Process 'wusa.exe' -ArgumentList `"c:\temp\Windows8.1-KB3118401-x64.msu /extract:C:\MSU\`" -Wait -PassThru Start-Process dism.exe -ArgumentList `"/online /add-package /PackagePath:C:\MSU\Windows8.1-KB3118401-x64.cab /NoRestart`" -Wait -PassThru Remove-Item C:\MSU -Recurse -Force "@ 'pass' = @" ((Invoke-Command -Session `$session -ScriptBlock { (((Get-Item -ErrorAction SilentlyContinue `$env:windir\system32\ucrtbase_clr0400.dll).VersionInfo).ProductVersion) }) -ge 14.10) -or ((Invoke-Command -session `$session -ScriptBlock { (Test-Path -Path `$env:windir\system32\ucrtbase.dll) }) -eq `$false) "@ }) if (! ($PSBoundParameters.ContainsKey('check'))) { foreach ($asset in $assets) { $asset | Add-Member -Name 'fullpath' -Value (Join-Path -Path $share -ChildPath $asset.pkg) -MemberType NoteProperty if ($null -ne $asset.cmd) { $asset | Add-Member -MemberType NoteProperty -Value (join-path -path $share -childpath ($($asset.pkg) + (".bat"))) -Name 'ScriptFullPath' } } #download and process the required assets to deploy Get-RequierdAssets -assets $assets -share $share -verbose:$VerbosePreference } #check each computer for patch state foreach ($computer in $computername) { try { $params = @{ 'ComputerName' = $computer 'Assets' = $assets 'Credential' = $Credential 'Verbose' = $VerbosePreference 'ErrorAction' = 'stop' } $result = Get-PatchState @params $obj = [PSCustomObject]@{ 'ComputerName' = $computer 'RebootState' = $null } #update the computer object with the assets to be installed Copy-Property -From $result -To $obj foreach ($p in Get-Member -In $obj -MemberType NoteProperty) { $ret = switch ($p.name) { #do not evaluate computername 'computername' { $obj.($p.Name) } 'ndp48-x86-x64-allos-enu.exe' { if (($obj.($p.Name)) -lt '4.8') { 'missing' } else { 'present' } } 'Win7-KB3191566-x86.msu' { if (($obj.($p.Name)) -lt '5') { 'missing' } else { 'NA' } } 'Win7AndW2K8R2-KB3191566-x64.msu' { if (($obj.($p.Name)) -lt '5') { 'missing' } else { 'NA' } } 'Win8.1AndW2K12R2-KB3191564-x64.msu' { if (($obj.($p.Name)) -lt '5') { 'missing' } else { 'NA' } } Default { if (($obj.($p.Name)) -eq 'True') { 'present' } elseif (($obj.($p.Name)) -eq 'False') { 'missing' } else { 'NA' } } } $obj.($p.Name) = $ret } Write-Verbose $obj if (! ($PSBoundParameters.ContainsKey('check'))) { #deploy missing assets $missingassets = $assets | Where-Object -FilterScript { $obj.($_.pkg) -eq 'missing' } foreach ($asset in $missingassets) { $params = @{ 'ComputerName' = $computer 'Asset' = $asset 'Credential' = $Credential 'Share' = $share 'Verbose' = $VerbosePreference } if ($PSBoundParameters.ContainsKey('reboot_timeout')) { $params += @{'reboot_timeout' = $reboot_timeout } } $result = deploy-patch @params $obj.$($asset.pkg) = $result.Status $obj.RebootState = $($result.RebootState) } } Write-Output $obj } catch {} } #foreach computer |