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
Powershell – SCCMOG – Deployment Blog

Windows 10 Inject Start Menu Layout Offline – MDT SCCM OSD Powershell

In this blog I will show you how to inject your Windows 10 start menu offline so that on first boot its already configured in your reference image or even your deployment task sequence whether that be MDT of ConfigMgr (SCCM).

GITHUB: Action-OSD_InjectStartMenu_Offline.ps1

Note: If you have links for icons pinned on  the taskbar and the software is not already installed it ill not break and they will show as the applications are installed 😉

Important: Make sure you have added the PowerShell component to your boot image. Click a link to find out how: MDT or SCCM

MDT Setup

  • First download the script and save it into you deployment share “Scripts” folder:
J:\<YOUR_DEPLOYMENT_SHARE>\Scripts\Action-OSD_InjectStartMenu_Offline.ps1
    • Your welcome to also download the DefaultStart.xml and or just rename your default start menu XML to “DefaultStart.xml” and add it also to the deployment share “Scripts” folder.
J:\<YOUR_DEPLOYMENT_SHARE>\Scripts\DefaultStart.xml
  • 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:  Inject Start Menu Offline
    Then use the following command line:
Powershell.exe -ExecutionPolicy Bypass -File "%SCRIPTROOT%\Action-OSD_InjectStartMenu_Offline.ps1"

Example:

Windows-10-Inject-Start-menu-offline
Windows-10-Inject-Start-menu-offline

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 “Action-OSD_InjectStartMenu_Offline.ps1” into it.  And then your welcome to also download the DefaultStart.xml or just rename your default start menu XML to “DefaultStart.xml” and add it also to the ToolKit Package “Scripts” foldera also.
  • 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 the below command.

Powershell.exe -ExecutionPolicy Bypass -File "%DEPLOYROOT%\Action-OSD_InjectStartMenu_Offline.ps1"

And that is it. Your ConfigMgr or MDT Task sequence is now setup to inject the default start menu 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()
}

Disable RDP Windows 10 PowerShell Script Configuration Baseline SCCM

So I was setting up a KIOSK environment using  Windows 10 1709 for a client recently and we wanted to take the route of applying as few GPOs as possible (as it should be in 2018)!

Ensuring that this stayed disabled was something that we decided to deploy using ConfigMgr Configuration Baselines.

So the Check compliance script is as follows:

##################################################################################################################
#
#  Author: Richie Schuster - C5 Alliance - SCCMOG.com
#  Date:   06/07/2018
#  Script: Action-CheckRDPCompliance.ps1
#  Usage: Powershell.exe -ExecutionPolicy Bypass -File .\Action-CheckRDPCompliance.ps1
#
##################################################################################################################

#Variables
$TSRegPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server"
$TSRegProperty = "fDenyTSConnections"
$RDPTcpRegPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp"
$RDPTcpRegProperty = "UserAuthentication"

#Set initial values
$TSSet = $True
$RDPTCPSet = $True
$RDPUserinTCPReturn = $True
$RDPUserinUDPReturn = $True
$RDPShadinTCPReturn = $True

#Test fDenyTSConnections state
$TSReturn = (Get-ItemProperty -Path $TSRegPath -Name $TSRegProperty -ErrorAction SilentlyContinue).fDenyTSConnections
If ($TSReturn -eq 1) {
    $TSSet = $false
}

#Test RDP-TCP State
$RDPTCPReturn = (Get-ItemProperty -Path $RDPTcpRegPath -Name $RDPTcpRegProperty -ErrorAction SilentlyContinue).UserAuthentication
If ($RDPTCPReturn -eq 0) {
    $RDPTCPSet = $false
}

#Get Firewall states
$RDPUserinTCPReturn = (Get-NetFirewallRule -Name $RDPUserinTCP -ErrorAction SilentlyContinue).Enabled
$RDPUserinUDPReturn = (Get-NetFirewallRule -Name $RDPUserinUDP -ErrorAction SilentlyContinue).Enabled
$RDPShadinTCPReturn = (Get-NetFirewallRule -Name $RDPShadinTCP -ErrorAction SilentlyContinue).Enabled

#Evaluate and report
If (!($RDPUserinTCPReturn) -and ($RDPUserinUDPReturn) -and ($RDPShadinTCPReturn) -and ($TSSet) -and ($RDPTCPSet)) {
    Write-Host "Compliant!"
}

##################################################################################################################

Ok, so now the check script is out the way, here is the remediation script:

##################################################################################################################
#
#  Author: Richie Schuster - C5 Alliance - SCCMOG.com
#  Date:   06/07/2018
#  Script: Action-RemediateRDPCompliance.ps1
#  Usage: Powershell.exe -ExecutionPolicy Bypass -File .\Action-RemediateRDPCompliance.ps1
#
##################################################################################################################

#Variables
$TSRegPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server"
$TSRegProperty = "fDenyTSConnections"
$RDPTcpRegPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp"
$RDPTcpRegProperty = "UserAuthentication"

#Remediate and Block RDP
Set-ItemProperty $TSRegPath -Name $TSRegProperty -Value 1 -Force
Set-ItemProperty $RDPTcpRegPath -Name $RDPTcpRegProperty -Value 0 -Force
Disable-NetFirewallRule -DisplayGroup "Remote Desktop"

#The End :)
##################################################################################################################

As Always scripts are as is, and if you do use them remeber where you got them from 😉

If you would like to see the setup of this baseline let me know in the comments below.

Cheers,

SCCMOG

PowerShell add Computers to Collection from CSV – SCCM ConfigMgr

This is a quick and dirty PowerShell script to import from CSV using the name of the machine to find the resource ID. It will only work for machines that are already a member of the Site you are working on.

For example you could use one of my other scripts to export from one collection and then add to a new collection.

As always this is provided as is, usage is in the header and please use the modded by field 😉

#################################################################################################################
#Author:   Richie Schuster - SCCMOG.COM                                                                         #
#ModdedBy: You Name Here                                                                                        #
#Script:   Import-AddToCollectionfromCSV.ps1                                                                    #
#Date:     26/06/2017                                                                                           #
#Usage:    Import-AddToCollectionfromCSV.ps1 -CollectionID S0G001BA -SiteCode S0G -CSVin "C:\Temp\YourCSV.csv"  #
#################################################################################################################

#Params for Script execution
param 
(
[parameter(mandatory=$true,HelpMessage="Please, provide a Collection ID to add the machines to e.g. P01000F4 ")][ValidateNotNullOrEmpty()][String]$CollectionID,
[parameter(mandatory=$true,HelpMessage="Please, provide a SCCM SiteCode. e.g S0G")][ValidateNotNullOrEmpty()][String]$SiteCode,
[parameter(mandatory=$true,HelpMessage="Please, provide a location to import the CSV file from with the filename. e.g C:\Temp\YourCSV.csv")][ValidateNotNullOrEmpty()][String]$CSVin
)
#Import the ConfigurationManager.psd1 module 
Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1"
#Set the current location to be the site code.
Set-Location "$SiteCode`:"

#$ErrorActionPreference= 'silentlycontinue'
#Get the content of the CSV file
$Computers = Import-Csv $CSVin

#Loop through each Device and perform actions
Foreach ($Computer in $Computers) {
    #Get Device Resource ID
    $ResourceID = (Get-CMDevice -name $($Computer.Name)).ResourceID
    #Add the Device to the Collection specified
    Write-Host "Adding Machine $($Computer.Name) ResourceID: $ResourceID" -ForegroundColor Yellow
    add-cmdevicecollectiondirectmembershiprule -CollectionId $CollectionID -resourceid $ResourceID -Verbose 

} 
#Set location of script back to script root.
Set-Location $PSScriptRoot

###########################################################################

Copyright 2016 SCCMOG | All Rights Reserved