While client push certainly has it's place in the world, it assumes a lot of things. Like boundary groups being correctly configured, and a clients ability to know what management point it should talk to. There are also some awkward security conversation to be had such as, service accounts with local admin on every machine in an environment are typically less than ideal. ## Determine a site Code I currently help support 36 "unique" environments. Nine ConfigMgr Labs, in four domains. Because all of the Configmgr servers are in the same domain, things like AD site assignment aren't practical or frankly needed. Additionally, it's takes a second for the client to come to an answer. I have found it's way faster to determine the current management point, and use the current management point to direct the install. With a quick CIM (or WMI call) you can determine this. ```powershell $ManagementPoint = (Get-CimInstance -ClassName SMS_Authority -Namespace 'root\ccm').CurrentManagementPoint ``` For the purposes of my lab, the MP is always on the primary site server as result, a little gentle manipulation converts the MP information to a site code name. ```powershell $siteCodePath = (Get-CimInstance -ClassName SMS_Authority -Namespace 'root\ccm').Name.Replace(":","_") ``` ## Calling for Install When you use client push, the client has to download the full contents of the CCM installer from the management point. Every time. We can do exactly what it does but as a "pull" instead of a push. First we check to see if there is a scratch space where we want to copy the client content to, and if not create it. Then we just copy the content from the management point. ```PowerShell if(!(Test-Path -Path C:\Scratch\CurrentClient)){ Write-Verbose -Message "The Scratch Space DOESNT exist, creating and downloading Client Info" New-Item -ItemType Directory -Path C:\Scratch\CurrentClient | Out-Null Copy-Item -Path \\$($ManagementPoint)\$($siteCodePath)\Client -Destination C:\Scratch\CurrentClient -Recurse Set-Location -Path C:\Scratch\CurrentClient\Client Write-Verbose -Message "Now starting the install..." .\ccmsetup.exe /source:C:\Scratch\CurrentClient\Client /mp:$($ManagementPoint) Write-Verbose -Message "Now opening log directory..." explorer.exe C:\Windows\ccmsetup\Logs } else{ Write-Verbose -Verbose "Scratch space existed, cleaning up and re-downloading..." Remove-Item -Path C:\Scratch\CurrentClient -Recurse -Force New-Item -ItemType Directory -Path C:\Scratch\CurrentClient | Out-Null Copy-Item -Path \\$($ManagementPoint)\$($siteCodePath)\Client -Destination C:\Scratch\CurrentClient -Recurse Set-Location -Path C:\Scratch\CurrentClient\Client Write-Verbose -Message "Now starting the install..." .\ccmsetup.exe /source:C:\Scratch\CurrentClient\Client /mp:$($ManagementPoint) Write-Verbose -Message "Now opening log directory..." explorer.exe C:\Windows\ccmsetup\Logs } ``` >[!note] >If you run this interactively on the client, the example here will open the default log directory so you can then watch the install. ## Putting it all together We can put all of the code together as a single function, and run it on the client. ```powershell Function Update-CMClient{ [cmdletbinding()] param( [Parameter(HelpMessage = "Provide the Management Point, if you don't provide one I'll guess." , Mandatory = $FALSE)] [string]$ManagementPoint ) if(!($PSBoundParameters.ContainsKey('ManagementPoint'))){ $ManagementPoint = (Get-CimInstance -ClassName SMS_Authority -Namespace 'root\ccm').CurrentManagementPoint } Write-Verbose -Message "Determined the MP is: $($ManagementPoint)" $siteCodePath = (Get-CimInstance -ClassName SMS_Authority -Namespace 'root\ccm').Name.Replace(":","_") Write-Verbose -Message "Determined the Site Code Info to be: $($siteCodePath)" if(!(Test-Path -Path C:\Scratch\CurrentClient)){ Write-Verbose -Message "The Scratch Space DOESNT exist, creating and downloading Client Info" New-Item -ItemType Directory -Path C:\Scratch\CurrentClient | Out-Null Copy-Item -Path \\$($ManagementPoint)\$($siteCodePath)\Client -Destination C:\Scratch\CurrentClient -Recurse Set-Location -Path C:\Scratch\CurrentClient\Client Write-Verbose -Message "Now starting the install..." .\ccmsetup.exe /source:C:\Scratch\CurrentClient\Client /mp:$($ManagementPoint) Write-Verbose -Message "Now opening log directory..." explorer.exe C:\Windows\ccmsetup\Logs } else{ Write-Verbose -Verbose "Scratch space existed, cleaning up and re-downloading..." Remove-Item -Path C:\Scratch\CurrentClient -Recurse -Force New-Item -ItemType Directory -Path C:\Scratch\CurrentClient | Out-Null Copy-Item -Path \\$($ManagementPoint)\$($siteCodePath)\Client -Destination C:\Scratch\CurrentClient -Recurse Set-Location -Path C:\Scratch\CurrentClient\Client Write-Verbose -Message "Now starting the install..." .\ccmsetup.exe /source:C:\Scratch\CurrentClient\Client /mp:$($ManagementPoint) Write-Verbose -Message "Now opening log directory..." explorer.exe C:\Windows\ccmsetup\Logs } } Update-CMClient -Verbose ``` ## Bonus Points When I use this script, I typically remove the function block, and ship the entire script via invoke-command. This then let's me kick the update on all of my remote hyper-v clients at once. Technically, you could use something like run scripts to do this as well if you wanted to. >[!warning] >This script is intended for use in a small lab environment. I would not suggest downloading the CMClient manually via SMB in a normal standard environment. Instead I would use this as a thought exercise for how to automate things in your lab.