Powershell : Add $COMPUTERS to $GROUP

Introduction

This script was created to add all computers in a given text file to a Windows AD security group

Output

New objects are added the defined AD security group – check the variables in the script for the input file and target group
Local log file of events and errors on the executing computer C:\Logs\PowershellScripts\add_computers_to_group.ps1.log

Logging

Currently the logging is managed from within the script.
Log file location: C:\Logs\ADCudIncomingDisableAccounts\cudincomingDisable.ps1.log
$LOGTIME is s timestamp in the format “yyyy-MM-dd_hh-mm-ss”
Log call within the script:
“$LOGTIME <>” | Out-File $LOG -Append -Force
The script is then contained with a try{} catch{} parameter with logging output for all exception messages and items.
I’ve also tried to log throughout each action within the script so both SUCCESS and ERRORs are logged which provides a debugging method (at least I
should know where it falls over!).

Usage Examples

Contained in the header of the script – see below
Dependancies
Powershell module “Import-Module ActiveDirectory”

The Script

# Name        : Add Computers to Group
# Author    : Dave
# Date        : 
# Ticket#    :
# Scope     :  Text file containing computer names and an existing AD security group
# Input(s)    : text file with a list of computer names
# Output(s)    : 1. Log of script actions in csv to $LOGFILE
#                 2. Computers added to the specified AD security group
####################################################
# This script is designed to
# 1.  Add all computers in the $COMPUTERS text file to into $ADGROUP specified
####################################################
  
# Notes:
########################
  
  
# Set the variables
########################
$COMPUTERS = Get-Content -Path "ENTER AN ACCESSIBLE PATH TO A TEXT FILE OF COMPUTER NAMES, ONE PER LINE" # list of target computers
$GROUP = "ENTER A VALID AD SECURITY GROUP NAME TO TARGET"
 
$LOGFILEDIR = "C:\Logs\PowershellScripts\" # the full path of the log file for the script to output to
$LOGFILENAME =  "add_computers_to_group.ps1.log" # the full name of the log file for the script to output to
$LOG = ($LOGFILEDIR + "\" + $LOGFILENAME)
$LOGTIME = Get-Date -Format "MM-dd-yyyy_hh-mm-ss"
  
# Prepare the logging
##########################
# Check for the $LOGFILEDIR & $LOGFILENAME and create them if they don't exist
# NOTE: No logging until this happens except to STDOUT (Screen)
  
# Test for the folder and create if it doesn't exist
Try
    {
      
        if(! (Test-Path -Path $LOGFILEDIR )){
                New-Item -ItemType directory -Path $LOGFILEDIR
            }
    }
Catch
    {
        $ErrorMessage = $_.Exception.Message
        $FailedItem = $_.Exception.ItemName
    }
      
# test for the file and create if it doesn't exist
Try
    {
        if(! (Test-Path $LOGFILEDIR\$LOGFILENAME  )){
            New-Item -ItemType file -Path $LOGFILEDIR\$LOGFILENAME
        }
    }
Catch
    {
        $ErrorMessage = $_.Exception.Message
        $FailedItem = $_.Exception.ItemName
    }
  
  
"$LOGTIME BEGIN STARTING SCRIPT" | Out-File $LOG -Append -Force 
 
# Log the computer name in question
    # query ad for the computer and append the results to an array named $BITLOCKEDCOMPS
    Try
    {
        foreach ($COMPUTER in $COMPUTERS) {           
            $obj = Get-ADComputer $COMPUTER
            Add-ADGroupMember -ID $GROUP -Members $obj
            "$LOGTIME $($COMPUTER) ADDED TO $GROUP" | Out-File $LOG -Append -Force
         }
    }
    Catch
    {
        $ErrorMessage = $_.Exception.Message
        $FailedItem = $_.Exception.ItemName
        "$LOGTIME ERROR $($_) Creating C:\$($TARGETDIR) $($ErrorMessage) $($FailedItem)" | Out-File $LOG -Append -Force
    }
      
    
 
      
"$LOGTIME END EXITING SCRIPT" | Out-File $LOG -Append -Force
exit

Batch : Service Status & Recovery

@echo off
 
REM Change the "servicename" value to match your desired service below
REM Change the "logfilename" value to your own logfile
REM change the %processLinked% value to the process name associated with the target service 
 
set servicename="explorerService"
set processLinked="explorer.exe"
set logfilename="C:\Logs\thisscript.log"
 
rem get the date and time
For /f "tokens=1-3 delims=/ " %%a in ('date /t') do (set mydate=%%c-%%b-%%a)
For /f "tokens=1-2 delims=/:" %%a in ('time /t') do (set mytime=%%a%%b)
 
rem execute the "sc query <service>" command and loop through the output
for /F "tokens=3 delims=: " %%i in ('sc query "%servicename%" ^| findstr " STATE"') do (
 
  rem log the datetime and service state to the logfile
  echo %mydate%_%mytime% >> %logfilename%
  echo "%servicename% Service's current state is: %%i" >> %logfilename%
 
  rem restart the service after killing off the associate %processLinked%
  echo "%servicename% Service is forcibly restarting..." >> %logfilename%
  taskkill /IM %processLinked% /F >> %logfilename%
  net start %servicename% >> %logfilename%
   
)

SCCM Site Console (Admin UI) Failure

Following a number of interferences with our beloved SCCM Primary Site it was in a broken state.

The “\Program Files\Microsoft Configuration Manager\AdminConsole\AdminUILog\SmsAdminUI.log” reported:

“Error Code:
ProviderLoadFailure
\r\nSystem.Management.ManagementException\r\nProvider load failure \r\n   at System.Management.ManagementException.ThrowWithExtendedInfo(ManagementStatus errorCode)
   at System.Management.ManagementObjectCollection.ManagementObjectEnumerator.MoveNext()
   at Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine.WqlQueryResultsObject.<GetEnumerator>d__74.MoveNext()\r\nManagementException details:
instance of __ExtendedStatus
{
    Operation = “ExecQuery”;
    ParameterInfo = “SELECT * FROM SMS_Site WHERE SiteCode = ‘XXX'”;
    ProviderName = “WinMgmt”;
};

Where “XXX” is the name of an SCCM site but not ours! This led me to https://docs.microsoft.com/en-us/previous-versions/system-center/configuration-manager-2007/bb633148(v=technet.10)?redirectedfrom=MSDN followed by https://docs.microsoft.com/en-us/previous-versions/system-center/configuration-manager-2007/bb932190(v=technet.10)?redirectedfrom=MSDN , this latter article walked me through examinig the SMS_Providor WMI class and it is there I found the spurious reference to the unknown XXX site.

Deleting that reference restored AdminUI Console functionality (yay!).

Another case with similar symptoms was the result of a WMI db corruption which caused the OS to automatically rebuild the db but which did not re-import the SCCM WMI references. That was resolved by:

  1. Run > Wbemtest
  2. Connect to “root\sms” –> Enum Classes–>Select recursive and check for SMS_ProviderLocation – it was not present
  3. From an elevated command prompt enter the following commands to add the SCCM .mof’s (excluding the _*.mofs) to the $mofs variable and then switch to the Wbem folder and import the WMI modules to the OS PS D:\> $mofs = get-childitem "D:\Program Files\Microsoft Configuration Manager\bin\X64" -filter "*.mof" -exclude "_*.mof" -recursePS D:\> cd C:\Windows\System32\WbemPS C:\Windows\System32\Wbem> foreach ($mof in $mofs){mofcomp $mof.FullName}
  4. Restart the Windows Management Instrumentation Service
  5. Repeated Steps#1 & 2 and noted SMS_ProviderLocation now exists in WMI
  6. Launched SCCM Admin Console locally successfully
  7. Launched SCCM Admin Console remotely successfully
  8. Launched Task Sequence Creation Wizard successfully

Powershell Domain Controller Assessment

To get a list of the FSMO Role holders for a Single Domain.

1 Get-ADDomain | Select-Object DistinguishedName, SchemaMaster, DomainNamingMaster, InfrastructureMaster, PDCEmulator, RIDMaster

To get a list of the FSMO Role holders in a Forest.

1 Get-ADForest | Select-Object Name,SchemaMaster, DomainNamingMaster,InfrastructureMaster, PDCEmulator, RIDMasterall

To get a nicely formatted list with all the Domain Controllers and who owns which particular role.

1 Get-ADDomainController -Filter * | Select-Object Name, Domain, Forest, OperationMasterRoles | Where-Object {$_.OperationMasterRoles}

ref: https://www.markou.me/2016/10/get-list-fsmo-role-holders-using-powershell-one-liners/

Remote Desktop CredSSP Failure

Temporary reprieve for affected clients:

 

REG ADD HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System\CredSSP\Parameters\ /v AllowEncryptionOracle /t REG_DWORD /d 2

 

Revert via this command once all remote connections are patched:

REG ADD HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System\CredSSP\Parameters\ /v AllowEncryptionOracle /t REG_DWORD /d 1

PowerShell : Editing File Properties

Whilst writing a script which included a recycler section to ensure files older than 14 days were removed from a directory I needed a way to test the code. I then came across the set-itemproperty cmdlet which was just what I needed.

First i explored the cmdlet via:

get-help get-itemproperty

and

get-help get-itemproperty -examples

This then led me to run the commands

$folder = "C:\tmp\test"
get-itemproperty $folder | format-list -property *
PSPath : Microsoft.PowerShell.Core\FileSystem::C:\tmp\test
PSParentPath : Microsoft.PowerShell.Core\FileSystem::C:\tmp
PSChildName : test
PSDrive : C
PSProvider : Microsoft.PowerShell.Core\FileSystem
Mode : d-----
BaseName : test
Target : {}
LinkType :
Name : test
FullName : C:\tmp\test
Parent : tmp
Exists : True
Root : C:\
Extension :
CreationTime : 6/21/2018 11:30:13 AM
CreationTimeUtc : 6/21/2018 10:30:13 AM
LastAccessTime : 6/21/2018 11:30:13 AM
LastAccessTimeUtc : 6/21/2018 10:30:13 AM
LastWriteTime : 6/21/2018 11:30:13 AM
LastWriteTimeUtc : 6/21/2018 10:30:13 AM
Attributes : Directory

I wanted to set the creation and modified dates back in time to test my recyler one-liner, I acheieved this by first setting a variable to be a datetime object in the past (US date format so that’s the 31st January 2018):

$olddate = [datetime]"1/31/2018"

I then assigned this datetime value to the properties of the folder I wanted via the commands:

Set-ItemProperty $folder -Name CreationTime -Value $olddate
Set-ItemProperty $folder -Name LastWriteTime -Value $olddate

This worked a treat. I could then use this command to delete the folder and it’s contents if it was older than 14 days (credit to https://www.thomasmaurer.ch/2010/12/powershell-delete-files-older-than/ for this one):

$Daysback = "-14"
$CurrentDate = Get-Date
$DatetoDelete = $CurrentDate.AddDays($Daysback)
Get-ChildItem C:\tmp | Where-Object { $_.LastWriteTime -lt $DatetoDelete } | Remove-Item -recurse -force

SCCM DP Package Transfer Errors

The Problem

After a DNS change on one of our Distribution Points within SCCM 2012 R2 I decided to remove the old DP entry and recreate it. Removing the DP was easy enough, drop the roles and then delete the server from Administration > Servers and Site System Roles then wait 24 hours for synchronisation to remove the content from the DP.

I then created a new DP in SCCM under the new DNS name and monitored the package transfer via Monitoring > Distribution Point Group Status > All Site Distribution Points. The results looked bad, every package was failing to transfer.

The Investigation

I then reviewed the PkgXferMgr.log file at \\<<SCCM PRI SITE>\SMS_ES1\Logs\ which contained the errors:

Failed to get object class $$<SMS_PACKAGE_TRANSFER_MANAGER><06-14-2018 06:26:25.828-60><thread=9112 (0x2398)>
~ExecStaticMethod failed (80041002) SMS_DistributionPoint, AddFile $$<SMS_PACKAGE_TRANSFER_MANAGER><06-14-2018 06:26:25.828-60><thread=9112 (0x2398)>
CSendFileAction::AddFile failed; 0x80041002 $$<SMS_PACKAGE_TRANSFER_MANAGER><06-14-2018 06:26:25.828-60><thread=9112 (0x2398)>
Failed to add the file bcmnfcscr7-x64.cat in content 01C39B5C-4DA1-4A0E-A328-3FD2AC9F500F. Error 0x80041002 $$<SMS_PACKAGE_TRANSFER_MANAGER><06-14-2018 06:26:25.828-60><thread=9112 (0x2398)>
CSendFileAction::AddFileMetaData failed; 0x80041002 $$<SMS_PACKAGE_TRANSFER_MANAGER><06-14-2018 06:26:25.828-60><thread=9112 (0x2398)>
CSendFileAction::SendFiles failed; 0x80041002 $$<SMS_PACKAGE_TRANSFER_MANAGER><06-14-2018 06:26:25.828-60><thread=9112 (0x2398)>
CSendFileAction::SendContent failed; 0x80041002 $$<SMS_PACKAGE_TRANSFER_MANAGER><06-14-2018 06:26:25.828-60><thread=9112 (0x2398)>
~ Sending failed. Failure count = 24, Restart time = 14/06/2018 06:56:25 GMT Daylight Time $$<SMS_PACKAGE_TRANSFER_MANAGER><06-14-2018 06:26:25.828-60><thread=9112 (0x2398)>
Failed to get object class $$<SMS_PACKAGE_TRANSFER_MANAGER><06-14-2018 06:26:25.812-60><thread=5008 (0x1390)>
~ExecStaticMethod failed (80041002) SMS_DistributionPoint, AddFile $$<SMS_PACKAGE_TRANSFER_MANAGER><06-14-2018 06:26:25.859-60><thread=5008 (0x1390)>
CSendFileAction::AddFile failed; 0x80041002 $$<SMS_PACKAGE_TRANSFER_MANAGER><06-14-2018 06:26:25.859-60><thread=5008 (0x1390)>
Failed to add the file dptf_cpu.cat in content 08D125AE-8841-4C08-90AA-0D6B091B5C39. Error 0x80041002 $$<SMS_PACKAGE_TRANSFER_MANAGER><06-14-2018 06:26:25.859-60><thread=5008 (0x1390)>
CSendFileAction::AddFileMetaData failed; 0x80041002 $$<SMS_PACKAGE_TRANSFER_MANAGER><06-14-2018 06:26:25.859-60><thread=5008 (0x1390)>
CSendFileAction::SendFiles failed; 0x80041002 $$<SMS_PACKAGE_TRANSFER_MANAGER><06-14-2018 06:26:25.859-60><thread=5008 (0x1390)>
CSendFileAction::SendContent failed; 0x80041002 $$<SMS_PACKAGE_TRANSFER_MANAGER><06-14-2018 06:26:25.859-60><thread=5008 (0x1390)>
~ Sending failed. Failure count = 24, Restart time = 14/06/2018 06:56:25 GMT Daylight Time $$<SMS_PACKAGE_TRANSFER_MANAGER><06-14-2018 06:26:25.859-60><thread=5008 (0x1390)>

Inspecting the D:\ drive on the DP suggested the packages were actually being copied, there was plenty of capacity free on the taregt disk D:\ and it’s used storage was increasing through the synch process.

I did some searching online and came across a blog which described the error I received exactly:

http://www.christopherkibble.com/sccm-2012-dp-errors-sendfiles-failed

Following this blog restored my DP’s synchronisation functionality! What follows is a copy and paste job for reference.

The Solution

On the affected distribution point:

  1. Backup the registry
  2. elevated command prompt:
    cd c:\windows\system32\wbem
    for %F in (*.dll) do regsvr32 /s %F
    mofcomp -check AuditRsop.mof
  3. Review the output of the mofcomp command, if it looks like it’ll compile continue else address any issues:
    mofcomp -AuditRsop.mof
  4. Locate the SMS_DP$ share directory
    cd SMS_DP$\sms\bin
    for %F in (*.dll) do regsvr32 /s %F
    mofcomp -check smsdpprov.mof
  5. Review the output of the mofcomp command, if it looks like it’ll compile continue else address any issues:
    mofcomp smsdpprov.mof
  6. Reboot the DP
  7. Monitor the distribution status from the SCCM console (Monitoring > Distribution Point Group Status > All Site Distribution Points)

Windows Commands : Safeboot

Safe Mode:

bcdedit /set {default} safeboot minimal

Safe Mode with Networking:

bcdedit /set {default} safeboot network

Safe Mode with Command Prompt:

bcdedit /set {default} safeboot minimal
bcdedit /set {default} safebootalternateshell yes

To Remove either use msconfig to return to a normal boot or:

bcdedit /deletevalue {default} safeboot

Powershell Get-ADComputer

The following Powershell commmand uses the Get-ADComputer cmdlet to query AD and return a CSV with the headers “OU”,”Name” & “OperatingSystem”.
It was designed to return this information to marry up with GPO controlled policies against the OUs so I could plan servicing schedules.

Note the “-Properties *” to ensure the OperatingSystem value is available and the “-NoTypeInformation” to drop the header row of the CSV file and leave the column headers as the first row.

Get-ADComputer -Filter * -property * -SearchBase "OU=XXX, DC=XXX, DC=XXX, DC=XXX, DC=XXX" | Select @{l='OU';e={$_.DistinguishedName.split(',')[1].split('=')[1]}},"Name", "OperatingSystem" | export-csv -Path C:\SomeDir\SomeFile.csv -NoTypeInformation

Cancelling a Scheduled chkdsk (Check Disk)

  1. Boot from the Windows 10 DVD / install media
  2. [SHIFT]+[F10] to reveal a command prompt
  3. REGEDT32 to open registry editor
  4. Highlight HKLM > File > Load Hive
  5. Navigate to the local system disk :\Windows\System32\config and open [SYSTEM]
  6. Navigate to HKEY_LOCAL_MACHINE\<LOADED HIVE NAME>\CurrentControlSet\Control\Session Manager\ and edit the BootExecute MULTI-SZ value to read only: autocheck autochk *
  7. Reboot
  8. tadaa!