Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the twentyseventeen domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /var/www/html/wp-includes/functions.php on line 6121
Automation – SCCMOG – Deployment Blog

Windows 10 Configure User Experience Offline – MDT SCCM OSD -VBScript

So currently I am working on an Government Education site comprising of just under 40 schools. There was a requirement to remove/hide Microsoft’s Edge browser from the image being rolled out to the users. The reasoning behind this is down to a monitoring tool used by the education department that does not support Edge and therefor policies would be broken…

Anyway I hunted around on our favourite resource for a solution that would not break the image entirely by removing one of it core features.

Eventually I found these 4 registry keys that did the trick:

KEY: HKEY_LOCAL_MACHINE\NewOS\Microsoft\Windows\CurrentVersion\Explorer
Name: DisableEdgeDesktopShortcutCreation 
Value: 1
KEY: HKEY_LOCAL_MACHINE\NewOS\Policies\Microsoft\MicrosoftEdge\Main
Name: PreventFirstRunPage
Value: 1
KEY: HKEY_LOCAL_MACHINE\NewOS\Policies\Microsoft\MicrosoftEdge\Main
Name: AllowPrelaunch 
Value: 0
KEY: HKEY_LOCAL_MACHINE\NewOS\Policies\Microsoft\MicrosoftEdge\TabPreloader\AllowTabPreloading
Name: AllowTabPreloading 
Value: 0

Next was to figure out how to inject these into my reference image before  it was laid onto the VM for automated customisation. So I remembered a great script by Johan Arwidmark I use all the time for turning off Appx package updates during a reference image capture task  sequence (can break sysprep if allowed).

Anyway after a bit of modification to load the Software registry hive offline instead this is what I came up with. There is also some commented out portions here that may come in handy:

Github: Config-Win10-Offline-UE.wsf

MDT Setup

  • First download the script and save it into you deployment share “Scripts” folder:
J:\<YOUR_DEPLOYMENT_SHARE>\Scripts\Config-Win10-Offline-UE.wsf
  • Then Open up your chosen Task Sequence in MDT and just before the “Inject Drivers” step under the “Post Install Group” and a new “Run Commmand Line Step”.
  • Name it for example:  Configure User Experience
    Then use the following command line:
cscript.exe "%SCRIPTROOT%\Config-Win10-Offline-UE.wsf"

Example:

Configure-User-Environment-Offline-VBscript-Example
Configure-User-Environment-Offline-VBscript-Example

SCCM Setup

  • For SCCM you must be using the MDT integration (if you’re not… Start now!), you can make it work without it but I will not cover that here.
  • Find your current MDT Toolkit Package that is associated with the Task Sequence you would like to configure power settings in.
  • Open the “Source” location of your toolkit package, then open the scripts folder.

  • Once inside the scripts folder copy the “Config-Win10-Offline-UE.wsf” into it. Now, update the Package in ConfigMgr.
  • Next we need to add the step to the task sequence. It must go after a “Use Toolkit Package” step and before your Driver injection step in the task sequence. (If you have a reboot remember to add another use “Toolkit package”.)

Create a new “Run Command Line Step” and add the below command.

cscript.exe "%deployroot%\scripts\Config-Win10-Offline-UE.wsf"

And that is it. Your ConfigMgr or MDT Task sequence is now setup to configure the user environment before the machine boots!

Anyway as always, script is provided as is and if you do mod it, there is a line to add your name.

Get and Set ConfigMgr Machine Variables with WMI and PowerShell Functions

So I’m working on a client site at the moment with a difficult to automate OU structure. Essentially I need to be able to add and get ConfigMgr machine variables easily and without the need of the PowerShell module.

So as we do… I went to google, found a couple of nice hints then though I’d write them into functions to be easily re-used.

The beauty of these functions is they can be run from anywhere in your site or during a task sequence as they use WMI.
This means as long as the account running the script has access to the ConfigMgr site you can play with variables!

Anyway download the most up to date versions of the functions from the SCCMOG GitHub Repo:

Scripts:

#Get-ConfigMgrMachineVariableWMI
#SCCMOG.com Richie Schuster - 27/09/18
#Gets the value of a ConfigMgr Objects Variable
#E.g <Get-ConfigMgrMachineVariable -Siteserver $Siteserver -SiteCode $SiteCode -MachineName TUDOR -VarName "Hello2">
#Returns blank string if not found and value if found.
Function Get-ConfigMgrMachineVariable{
	param(
		[parameter(Mandatory=$true, HelpMessage="Site server FQDN")]
		[ValidateNotNullOrEmpty()]
		[string]$Siteserver,

		[parameter(Mandatory=$true, HelpMessage="SCCM Site Code")]
		[ValidateNotNullOrEmpty()]
		[string]$SiteCode,

		[parameter(Mandatory=$true, HelpMessage="ConfigMgr Machine Object to add Variable to")]
		[ValidateNotNullOrEmpty()]
		[string]$MachineName,

		[parameter(Mandatory=$true, HelpMessage="Variable Name to query for.")]
		[ValidateNotNullOrEmpty()]
		[string]$VarName
	)
    #Set to null
    $objMachineSettings = $null
    #Get machine object from ConfigMgr
    $objComputer = gwmi -computername $($Siteserver) -namespace "root\sms\site_$($SiteCode)" -class "sms_r_system" | where{$_.Name -eq $MachineName}
    #Get settings from ConfigMgr
    $objMachineSettings = gwmi -computername $($Siteserver) -namespace "root\sms\site_$($SiteCode)" -class "sms_machinesettings" | where{$_.ResourceID -eq $objComputer.ResourceID}
    If ($objMachineSettings -ne $null){
        $objMachineSettings.get()
        If ($objMachineSettings.MachineVariables | where{$_.Name -eq "$VarName"}) {
            $variable = (($objMachineSettings.MachineVariables | where{$_.Name -eq "$VarName"}).Value).Trim()
            return $variable
        }
        Else {
            $variable = ""
            return $variable
        }
    }
    else {
        $variable = ""
        return $variable
    }   
}
#Set-ConfigMgrMachineVariableWMI
#SCCMOG.com Richie Schuster - 27/09/18
#Gets the value of a ConfigMgr Objects Variable
#E.g <Set-ConfigMgrMachineVariable -Siteserver ROARY-CM-01 -SiteCode ROR -MachineName TUDOR -VarName Hello2 -VarValue Really -VarMasked $false>
#Sets ConfigMgr Variable - will add a new variable if others already set.
Function Set-ConfigMgrMachineVariable {
	param(
		[parameter(Mandatory=$true, HelpMessage="Site server FQDN")]
		[ValidateNotNullOrEmpty()]
		[string]$Siteserver,

		[parameter(Mandatory=$true, HelpMessage="SCCM Site Code")]
		[ValidateNotNullOrEmpty()]
		[string]$SiteCode,

		[parameter(Mandatory=$true, HelpMessage="ConfigMgr Machine Object to add Variable to")]
		[ValidateNotNullOrEmpty()]
		[string]$MachineName,

		[parameter(Mandatory=$true, HelpMessage="Variable Name")]
		[ValidateNotNullOrEmpty()]
		[string]$VarName,

		[parameter(Mandatory=$true, HelpMessage="Variable Value")]
		[ValidateNotNullOrEmpty()]
		[string]$VarValue,

		[parameter(Mandatory=$false, HelpMessage="Mask variable - `$true or `$false - Default is `$false")]
		[ValidateNotNullOrEmpty()]
		[bool]$VarMasked = $false
	)
    #Set to null
    $objMachineSettings = $null
    #Get machine resource id
    $objComputer = gwmi -computername $($Siteserver) -namespace "root\sms\site_$($SiteCode)" -class "sms_r_system" | where{$_.Name -eq $MachineName}
    #Get SMS Machine Settings Class
    $objSMSMachineSettings = [WmiClass]"\\$($Siteserver)\ROOT\SMS\site_$($SiteCode):SMS_MachineSettings"
    #Get SMS Machine settings Instances
    $objSMSMachineSettings.GetInstances() | Out-Null
    #Get Machine Settings
    $objMachineSettings = gwmi -computername $($Siteserver) -namespace "root\sms\site_$($SiteCode)" -class "sms_machinesettings" | where{$_.ResourceID -eq $objComputer.ResourceID}

    #test if variables already present
    If ($objMachineSettings -ne $null){
        $objMachineSettings.Get()  
        #Get new array index
        if ($objMachineSettings.MachineVariables.length -ne 0){
            $i = 0
            $newVarIndex = $i
            DO {
            $newVarIndex = $i + 1
            $i++
            } While ($i -le $objMachineSettings.MachineVariables.length - 1)
            $newVarIndex
        }
        else {
            $newVarIndex = 0
        }
        #Create the new emty variable
        $objMachineSettings.MachineVariables = $objMachineSettings.MachineVariables += [WmiClass]"\\$($Siteserver)\ROOT\SMS\site_$($SiteCode):SMS_MachineVariable"
        #get array of variables
        $arrayMachineVariables = $objMachineSettings.MachineVariables
        #set new variable
        $arrayMachineVariables[$newVarIndex].name=$varName
        $arrayMachineVariables[$newVarIndex].value=$VarValue
        $arrayMachineVariables[$newVarIndex].ismasked = $VarMasked
    }
    Else {
        #Create Machine instance
        $objMachineSettings = $objSMSMachineSettings.CreateInstance()
        #Create base properties
        $objMachineSettings.psbase.properties["ResourceID"].value = $($objComputer.ResourceID)
        $objMachineSettings.psbase.properties["SourceSite"].value = $($SiteCode)
        $objMachineSettings.psbase.properties["LocaleID"].value = 1033
        #Create empty variable
        $objMachineSettings.MachineVariables = $objMachineSettings.MachineVariables + [WmiClass]"\\$($Siteserver)\ROOT\SMS\site_$($SiteCode):SMS_MachineVariable"
        #get array of variables
        $arrayMachineVariables = $objMachineSettings.MachineVariables
        #set the new variable
        $arrayMachineVariables[0].name=$varName
        $arrayMachineVariables[0].value=$VarValue
        $arrayMachineVariables[0].ismasked = $VarMasked
    }
    # write the variables back to the machine object 
    $objMachineSettings.MachineVariables = $arrayMachineVariables
    #Save the new Variable
    $objMachineSettings.put()
}

Bulk Discover Client Versions

So this morning I was checking up on the status of some client upgrades after installing the latest 1710 hotfix. WMI on each machine had updated to reflect the latest client versions, however most machines hadn’t reported back to ConfigMgr so they were still listed as the older version. Being impatient, I wrote a script that I could use with SCCMs ‘Run Script‘ feature (available as a pre-release feature from version 1706) that would scrape WMI on each machine locally and report back the client version… simple, but awesome!

The script is as follows:

#############################################################
#
#  Author: Jack O'Connor
#  Website: https://github.com/JackOconnor21
#  Modified By: Your name here...
#  Description: Simple script to use on a local machine or via SCCMs
#     'run script' feature to find the client version of a machine
#     in the event SCCM has not yet updated the machine records.
#  
#  Edit the $CurrClientVer variable to reflect the latest client version
#  which is what we will test against.
#
##############################################################

$CurrClientVer = "5.00.8577.1115"
$MyClientVer = (Get-WMIObject -Namespace root\ccm -Class SMS_Client).ClientVersion

If ($MyClientVer -eq $CurrClientVer) {
    Write-Host "Up to date" -ForegroundColor Green
} Else {
    Write-Host "Out of date ($MyClientVer)" -ForegroundColor Red
}

The idea is you add the new client version number into the $CurrClientVer and the script will check WMI on each machine and match the client version against that – if it matches then we get an “Up to date” output, but if it does not we get an “Out of date” output followed by the actual client version on that machine.

You can run this script on any collection you like, I chose to run it on my “System Health | Clients Active” collection, which gave me the feedback pictured below.

 

 

 

 

 

Copyright 2016 SCCMOG | All Rights Reserved