Deploy-DotNet48.psm1
function Get-RequierdAssets { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [object[]]$assets, [Parameter(Mandatory = $true)] [string] $share ) $ErrorActionPreference = 'stop' Write-Verbose "checking required assets" [System.IO.Directory]::SetCurrentDirectory($share) [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true } [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 foreach ($asset in $assets) { Write-Verbose "processing $($asset.name)" $dl = ($share) + (Split-Path -Path $asset.URL -Leaf) if (!(Test-Path -Path $asset.fullpath)) { if ($asset.method -eq 'webclient') { (New-Object System.Net.WebClient).DownloadFile($asset.URL, $dl) } else { if ($asset.method -eq 'Start-BitsTransfer') { $param = @{ 'source' = $asset.URL 'destination' = $dl } } if ($asset.method -eq 'Invoke-WebRequest') { $param = @{ 'uri' = $asset.URL 'OutFile' = $dl } } & $asset.method @param } # TODO error handling $ext = [io.path]::GetExtension($dl) $ext = $ext.replace('.', '') if ($ext -eq 'zip') { Expand-Archive -Path $dl -DestinationPath $share -Force Remove-Item $dl -ErrorAction SilentlyContinue } } if ($null -ne $asset.cmd) { New-Item -Path $asset.scriptfullpath -Value $asset.cmd -Force | Out-Null } } } #function Get-RequiredAssets function Get-PatchState { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [Alias('Hostname', 'CN')] [string[]] $computername, [Parameter(Mandatory = $true)] [object[]]$assets, [Parameter(Mandatory = $true)] [ValidateNotNull()] [System.Management.Automation.PSCredential] [System.Management.Automation.Credential()] [pscredential] $Credential ) foreach ($computer in $computername) { Write-Verbose "processing $computer" $params = @{ 'computername' = $computer 'Authentication' = 'CredSSP' 'Credential' = $Credential 'ErrorAction' = 'Stop' } try { $session = New-PSSession @params } catch { Write-Error "Failed to connect to $computer" return; } $os = Invoke-Command -Session $session -ScriptBlock { Get-WmiObject -Class Win32_OperatingSystem } $arch = $os.osarchitecture $os = $os | Select-Object -ExpandProperty version $ver = $os.IndexOf('.') + 2 $os = $os.remove($ver) $arch = $arch.remove(2) $obj = [PSCustomObject]@{ } # check asset installtion required environment, OS and Arch. foreach ($asset in $assets) { if (($os -like $asset.os) -and ($arch -like $asset.arch) -and ($null -ne $asset.pass)) { $result = Invoke-Expression $asset.pass } elseif (($os -like $asset.os) -and ($arch -like $asset.arch) -and ($null -eq $asset.pass)) { $result = 'false' } else { $result = 'NA' } $obj | Add-Member -Name $asset.pkg -MemberType NoteProperty -Value $result } Write-Output $obj Remove-PSSession $session } } function Deploy-Patch { [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Enter a target computer name to deploy")] [Alias('Hostname', 'CN')] [string[]]$computername, [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [object]$asset, [Parameter(Mandatory = $true)] [string]$share, [Parameter(Mandatory = $true)] [ValidateNotNull()] [System.Management.Automation.PSCredential] [System.Management.Automation.Credential()] [pscredential] $Credential, [Parameter(Mandatory = $false)] [int] [ValidateRange(30, 1000)] $reboot_timeout ) foreach ($computer in $computername) { Write-Verbose "processing $computer" $params = @{ 'computername' = $computer 'Authentication' = 'CredSSP' 'Credential' = $Credential 'ErrorAction' = 'Stop' } try { $session = New-PSSession @params } catch { Write-Error "Failed to connect to $computer" return; } Write-Verbose "installing $($asset.name)" #evaluate deployment method if ($null -ne $asset.pre_process) { $Script = [scriptblock]::Create($asset.pre_process) Invoke-Command -Session $session -ArgumentList $asset.pre_process -ScriptBlock $Script } if ($null -ne $asset.script) { $Script = [scriptblock]::Create($asset.script) Invoke-Command -Session $session -ScriptBlock $Script } elseif ($null -ne $asset.cmd) { Invoke-Command -Session $session -ArgumentList $asset.scriptfullpath -ScriptBlock { & $args[0] } } else { Invoke-Command -Session $session -ArgumentList $asset.fullpath -ScriptBlock { Start-Process $args[0] } } $ExitCode = Invoke-Command -Session $session -ScriptBlock { $LASTEXITCODE } if ($null -ne $asset.post_process) { $Script = [scriptblock]::Create($asset.post_process) Invoke-Command -Session $session -ArgumentList $asset.post_process -ScriptBlock $Script } $rebootState = (Get-RebootState -credential $Credential -ComputerName $Computer).IsRebootPending if (($rebootState -eq $true) -and ($PSBoundParameters.ContainsKey('reboot_timeout'))) { $params = @{ 'computername' = $computer 'Force' = $true 'Wait' = $true 'For' = 'WinRM' 'timeout' = $reboot_timeout 'Credential' = $Credential } Write-Verbose "Rebooting $computer" Restart-Computer @params $rebootState = 'rebooted' } $obj = [PSCustomObject]@{ 'Computername' = $computer 'Asset' = $asset 'Status' = $ExitCode 'RebootState' = $rebootState } Write-Output $obj Remove-PSSession $session } #foreach computer } function Resolve-UNCProperPath { [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string]$UNC, [switch]$test ) #resolve mount point to full path if (($unc).Contains(':')){ $UNC = ($UNC).Substring(0, 1) $unc = (Get-PSDrive -Name $UNC).Root } else { while ($UNC -notmatch '\\$') { $UNC += '\' } while ($UNC -notmatch '^\\\\') { $UNC = '\' + $UNC } } while (!(Test-Path -Path $UNC) -and ($PSBoundParameters.ContainsKey('test'))) { Write-Error "invalid share" $UNC = Read-Host "enter valid share" $UNC = Resolve-UNCProperPath -UNC $UNC -test } return $UNC } #function function Copy-Property ($From, $To) { foreach ($p in Get-Member -In $From -MemberType NoteProperty) { Add-Member -In $To -MemberType NoteProperty -Name $p.Name -Value $From.$($p.Name) -Force } } function Get-RebootState { [CmdletBinding()] param( [Parameter(Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias("CN", "Computer")] [String[]] $ComputerName = $env:COMPUTERNAME, [Parameter()] [System.Management.Automation.PSCredential] [System.Management.Automation.CredentialAttribute()] $Credential, [Parameter()] [Switch] $Detailed, [Parameter()] [Switch] $SkipConfigurationManagerClientCheck, [Parameter()] [Switch] $SkipPendingFileRenameOperationsCheck ) process { foreach ($computer in $ComputerName) { $invokeWmiMethodParameters = @{ Namespace = 'root/default' Class = 'StdRegProv' Name = 'EnumKey' ComputerName = $computer ErrorAction = 'silentlycontinue' } $hklm = [UInt32] "0x80000002" if ($PSBoundParameters.ContainsKey('Credential')) { $invokeWmiMethodParameters.Credential = $Credential } ## Query the Component Based Servicing Reg Key $invokeWmiMethodParameters.ArgumentList = @($hklm, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\') $registryComponentBasedServicing = (Invoke-WmiMethod @invokeWmiMethodParameters).sNames -contains 'RebootPending' ## Query WUAU from the registry $invokeWmiMethodParameters.ArgumentList = @($hklm, 'SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\') $registryWindowsUpdateAutoUpdate = (Invoke-WmiMethod @invokeWmiMethodParameters).sNames -contains 'RebootRequired' ## Query JoinDomain key from the registry - These keys are present if pending a reboot from a domain join operation $invokeWmiMethodParameters.ArgumentList = @($hklm, 'SYSTEM\CurrentControlSet\Services\Netlogon') $registryNetlogon = (Invoke-WmiMethod @invokeWmiMethodParameters).sNames $pendingDomainJoin = ($registryNetlogon -contains 'JoinDomain') -or ($registryNetlogon -contains 'AvoidSpnSet') ## Query ComputerName and ActiveComputerName from the registry and setting the MethodName to GetMultiStringValue $invokeWmiMethodParameters.Name = 'GetMultiStringValue' $invokeWmiMethodParameters.ArgumentList = @($hklm, 'SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName\', 'ComputerName') $registryActiveComputerName = Invoke-WmiMethod @invokeWmiMethodParameters $invokeWmiMethodParameters.ArgumentList = @($hklm, 'SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName\', 'ComputerName') $registryComputerName = Invoke-WmiMethod @invokeWmiMethodParameters $pendingComputerRename = $registryActiveComputerName -ne $registryComputerName -or $pendingDomainJoin ## Query PendingFileRenameOperations from the registry if (-not $PSBoundParameters.ContainsKey('SkipPendingFileRenameOperationsCheck')) { $invokeWmiMethodParameters.ArgumentList = @($hklm, 'SYSTEM\CurrentControlSet\Control\Session Manager\', 'PendingFileRenameOperations') $registryPendingFileRenameOperations = (Invoke-WmiMethod @invokeWmiMethodParameters).sValue $registryPendingFileRenameOperationsBool = [bool]$registryPendingFileRenameOperations } ## Query ClientSDK for pending reboot status, unless SkipConfigurationManagerClientCheck is present if (-not $PSBoundParameters.ContainsKey('SkipConfigurationManagerClientCheck')) { $invokeWmiMethodParameters.NameSpace = 'ROOT\ccm\ClientSDK' $invokeWmiMethodParameters.Class = 'CCM_ClientUtilities' $invokeWmiMethodParameters.Name = 'DetermineifRebootPending' $invokeWmiMethodParameters.Remove('ArgumentList') try { $sccmClientSDK = Invoke-WmiMethod @invokeWmiMethodParameters $systemCenterConfigManager = $sccmClientSDK.ReturnValue -eq 0 -and ($sccmClientSDK.IsHardRebootPending -or $sccmClientSDK.RebootPending) } catch { $systemCenterConfigManager = $null #Write-Warning -Message ($script:localizedData.invokeWmiClientSDKError -f $computer) } } $isRebootPending = $registryComponentBasedServicing -or ` #$pendingComputerRename -or ` #$pendingDomainJoin -or ` $registryPendingFileRenameOperationsBool -or ` $systemCenterConfigManager -or ` $registryWindowsUpdateAutoUpdate if ($PSBoundParameters.ContainsKey('Detailed')) { [PSCustomObject]@{ ComputerName = $computer ComponentBasedServicing = $registryComponentBasedServicing #PendingComputerRenameDomainJoin = $pendingComputerRename PendingFileRenameOperations = $registryPendingFileRenameOperationsBool PendingFileRenameOperationsValue = $registryPendingFileRenameOperations SystemCenterConfigManager = $systemCenterConfigManager WindowsUpdateAutoUpdate = $registryWindowsUpdateAutoUpdate IsRebootPending = $isRebootPending } } else { [PSCustomObject]@{ ComputerName = $computer IsRebootPending = $isRebootPending } } } } } #function Get-RebootState |