functions/private.ps1
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments", "")] param() #there are private, non-exported functions Function _PesterCheck { [CmdletBinding(SupportsShouldProcess)] Param() #1/31/2024 Revised to check for the latest version of Pester $currentPester = (Get-Module Pester -ListAvailable)[0] #Get-Module -FullyQualifiedName @{ModuleName = "Pester"; ModuleVersion = "$pesterVersion"} -ListAvailable if ($currentPester.Version -eq '3.4.0') { Write-Warning "Pester v3.4.0 is installed and has never been updated. Installing the latest version of Pester" Install-Module -Name Pester -Force -SkipPublisherCheck } elseif ($currentPester.Version -lt $PesterVersion) { Write-Warning "Pester v5.0.0 or later is required. Updating to the latest version of Pester" Update-Module -Name Pester } else { Write-Host "Pester verified" -ForegroundColor green } #Import-Module -name Pester -RequiredVersion $PesterVersion -Force -Global Import-Module -name Pester -Force -Global } Function _LabilityCheck { [CmdletBinding(SupportsShouldProcess)] Param( [Parameter(Position = 0, Mandatory)] [ValidateNotNullOrEmpty()] [String]$RequiredVersion, [Switch]$SkipPublisherCheck ) $LabilityMod = Get-Module -Name Lability -ListAvailable | Sort-Object Version -Descending $PSBoundParameters.Add("Name", "Lability") $PSBoundParameters.Add("Force", $True) $PSBoundParameters.Add("ErrorAction", "Stop") $PSBoundParameters | Out-String | Write-Verbose if (-Not $LabilityMod) { Write-Host -ForegroundColor Cyan "Installing Lability module version $requiredVersion" Install-Module @PSBoundParameters #-Name Lability -RequiredVersion $requiredVersion -Force } elseif ($LabilityMod[0].Version.ToString() -eq $requiredVersion) { Write-Host "Version $requiredVersion of Lability is already installed" -ForegroundColor Cyan } elseif ($LabilityMod[0].Version.ToString() -ne $requiredVersion) { Write-Host -ForegroundColor Cyan "Updating Lability Module to version $RequiredVersion" #remove the currently loaded version Remove-Module -Name Lability -ErrorAction SilentlyContinue try { if ($SkipPublisherCheck) { Write-Verbose "Skipping publisher check and calling Install-Package" Install-Package @PSBoundParameters } else { Write-Verbose "Calling Update-Module" [void]($PSBoundParameters.remove("SkipPublisherCheck")) Update-Module @PSBoundParameters } } Catch { Write-Warning "Failed to update to the current version of Lability. If the error message is about a certificate mismatch, re-run this command and use the -SkipPublisherCHeck parameter. `n$($_.exception.message)" } } } #end function Function Invoke-WUUpdate { [CmdletBinding(DefaultParameterSetName = "computer")] Param( [Parameter(Position = 0, Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName, ParameterSetName = "computer")] [ValidateNotNullOrEmpty()] [string[]]$Computername, [Parameter(Position = 0, ParameterSetName = "VM")] [string[]]$VMName, [ValidateNotNullOrEmpty()] [PSCredential]$Credential, [Switch]$AsJob ) Begin { Write-Verbose "[BEGIN ] Starting: $($MyInvocation.MyCommand)" $all = @() #this is a nested function to deploy remotely Function WUUpdate { [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = "Computer")] Param( [Parameter(Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName, ParameterSetName = "Computer")] [ValidateNotNullOrEmpty()] [string[]]$Computername = $env:COMPUTERNAME ) Begin { Write-Verbose "[BEGIN ] Starting: $($MyInvocation.MyCommand)" $ns = "ROOT/Microsoft/Windows/WindowsUpdate" } #begin Process { #test if using the new Class Try { [void](Get-CimClass -Namespace $ns -ClassName 'MSFT_WUOperations' -ErrorAction Stop) $class = 'MSFT_WUOperations' $scanArgs = @{SearchCriteria = "IsInstalled=0" } #always scan even if the function is run with -WhatIf Write-Host "[$(Get-Date)] Scanning for updates to install on $($env:computername)" -ForegroundColor Cyan $scan = Invoke-CimMethod -Namespace $ns -ClassName $class -MethodName 'ScanForUpdates' -Arguments $scanArgs -WhatIf:$false -ErrorAction Stop Write-Host "[$(Get-Date)] Found $($scan.updates.count) updates to install on $($env:computername)" -ForegroundColor Cyan if ($scan.Updates.count -gt 0) { if ($PSCmdlet.ShouldProcess("$($scan.updates.count) updates", "Install Updates" )) { [void](Invoke-CimMethod -Namespace $ns -ClassName MSFT_WUOperations -MethodName InstallUpdates -Arguments @{Updates = $scan.updates }) } } } #try Catch { #uncomment for debugging and troubleshooting #Write-Host "Failed to find MSFT_WUOperations on $env:computername" -ForegroundColor yellow $class = 'MSFT_WUOperationsSession' $scanArgs = @{OnlineScan = $True; SearchCriteria = "IsInstalled=0" } $ci = New-CimInstance -Namespace $ns -ClassName $class -WhatIf:$False Write-Host "[$(Get-Date)] Scanning for updates to install on $($env:computername)" -ForegroundColor Cyan $scan = $ci | Invoke-CimMethod -MethodName 'ScanForUpdates' -Arguments $scanArgs -WhatIf:$False Write-Host "[$(Get-Date)] Found $($scan.updates.count) updates to install on $($env:computername)" -ForegroundColor Cyan if ($scan.Updates.count -gt 0) { if ($PSCmdlet.ShouldProcess("$($scan.updates.count) updates", "Apply Updates" )) { [void]($ci | Invoke-CimMethod -MethodName applyApplicableUpdates ) } } } #catch if ($scan.updates.count -gt 0) { Write-Host "[$(Get-Date)] Update process complete on $env:computername" -ForegroundColor Cyan } #check for reboot $r = Invoke-CimMethod -Namespace $ns -ClassName 'MSFT_WUSettings' -MethodName 'IsPendingReboot' if ($r.PendingReboot) { Write-Warning "$($env:computername) requires a reboot" } if ($ci) { Remove-Variable ci } } #process End { Write-Verbose "[END ] Ending: $($MyInvocation.MyCommand)" } #end } #end nested function #get the contents of the nested function $fun = ${function:WUUpdate} $icmParams = @{ HideComputername = $True Session = $null Scriptblock = { WUUpdate } } if ($AsJob) { $icmparams.AsJob = $True $icmParams.JobName = "WUUpdate" } } #begin Process { if ($PSBoundParameters.ContainsKey("AsJob")) { [void]$PSBoundParameters.remove("AsJob") } #Write-Verbose ($PSBoundParameters | Out-String) Try { Write-Verbose "[PROCESS] Creating PSSessions" $sess = New-PSSession @PSBoundParameters -ErrorAction stop Write-Verbose "[PROCESS] Copy the function to the remote computer" [void](Invoke-Command -ScriptBlock { New-Item -Path Function:WUUpdate -Value $using:fun -force } -Session $sess) $icmParams.Session = $sess } Catch { Write-Warning "Failed to create session to $Computer. $($_.exception.message)" } Write-Verbose "[PROCESS] Run the remote function" $r = Invoke-Command @icmParams if ($AsJob) { $r } else { $r | Select-Object -Property * -ExcludeProperty RunspaceID Write-Verbose "[PROCESS] Cleaning up sessions" $sess | Remove-PSSession } } #process End { Write-Verbose "[END ] Ending: $($MyInvocation.MyCommand)" } #end } Function Test-IsAdministrator { $user = [Security.Principal.WindowsIdentity]::GetCurrent(); (New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator) } |