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
Config Manager – Page 4 – SCCMOG – Deployment Blog

PowerShell Export Collection Members to CSV SCCM ConfigMgr

I was at a client’s yesterday and wanted to “True Up” SCCM/ConfigMgr’s Collection memberships compared to a spread sheet they had of their servers. Now I’m not an Excel wizard by any stretch of the Imagination! So the client said “Can you get me a CSV with the server names listed”.

The next thing that happened is bellow! It’s really quite a simple script when you think about it. As always comments throughout the script explain what is happening.

Anyway here it is:

#################################################################################################################
#Author:   Richie Schuster - SCCMOG.COM                                                                         #
#ModdedBy: You Name Here                                                                                        #
#Script:   Export-CMCollectionMembers                                                                           #
#Date:     23/05/2017                                                                                           #
#Usage:    Export-CMCollectionMembers -CollectionIDs S0G000F4,S0G000F2 -SiteCode S0G -CSVout C:\Temp\YourCSV.CSV#
#Update:   26/06/2017 - Removed Quotes from output.                                                             #
#################################################################################################################
#Input Parameters for Script
param (
[parameter(mandatory=$true,HelpMessage="Please, provide Collection ID(s). To list more than one Collection ID seprate with , e.g. S0G000F4,S0G000F2")][ValidateNotNullOrEmpty()][String[]]$CollectionIDS,
[parameter(mandatory=$true,HelpMessage="Please, provide a SCCM SiteCode. e.g S0G")][ValidateNotNullOrEmpty()][String]$SiteCode,
[parameter(mandatory=$true,HelpMessage="Please, provide a location to save the Exported CSV with the filename. e.g C:\Temp\YourCSV.CSV")][ValidateNotNullOrEmpty()][String]$CSVOut
)

#Set delimiter for CSV
$delimiter = ','

#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`:"

#Loop through Collection Members and add to Variable
Foreach ($Collection in $CollectionIDS) {
$MembersSep = Get-CMCollectionMember -CollectionId $Collection | Select-Object Name
$Members += $MembersSep
}

#Export to CSV specified removing quotes.
$Members | ConvertTo-Csv -Delimiter $delimiter -NoTypeInformation | foreach { $_ -replace '^"','' -replace "`"$delimiter`"",$delimiter -replace '"$','' } | out-file $CSVOut -fo -en ascii
#Set Location Back to Script Root
Set-Location -Path $PSScriptRoot

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

Get Current or old Machine Name from WinPE VBScript

This script was designed to get the current or old computer name from WinPE and apply it to the Task Sequence Variable OSDComputerName.

It has been written in VBScript to not require PowerShell in the boot image.

Here is the script:

'====================================================
'Author: Richie Schuster - SCCMOG.com
'Date  : 24-03-2017
'Info  : Script finds old machine name for refresh Scenario and prepopulates it
'====================================================

Option Explicit
'On Error Resume Next

Dim oShell, env, objWMIService, colItems, objItem, strWinDrive, strCurrentComputer
Const strComputer = "."

Set oShell = WScript.CreateObject("WScript.Shell")
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set env = CreateObject("Microsoft.SMS.TSEnvironment")

'End Header

' Worker

'Get Windows drive
Set colItems = objWMIService.ExecQuery ("Select * From Win32_LogicalDisk Where VolumeName = 'Windows'")
For Each objItem in colItems
	strWinDrive = objItem.DeviceID
Next

'Check Task Sequence found a Windows Drive
If IsNull(strWinDrive)  Or  IsEmpty(strWinDrive) Then
   MsgBox "The TaskSequence could not locate a previous Machine Name. Please PXE again and deploy this as a new machine!", 6, "No Previous Machine Name"
   WScript.Quit 1
Else
'Mount Registry from Windows Drive
oShell.Run "cmd.exe /c REG LOAD HKLM\TempHive " & strWinDrive & "\windows\system32\config\system",0,True
strCurrentComputer = oShell.RegRead("HKLM\TempHive\ControlSet001\Control\ComputerName\ComputerName\computername")
env("OSDComputerName") = strCurrentComputer
WScript.Quit 0
End If

Scheduled Task Set ADR Disabled or Enabled SCCM ConfigMgr

When I setup a customers SCCM (ConfigMgr) site for patching I use ADR’s (Automatic Deployment Rules) to create a no hassle patching cycle each month.
This is done by automatically creating the monthly Software Update groups and then creating the deployments but NOT enabling them to the customer’s Pilot collections, Release Collections and Production Collections. This allows the customer to effectively “right click, enable” the deployment to that collection when ready.

The problem you have with this is the “Critical” security patches that are released out of the usual time period. You know the patches that cover that hole that no one noticed before release!
Anyway to get round that I create more ADR’s that run every day checking for a “Critical” Patch release. The issue with this is if left… Yep you guessed it, it will run on the monthly schedule day as well, which will just duplicate content.

So I came up with this Script to be run as a Scheduled Task by a service account just before the main ADR’s run and then later that day when they are complete.

Here is the Script:

##############################################################################################################################################
#Author: C5 Richie Schuster - SCCMOG.COM
#Script: Set-ADREnableDisabled
#Usage : "Set-ADREnableDisabled -State Enabled -SiteCode S0G" or "Set-ADREnableDisabled -State Disabled -SiteCode S0G"
#Info  : This script was writtent to run as a scheduled task to automatically disable and enable ADR Rules specified in the variable $ADRNames
##############################################################################################################################################
#Parameters
Param
(
[parameter(mandatory=$true,HelpMessage="Please, provide your SiteCode.")][ValidateNotNullOrEmpty()][String]$SiteCode = "",
[parameter(mandatory=$true,HelpMessage="Please, provide a state for the script to Run e.g. Enable or Disable")][ValidateNotNullOrEmpty()][String]$State = ""
)

#ADR Names stored in ARRAY -  Copy and Pasted name of ADR Bellow.
$ADRNames = @("ADR Critical Security Releases Windows 10 1607",`
            "ADR Critical Security Releases Windows 10 1511")

#Disable warnings for Fast switch
$CMPSSuppressFastNotUsedCheck = $true

# Check for elevation
Write-Host "Checking for elevation"
If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(`
    [Security.Principal.WindowsBuiltInRole] "Administrator"))
{
    Write-Warning "Oupps, you need to run this script from an elevated PowerShell prompt!`nPlease start the PowerShell prompt as an Administrator and re-run the script."
    Write-Warning "Aborting script..."
    Break
}
#Import Module but check if user entered sitecode
If ($SiteCode -ne "") {
#[string]$SiteCode = "P01"
# Import the ConfigurationManager.psd1 module 
Write-Host "Importing ConfigMgr Module..." -ForegroundColor Yellow
Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1"
# Set the current location to be the site code.
Write-Host "Setting Location to ConfigMgr Drive..." -ForegroundColor Yellow
Set-Location "$SiteCode`:"
}
Else {
    Write-Warning "Oupps, you need to enter a Site code!`nPlease use the -SiteCode followed by your sitecode."
    Write-Warning "Aborting script..."
    Break
}

#If State set to Disable
If ($State -eq "Disable") {
    Foreach ($ADR in $ADRNames) {
        #Retrieve ADR information
        $RetADR = Get-CMSoftwareUpdateAutoDeploymentRule -Name $ADR
            #Check if ADR is Enabled and if so disable
            If ($RetADR.AutoDeploymentEnabled -eq $True) {
                Write-Host "Its On... Disabling...." -ForegroundColor Yellow
                #Disable ADR
                Set-CMSoftwareUpdateAutoDeploymentRule -Name $RetADR.Name -Enable $false
                #Check Action successfully completed.
                $Check = Get-CMSoftwareUpdateAutoDeploymentRule -Name $ADR
                If ($Check.AutoDeploymentEnabled -eq $False) {
                    Write-Host "Successfully Disabled $($Check.Name)!" -ForegroundColor Green
                    }
            }
            #If ADR Already Enabled Warn User and move onto next.
            ElseIf ($RetADR.AutoDeploymentEnabled -eq $false) {
                    Write-Host "$($Check.Name) is already disabled!" -ForegroundColor Green
            }
            #If ADR same as previous name or not pupulated then warn user.
            Elseif (($RetADR.Name -ne $ADR) -or ($RetADR -eq $null)) {
                    Write-Host "ADR $ADR cannot be found!" -ForegroundColor Red        
            }
            #If you hit this something fishy is going on!
            Else {
                Write-Host "Error please message Richie Schuster C5 - SCCMOG.com" -ForegroundColor Red 
            }
    }
}

#If State set to Enable
ElseIf ($State -eq "Enable") {
    Foreach ($ADR in $ADRNames) {
        #Retrieve ADR information
        $RetADR = Get-CMSoftwareUpdateAutoDeploymentRule -Name $ADR
            #Check if ADR is Disabled and if so enable
            If ($RetADR.AutoDeploymentEnabled -eq $False) {
                Write-Host "Its Off... Enabling...." -ForegroundColor Yellow
                #Enable ADR
                Set-CMSoftwareUpdateAutoDeploymentRule -Name $RetADR.Name -Enable $True
                #Check Action successfully completed.
                $Check = Get-CMSoftwareUpdateAutoDeploymentRule -Name $ADR
                If ($Check.AutoDeploymentEnabled -eq $True) {
                    Write-Host "Successfully Enabled $($Check.Name)!" -ForegroundColor Green
                    }
            }
            #If ADR Already Disabled Warn User and move onto next.
            ElseIf ($RetADR.AutoDeploymentEnabled -eq $True) {
                    Write-Host "$($Check.Name) is already enabled!" -ForegroundColor Green
            }
            #If ADR same as previous name or not pupulated then warn user.
            Elseif (($RetADR.Name -ne $ADR) -or ($RetADR -eq $null)) {
                    Write-Host "ADR $ADR cannot be found!" -ForegroundColor Red        
            }
            #If you hit this something fishy is going on!
            Else {
                Write-Host "Error please message Richie Schuster C5 - SCCMOG.com" -ForegroundColor Red 
            }
    }
}
#If Input empty or does not match write warning.
Else {
    Write-Host "Please use Enable or Disable param e.g. Set-ADREnableDisabled -State Enable  -SiteCode S0G" -ForegroundColor Red
    Set-Location $PSScriptRoot
}
################################################################

Here is the XML for the Scheduled Task to disable the daily ADRs. You will have to change some details but this should get you going. When you want to re-enable it in the evening just change line 65 from Disable to enable:

<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <Date>2017-05-02T16:06:29.8383361</Date>
    <Author>SCCMOG\Administrator</Author>
    <Description>This task runs one a month to disable the critical security ADRs.</Description>
  </RegistrationInfo>
  <Triggers>
    <CalendarTrigger>
      <StartBoundary>2017-05-02T01:00:00</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByMonthDayOfWeek>
        <Weeks>
          <Week>2</Week>
        </Weeks>
        <DaysOfWeek>
          <Wednesday />
        </DaysOfWeek>
        <Months>
          <January />
          <February />
          <March />
          <April />
          <May />
          <June />
          <July />
          <August />
          <September />
          <October />
          <November />
          <December />
        </Months>
      </ScheduleByMonthDayOfWeek>
    </CalendarTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <UserId>YourDomain\SCCMAdmin</UserId>
      <LogonType>Password</LogonType>
      <RunLevel>HighestAvailable</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
    <AllowHardTerminate>true</AllowHardTerminate>
    <StartWhenAvailable>false</StartWhenAvailable>
    <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
    <IdleSettings>
      <StopOnIdleEnd>true</StopOnIdleEnd>
      <RestartOnIdle>false</RestartOnIdle>
    </IdleSettings>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <Enabled>true</Enabled>
    <Hidden>false</Hidden>
    <RunOnlyIfIdle>false</RunOnlyIfIdle>
    <WakeToRun>false</WakeToRun>
    <ExecutionTimeLimit>P3D</ExecutionTimeLimit>
    <Priority>7</Priority>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>Powershell.exe</Command>
      <Arguments>-ExecutionPolicy Bypass -File D:\Setup\Scripts\Set-ADREnableDisabled.ps1 .\Set-ADREnableDisabled.ps1 -State Disable -SiteCode P01</Arguments>
    </Exec>
  </Actions>
</Task>

Import IP Boundaries and Boundary Groups PowerShell SCCM ConfigMgr

This script is designed to work in harmony with the Export Sites and Subnets to CSV script I blogged about recently. The CSV file that is created by that script can then be used to import IP Subnet Boundaries and Groups with this PowerShell script.

Each Site will be Created as a Boundary Group and each Subnet listed with that Site in the CSV will be created as a IP Subnet Boundary associated to the Boundary Group.

Here is the Script:

#########################################################################################################
#Script Name:   Import Boundaries and Boundary Groups from CSV                                          #
#Script Author: SCCMOG - Richie Schuster 06/03/2017 WWW.SCCMOG.COM                                      #
#########################################################################################################
#Script Usage: ImportBoundariesandGroups.ps1 -CSVParam MyCSV.csv                                  #
#########################################################################################################

#CSV Name accepted as first PARAM
Param
(
[parameter(mandatory=$true,HelpMessage="Please, provide your SiteCode.")][ValidateNotNullOrEmpty()][String]$SiteCode,
[parameter(mandatory=$true,HelpMessage="Please, provide a CSV to import. It must be in the same folder as the script e.g. Sites.CSV")][ValidateNotNullOrEmpty()][String]$CSVParam
)

# Check for elevation
Write-Host "Checking for elevation"
If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(`
    [Security.Principal.WindowsBuiltInRole] "Administrator"))
{
    Write-Warning "Oupps, you need to run this script from an elevated PowerShell prompt!`nPlease start the PowerShell prompt as an Administrator and re-run the script."
    Write-Warning "Aborting script..."
    Break
}

If ($CSVParam -ne ""){

    #Import CSV
    $path     = Split-Path -parent $MyInvocation.MyCommand.Definition 
    $newpath  = $path + "\$CSVParam"
    #Check location of CSV is valid.
    If (Test-Path $newpath){
    $BoundaryList = Import-Csv -Path $newpath
    #Import ConfigMgr Module
    Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1"
    #Set the current location to be the site code.
    Set-Location "$SiteCode`:"

        foreach ($_ in $BoundaryList){
            #Check If Boundary Group Already Created
            $getbg = Get-CMBoundaryGroup -Name $($_.Name)
 
            #If no bounday group maching that name create it
            if ($getbg -eq $null){
                New-CMBoundaryGroup -Description $($_.Name) -Name $($_.Name)
                }

            #Split on /
            $Subnet,$Bit = $_.Subnet.split('/',2)

            #Check if Boundary is already Created
            $getbn = Get-CMBoundary | where Value -eq $Subnet
    
            #If it is not then create new boundry and add it to Boundary Group
            if ($getbn -eq $null){
            New-CMBoundary -DisplayName $($_.Name) -BoundaryType IPSubnet -Value $Subnet
            Add-CMBoundaryToGroup -BoundaryGroupName $($_.Name) -BoundaryName $($_.Name)
                }
            }
        }
    Else{
    Write-Host "Please enter VALID CSV Name. Make sure it is in the same folder as this script." -ForegroundColor Cyan
    }
}
Else{
    Write-Host "Please enter CSV Name. Make sure it is in the same folder as this script." -ForegroundColor Cyan
}
###############################################################################################################

Below is a demonstration of the Script complete:

Import Boundaries and Groups PowerShell Script output
Import Boundaries and Groups PowerShell Script output
IP Subnet Boundaries Created
IP Subnet Boundaries Created
Boundary Groups Created
Boundary Groups Created
CSV from Export Script
CSV from Export Script

Copyright 2016 SCCMOG | All Rights Reserved