CCMClient.psm1
#using Add-Type instead of Enum because I want to group by namespace Add-Type -ErrorAction SilentlyContinue -TypeDefinition @' namespace CCMClient { public enum EvalResult { Not_Yet_Evaluated = 1, Not_Applicable = 2, Evaluation_Failed = 3, Evaluated_Remediated_Failed = 4, Not_Evaluated_Dependency_Failed = 5, Evaluated_Remediated_Succeeded = 6, Evaluation_Succeeded = 7 } public enum EvaluationState { None = 0, Available = 1, Submitted = 2, Detecting = 3, PreDownload = 4, Downloading = 5, WaitInstall = 6, Installing = 7, PendingSoftReboot = 8, PendingHardReboot = 9, WaitReboot = 10, Verifying = 11, InstallComplete = 12, Error = 13, WaitServiceWindow = 14, WaitUserLogon = 15, WaitUserLogoff = 16, WaitJobUserLogon = 17, WaitUserReconnect = 18, PendingUserLogoff = 19, PendingUpdate = 20, WaitingRetry = 21, WaitPresModeOff = 22, WaitForOrchestration = 23 } public enum DCMEvaluationState { NonCompliant = 0, Compliant = 1, Submitted = 2, Unknown = 3, Detecting = 4, NotEvaluated = 5 } } '@ class ccmCimCredentialTransform:System.Management.Automation.ArgumentTransformationAttribute { [object] Transform([System.Management.Automation.EngineIntrinsics]$engineIntrinsics, [object]$object) { $output = switch ($object) { { $PSItem -is [Microsoft.Management.Infrastructure.Options.CimCredential] } { $PSItem } { $PSItem -is [PSCredential] } { $domain = $object.UserName -replace '.+@|\\.+' $UserName = $object.UserName -replace '.+\\|@.+' [Microsoft.Management.Infrastructure.Options.CimCredential]::new('Default', $domain, $UserName, $object.Password) } } return $output } } class ccmClient { [ciminstance] static getClientCimInstance ( [string]$ClassName, [string]$NameSpace ){ return (Get-Ciminstance -NameSpace $NameSpace -ClassName $ClassName) } [ciminstance[]] static getClientCimInstance ( [string]$ClassName, [string]$NameSpace, [string[]]$ComputerName ){ return (Get-Ciminstance -ComputerName $ComputerName -NameSpace $NameSpace -ClassName $ClassName) } [ciminstance[]] static getClientCimInstance ( [string]$ClassName, [string]$NameSpace, [CimSession[]]$CimSession ){ return (Get-Ciminstance -CimSession $CimSession -NameSpace $NameSpace -ClassName $ClassName) } [ciminstance[]] static getClientCimInstance ( [CimInstance[]]$CimInstance ){ return ($CimInstance | Get-Ciminstance) } } <# class ModuleInfoAttribute : System.Management.Automation.ArgumentTransformationAttribute { [object] Transform([System.Management.Automation.EngineIntrinsics]$engineIntrinsics, [object] $inputData) { $ModuleInfo = $null if ($inputData -is [string] -and -not [string]::IsNullOrWhiteSpace($inputData)) { $ModuleInfo = Get-Module $inputData -ErrorAction SilentlyContinue if (-not $ModuleInfo) { $ModuleInfo = @(Get-Module $inputData -ErrorAction SilentlyContinue -ListAvailable)[0] } } if (-not $ModuleInfo) { throw ([System.ArgumentException]"$inputData module could not be found, please try passing the output of 'Get-Module $InputData' instead") } return $ModuleInfo } } #> function Clear-CCMClientCache { [cmdletbinding(SupportsShouldProcess)] param ( [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName', Position = 0, Mandatory = $true)] [string[]]$ComputerName, [Parameter(ParameterSetName = 'ComputerName')] [PSCredential]$Credential ) Begin { $invokeParam = @{ ScriptBlock = { $CMObject = new-object -com "UIResource.UIResourceMgr" $cacheInfo = $CMObject.GetCacheInfo() $objects = $cacheinfo.GetCacheElements() Write-Verbose ( "Removing {0:N2}gb of CCM Cache Files" -f (($objects | Measure-Object -Property contentsize -Sum).sum/1mb) ) $objects | ForEach-Object { $cacheInfo.DeleteCacheElement($_.CacheElementId) } } } $computerList = [System.Collections.Generic.List[String]]::new() if ($Credential) { $invokeParam['Credential'] = $Credential } } Process { $computerList.AddRange([string[]]$ComputerName) } End { Invoke-Command @invokeParam -ComputerName $computerList } } function ConvertTo-CCMClientCimCredential { <# .Synopsis Short description .DESCRIPTION Long description .EXAMPLE Example of how to use this cmdlet .EXAMPLE Another example of how to use this cmdlet .INPUTS Inputs to this cmdlet (if any) .OUTPUTS Output from this cmdlet (if any) .NOTES General notes .COMPONENT The component this cmdlet belongs to .ROLE The role this cmdlet belongs to .FUNCTIONALITY The functionality that best describes this cmdlet #> [CmdletBinding()] [Alias()] [OutputType([Microsoft.Management.Infrastructure.Options.CimCredential])] Param ( [Parameter(Mandatory, Position = 0, ValueFromPipeline)] [PSCredential]$Credential ) process { $domain = $Credential.UserName -replace '.+@|\\.+' $UserName = $Credential.UserName -replace '.+\\|@.+' [Microsoft.Management.Infrastructure.Options.CimCredential]::new('Default', $domain, $UserName, $Credential.Password) } } function Get-CCMClientBoundaryGroupCache { <# .SYNOPSIS Boundary group caching was introduced with the first version of System Center Configuration Manager (ConfigMgr) Current Branch (CB): version 1511. As the term implies, clients cache the name of their current boundary groups .DESCRIPTION Similar to management point assignment, client’s refresh their current boundary group at three “times”: Every 25 hours At client agent startup When a network change is detected .EXAMPLE PS C:\> Get-CCMClientBoundaryGroupCache Computer1, Computer2 Returns boundary cache info from two computers .NOTES https://home.configmgrftw.com/boundary-group-caching-and-missing-boundaries-in-configmgr/ #> [cmdletbinding()] param( [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName', Position = 0, Mandatory = $true)] [alias('Name')] [string[]]$ComputerName, [parameter()] [pscredential]$Credential ) begin { $cimParam = @{ NameSpace = 'root/ccm/LocationServices' ClassName = 'BoundaryGroupCache' } } process { $sessionParam = @{ ComputerName = $ComputerName } if ($Credential) { $sessionParam['Credential'] = $Credential } New-CCMClientCimSession @sessionParam | Get-CimInstance @cimParam } } function Get-CCMClientCacheConfig { [cmdletbinding(DefaultParameterSetName = 'none')] param ( [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName', Position = 0, Mandatory = $true)] [alias('Name')] [string[]]$ComputerName, [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession', Position = 0, Mandatory = $true)] [Microsoft.Management.Infrastructure.CimSession[]]$CimSession, [parameter(ParameterSetName = 'ComputerName')] [pscredential]$Credential ) begin { $cimParam = @{ NameSpace = 'root\ccm\SoftMgmtAgent' ClassName = 'CacheConfig' } } process { Switch ($PSCmdlet.ParameterSetName) { 'ComputerName' { $cimParam['ComputerName'] = $ComputerName } 'CimSession' { $cimParam['CimSession'] = $CimSession } } if ($Credential) { $cimParam['Credential'] = $Credential } Get-CimInstance @cimParam } } function Get-CCMClientCacheItem { [cmdletbinding(DefaultParameterSetName = 'none')] param ( [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName', Position = 0, Mandatory = $true)] [alias('Name')] [string[]]$ComputerName, [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession', Position = 0, Mandatory = $true)] [Microsoft.Management.Infrastructure.CimSession[]]$CimSession, [parameter(ParameterSetName = 'ComputerName')] [pscredential]$Credential ) begin { $cimParam = @{ NameSpace = 'root\ccm\SoftMgmtAgent' ClassName = 'CacheInfoEx' } } process { Switch ($PSCmdlet.ParameterSetName) { 'ComputerName' { $cimParam['ComputerName'] = $ComputerName } 'CimSession' { $cimParam['CimSession'] = $CimSession } } if ($Credential) { $cimParam['Credential'] = $Credential } Get-CimInstance @cimParam } } function Get-CCMClientComplianceSettings { [cmdletbinding(DefaultParameterSetName = 'ComputerName')] param ( [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName', Position = 0)] [string]$ComputerName = $env:COMPUTERNAME, [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ValueFromRemainingArguments = $false, ParameterSetName = 'CimSession', Mandatory = $true)] [Microsoft.Management.Infrastructure.CimSession[]]$CimSession ) Begin { $cimParam = @{ NameSpace = 'root\ccm\dcm' ClassName = 'SMS_DesiredConfiguration' } } Process { Switch ($PSCmdlet.ParameterSetName) { 'ComputerName' { $cimParam['ComputerName'] = $ComputerName } 'CimSession' { $cimParam['CimSession'] = $CimSession } } Get-CimInstance @cimParam } } function Get-CCMClientExecutionRequest { param ( [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName', Position = 0, Mandatory = $true)] [string]$ComputerName, [Parameter(ParameterSetName = 'ComputerName')] [PSCredential]$Credential ) Begin { } Process { if (-not $CimSession) { try { $CimSession = Get-CimSession -ComputerName $ComputerName -ErrorAction Stop } catch { $cimParm = @{ ComputerName = $ComputerName } if ($Credential) { $cimParm['Credential'] = $Credential } $CimSession = New-CimSession @cimParm -ErrorAction Stop } } $cimParm = @{ OutVariable = 'update' NameSpace = 'root\ccm\SoftMgmtAgent' ClassName = 'CCM_ExecutionRequestEx' CimSession = $CimSession } Get-CimInstance @cimParm | ForEach-Object { $PSItem.PSObject.TypeNames.Insert(0, 'Microsoft.Management.Infrastructure.CimInstance.CCM_ExecutionRequestEx') ; $PSItem } } } function Get-CCMClientSoftwareUpdate { [cmdletbinding()] param ( [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName', Position = 0, Mandatory = $true)] [alias('Name')] [string[]]$ComputerName, [parameter()] [pscredential]$Credential ) begin { $cimParam = @{ NameSpace = 'root/ccm/ClientSDK' ClassName = 'CCM_SoftwareUpdate' } } process { $sessionParam = @{ ComputerName = $ComputerName } if ($Credential) { $sessionParam['Credential'] = $Credential } New-CCMClientCimSession @sessionParam | Get-CimInstance @cimParam } end { } } Function Install-CCMClientSoftwareUpdate { [cmdletbinding()] [alias('Install-CCMClientSoftwareUpdates')] param ( [Parameter(ValueFromPipeline = $true, #ValueFromPipelineByPropertyName = $true, #ParameterSetName = 'ComputerName', Position = 0, Mandatory = $true)] [alias('Update')] [ValidateCimClass('CCM_SoftwareUpdate')] [ciminstance[]]$InputObject ) begin { $updateList = [System.Collections.Generic.List[ciminstance]]::new() } process { $updateList.AddRange($InputObject) } end { $updateHash = $updateList | Group-Object { $PSItem.CimSystemProperties.ServerName } -AsHashTable -AsString Invoke-Command -ComputerName $updateHash.Keys.Where({$PSItem}) -ScriptBlock { $localUpdateHash = $using:updateHash $cimParam = @{ NameSpace = 'root/ccm/clientsdk' ClassName = 'CCM_SoftwareUpdatesManager' MethodName = 'InstallUpdates' Arguments = @{ CCMUpdates = [ciminstance[]]$localUpdateHash[$env:COMPUTERNAME] } } Invoke-CimMethod @cimParam #-ClassName CCM_SoftwareUpdatesManager -MethodName InstallUpdates -Arguments @{ CCMUpdates = [ciminstance[]]$updateHash[$PSItem.Key] } } } } Function Invoke-CCMClientPackageRerun { [cmdletbinding()] param( [string[]]$ComputerName = $env:COMPUTERNAME, [pscredential]$Credential ) Begin { $rerunSB = { Get-CimInstance -ClassName CCM_SoftwareDistribution -namespace root\ccm\policy\machine/ActualConfig -OutVariable Advertisements | Set-CimInstance -Property @{ ADV_RepeatRunBehavior = 'RerunAlways' ADV_MandatoryAssignments = $True } foreach ($a_Advertisement in $Advertisements) { Write-Verbose -Message "Searching for schedule for package: $() - $($a_Advertisement.PKG_Name)" Get-CimInstance -ClassName CCM_Scheduler_ScheduledMessage -namespace "ROOT\ccm\policy\machine\actualconfig" -filter "ScheduledMessageID LIKE '$($a_Advertisement.ADV_AdvertisementID)%'" | ForEach-Object { $null = Invoke-CimMethod -Namespace 'root\ccm' -ClassName SMS_CLIENT -MethodName TriggerSchedule @{ sScheduleID = $PSItem.ScheduledMessageID } [pscustomobject]@{ PKG_Name = $a_Advertisement.PKG_Name ADV_AdvertisementID = $a_Advertisement.ADV_AdvertisementID sScheduleID = $PSItem.ScheduledMessageID } } } } $ComputerList = [System.Collections.Generic.List[string]]::new() } Process { $ComputerList.AddRange( ([string[]]$ComputerName) ) } End { $invokeParm = @{ ScriptBlock = $rerunSB } $invokeParm['ComputerName'] = $ComputerList if ($Credential) { $invokeParm['Credential'] = $Credential } if ($ComputerName -eq $env:COMPUTERNAME) { $invokeParm.Remove('Credential') $invokeParm.Remove('ComputerName') } $invokeParm | Out-String | Write-Verbose Invoke-Command @invokeParm } } function Invoke-CCMClientComplianceSettingsEvaluation { [cmdletbinding()] param ( [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Position = 0, Mandatory )] [Microsoft.Management.Infrastructure.CimInstance[]]$CimInstance ) process { foreach ($obj in $CimInstance) { Invoke-CimMethod -InputObject $obj -MethodName TriggerEvaluation -Arguments @{ Name = $obj.Name; version = $obj.Version } } } } Function Invoke-CCMClientScheduleUpdate { [cmdletbinding()] param ( [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName', Position = 1, Mandatory = $true)] [string[]]$ComputerName, [Parameter(ParameterSetName = 'ComputerName')] [PSCredential]$Credential, [Parameter()] [ValidateSet('SoftwareUpdateScan')] [string[]]$ScheduleType, [Parameter()] [switch]$Quiet ) Begin { $scheduleHash = @{ '{00000000-0000-0000-0000-000000000001}' = 'Hardware Inventory' '{00000000-0000-0000-0000-000000000002}' = 'Software Inventory' '{00000000-0000-0000-0000-000000000003}' = 'Discovery Inventory' '{00000000-0000-0000-0000-000000000010}' = 'File Collection' '{00000000-0000-0000-0000-000000000011}' = 'IDMIF Collection' '{00000000-0000-0000-0000-000000000012}' = 'Client Machine Authentication' '{00000000-0000-0000-0000-000000000021}' = 'Request Machine Assignments' '{00000000-0000-0000-0000-000000000022}' = 'Evaluate Machine Policies' '{00000000-0000-0000-0000-000000000023}' = 'Refresh Default MP Task' '{00000000-0000-0000-0000-000000000024}' = 'LS (Location Service) Refresh Locations Task' '{00000000-0000-0000-0000-000000000025}' = 'LS (Location Service) Timeout Refresh Task' '{00000000-0000-0000-0000-000000000026}' = 'Policy Agent Request Assignment (User)' '{00000000-0000-0000-0000-000000000027}' = 'Policy Agent Evaluate Assignment (User)' '{00000000-0000-0000-0000-000000000031}' = 'Software Metering Generating Usage Report' '{00000000-0000-0000-0000-000000000032}' = 'Source Update Message' '{00000000-0000-0000-0000-000000000037}' = 'Clearing proxy settings cache' '{00000000-0000-0000-0000-000000000040}' = 'Machine Policy Agent Cleanup' '{00000000-0000-0000-0000-000000000041}' = 'User Policy Agent Cleanup' '{00000000-0000-0000-0000-000000000042}' = 'Policy Agent Validate Machine Policy / Assignment' '{00000000-0000-0000-0000-000000000043}' = 'Policy Agent Validate User Policy / Assignment' '{00000000-0000-0000-0000-000000000051}' = 'Retrying/Refreshing certificates in AD on MP' '{00000000-0000-0000-0000-000000000061}' = 'Peer DP Status reporting' '{00000000-0000-0000-0000-000000000062}' = 'Peer DP Pending package check schedule' '{00000000-0000-0000-0000-000000000063}' = 'SUM Updates install schedule' '{00000000-0000-0000-0000-000000000071}' = 'NAP action' '{00000000-0000-0000-0000-000000000101}' = 'Hardware Inventory Collection Cycle' '{00000000-0000-0000-0000-000000000102}' = 'Software Inventory Collection Cycle' '{00000000-0000-0000-0000-000000000103}' = 'Discovery Data Collection Cycle' '{00000000-0000-0000-0000-000000000104}' = 'File Collection Cycle' '{00000000-0000-0000-0000-000000000105}' = 'IDMIF Collection Cycle' '{00000000-0000-0000-0000-000000000106}' = 'Software Metering Usage Report Cycle' '{00000000-0000-0000-0000-000000000107}' = 'Windows Installer Source List Update Cycle' '{00000000-0000-0000-0000-000000000108}' = 'Software Updates Assignments Evaluation Cycle' '{00000000-0000-0000-0000-000000000109}' = 'Branch Distribution Point Maintenance Task' '{00000000-0000-0000-0000-000000000110}' = 'DCM policy' '{00000000-0000-0000-0000-000000000111}' = 'Send Unsent State Message' '{00000000-0000-0000-0000-000000000112}' = 'State System policy cache cleanout' '{00000000-0000-0000-0000-000000000113}' = 'Scan by Update Source' '{00000000-0000-0000-0000-000000000114}' = 'Update Store Policy' '{00000000-0000-0000-0000-000000000115}' = 'State system policy bulk send high' '{00000000-0000-0000-0000-000000000116}' = 'State system policy bulk send low' '{00000000-0000-0000-0000-000000000120}' = 'AMT Status Check Policy' '{00000000-0000-0000-0000-000000000121}' = 'Application manager policy action' '{00000000-0000-0000-0000-000000000122}' = 'Application manager user policy action' '{00000000-0000-0000-0000-000000000123}' = 'Application manager global evaluation action' '{00000000-0000-0000-0000-000000000131}' = 'Power management start summarizer' '{00000000-0000-0000-0000-000000000221}' = 'Endpoint deployment reevaluate' '{00000000-0000-0000-0000-000000000222}' = 'Endpoint AM policy reevaluate' '{00000000-0000-0000-0000-000000000223}' = 'External event detection' '{00000000-0000-0000-0000-000000000225}' = 'LSRefreshDefaultMPTask' } $ScheduleTypeHash = @{ SoftwareUpdateScan = '{00000000-0000-0000-0000-000000000108}', '{00000000-0000-0000-0000-000000000113}' } } Process { $cimSessionParam = @{ ComputerName = $ComputerName } if ($Credential) { $cimSessionParam['Credential'] = $Credential } $cimSession = New-CCMClientCimSession @cimSessionParam $cimSessionHash = @{ } #build hash to avoid slower where-object in invoke step $null = $cimSession.foreach( { $cimSessionHash.add($PSItem.ComputerName, $PSItem) }) $getScheduleParam = @{ Class = 'CCM_Scheduler_ScheduledMessage' Namespace = 'root\ccm\policy\machine\actualconfig' Filter = 'ScheduledMessageID LIKE "{00000000-0000-0000-0000-%"' CimSession = $cimSession } if ($ScheduleType) { $getScheduleParam['Filter'] = $ScheduleTypeHash[$ScheduleType].ForEach( { $PSItem }) -replace '.+', 'ScheduledMessageID = "$0"' -join " OR " } $schedule = Get-CimInstance @getScheduleParam $cimParam = @{ Namespace = 'root/ccm' Class = 'SMS_CLIENT' MethodName = 'TriggerSchedule' ErrorAction = 'Stop' } foreach ($a_Schedule in $schedule) { Try { Invoke-CimMethod @cimParam -CimSession $cimSessionHash[$a_Schedule.PSComputerName] -Arguments @{ sScheduleID = $a_Schedule.ScheduledMessageID } | Add-Member -NotePropertyName Schedule -NotePropertyValue ('{1} - {0}' -f $scheduleHash[$a_Schedule.ScheduledMessageID], $a_Schedule.ScheduledMessageID) -PassThru:(-not $Quiet.IsPresent) } catch { 'Could not trigger schedule: {0} - {1}' -f $scheduleHash[$a_Schedule.ScheduledMessageID], $a_Schedule.ScheduledMessageID | Write-Warning } } } } <#This function should be moved to the CCM client module Function Invoke-CCMPackageRerun { [cmdletbinding()] param( [string[]]$ComputerName = $env:COMPUTERNAME, [pscredential]$Credential ) Begin { $rerunSB = { Get-CimInstance -ClassName CCM_SoftwareDistribution -namespace root\ccm\policy\machine/ActualConfig -OutVariable Advertisements | Set-CimInstance -Property @{ ADV_RepeatRunBehavior = 'RerunAlways' ADV_MandatoryAssignments = $True } foreach ($a_Advertisement in $Advertisements) { Write-Verbose -Message "Searching for schedule for package: $() - $($a_Advertisement.PKG_Name)" Get-CimInstance -ClassName CCM_Scheduler_ScheduledMessage -namespace "ROOT\ccm\policy\machine\actualconfig" -filter "ScheduledMessageID LIKE '$($a_Advertisement.ADV_AdvertisementID)%'" | ForEach-Object { $null = Invoke-CimMethod -Namespace 'root\ccm' -ClassName SMS_CLIENT -MethodName TriggerSchedule @{ sScheduleID = $PSItem.ScheduledMessageID } [pscustomobject]@{ PKG_Name = $a_Advertisement.PKG_Name ADV_AdvertisementID = $a_Advertisement.ADV_AdvertisementID sScheduleID = $PSItem.ScheduledMessageID } } } } $ComputerList = [System.Collections.Generic.List[string]]::new() } Process { $ComputerList.AddRange( ([string[]]$ComputerName) ) } End { $invokeParm = @{ ScriptBlock = $rerunSB } $invokeParm['ComputerName'] = $ComputerList if ($Credential){ $invokeParm['Credential'] = $Credential } if ($ComputerName -eq $env:COMPUTERNAME) { $invokeParm.Remove('Credential') $invokeParm.Remove('ComputerName') } $invokeParm | Out-String | Write-Verbose Invoke-Command @invokeParm } } #https://kelleymd.wordpress.com/2015/02/08/run-local-advertisement-with-triggerschedule/ #> function New-CCMClientCimSession { <# .Synopsis Short description .DESCRIPTION Long description .EXAMPLE Example of how to use this cmdlet .EXAMPLE Another example of how to use this cmdlet .INPUTS Inputs to this cmdlet (if any) .OUTPUTS Output from this cmdlet (if any) .NOTES General notes .COMPONENT The component this cmdlet belongs to .ROLE The role this cmdlet belongs to .FUNCTIONALITY The functionality that best describes this cmdlet #> [CmdletBinding()] [Alias()] [OutputType([CimSession])] Param ( [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName, Position = 0)] [string[]]$ComputerName, [Parameter()] [ccmCimCredentialTransform()] [Microsoft.Management.Infrastructure.Options.CimCredential]$Credential ) Begin { $option = [Microsoft.Management.Infrastructure.Options.DComSessionOptions]::new() if ($Credential) { $option.AddDestinationCredentials( $Credential ) } } Process { ForEach ($a_ComputerName in $ComputerName) { [Microsoft.Management.Infrastructure.CimSession]::Create($a_ComputerName, $option) } } End { } } class ValidateCimClass : System.Management.Automation.ValidateEnumeratedArgumentsAttribute { [string]$PropertyName ValidateCimClass([string]$PropertyName) { $this.PropertyName = $PropertyName } [void]ValidateElement($Element) { if ([string]$Element.CimClass.CimClassName -ne $this.PropertyName) { throw ('{0} != {1}' -f $this.PropertyName, $Element.CimClass.CimClassName) } } } <# function test-validator { [cmdletbinding()] param( [ValidateCimClass('Win32_Bios')] [ciminstance[]]$cimInstance ) $cimInstance } test-validator -ciminstance (Get-CimInstance Win32_Bios -computername localhost,localhost) #> function Wait-CCMClientSoftwareUpdate { [cmdletbinding()] param ( [Alias('Wait-CCMClientSoftwareUpdateInstallation')] [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName', Position = 0, Mandatory = $true)] [alias('Name')] [string[]]$ComputerName, [Parameter(ParameterSetName = 'ComputerName')] [PSCredential]$Credential, [Parameter(ParameterSetName = 'CimSession')] [CimSession[]]$CimSession, [switch]$Quiet, [int]$Interval = 5 ) begin { $cimParam = @{ NameSpace = 'root/ccm/ClientSDK' ClassName = 'CCM_SoftwareUpdate' Filter = 'EvaluationState < 8' } } process { Switch ($PSCmdlet.ParameterSetName) { 'ComputerName' { $cimParam['ComputerName'] = $ComputerName if ($Credential) { $cimParam['Credential'] = $Credential } } 'CimSession' { $cimParam['CimSession'] = $CimSession } } While (($updates = Get-CimInstance @cimParam)) { $updates | ForEach-Object { Write-Progress -Activity 'Waiting for patch installation' -CurrentOperation $PSItem.PSComputerName -Status ('{0}: {1}' -f [CCM.EvaluationState]$PSItem.EvaluationState, $PSItem.Name) } if (-not $Quiet.IsPresent) { $updates | Out-String | Write-Host -ForegroundColor Green } Start-Sleep -Seconds $Interval } } end { } } |