Showing posts with label scripting. Show all posts
Showing posts with label scripting. Show all posts

Wednesday, July 13, 2011

SCCM/SMS Client Uninstall Script

Forgive the sloppy code but I'm just posting this in response to a post on TechNet in regards to someone trying to mass uninstall the SCCM client.

This script was hastily/sloppily written to address a major problem we had migrating from SMS 2003 to SCCM 2007 where the clients didn't like being reassinged to a new site. The fix action ended up being a myraid of things:

  1. Hung 'ccmexec' service due to the process not terminating
  2. The uninstall didn't fully complete
  3. Duplicate GUID problems
  4. ...etc

You may have to change some parts around:

On Error Resume Next

Set objShell = CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")

strOutputFile = "CCMOutputFile.txt"
strComputerFile = "computers.txt"
strSMSCfgFile = "c$\Windows\smscfg.ini"
strSMSDelCertString = "c:\temp\ccmdelcert.exe"
strSMSUninstallString = "c:\windows\system32\ccmsetup\ccmsetup.exe /uninstall"
strSMSCleanString = "c:\temp\ccmclean.exe /all /q"
strSCCMServer = "SCCMSERVERNAME"
strSMSServiceName = "ccmexec"

iComputersSuccess = 0
iComputersOffline = 0
iComputersTotal = 0



arrComputers = Split(getTextFile(strComputerFile), vbCrLf)

If IsArray(arrComputers) Then
 For Each strComputer In arrComputers
  strComputer = Trim(strComputer)
  If strComputer <> "" Then 
   WScript.Echo "Pinging " & strComputer & " to see if it is online."
   If Ping(strComputer) Then
    WScript.Echo "Binding to " & strComputer & " via WMI."
    Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
    If Err.Number <> 0 Then
     displayError("Binding error to WMI on:  " & strComputer)
     Err.Clear
    End If
    
    If Not objWMI Is Nothing Then
    
     WScript.Echo "Copying pertinent files to c:\temp"
     If Not objFSO.FileExists("\\" & strComputer & "\c$\" & strSMSUninstallString) Then
      objFSO.CopyFile "\\" & strSCCMServer & "\SCCM Client Tools\*", "\\" & strComputer & "\c$\temp\", true
     End If
     
     killProcess strComputer, "ccmexec.exe"

     Set objWMIProcess = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process") 
     
     WScript.Echo "Running delcert process on remote host."
     If objFSO.FileExists("\\" & strComputer & "\c$\temp\ccmdelcert.exe") Then
      spawnProcess strComputer, strSMSDelCertString
     Else
      WScript.Echo "Unable to locate delcert executable for execution."
     End If
     
     WScript.Echo "Running ccmsetup /uninstall process on remote host."
     If objFSO.FileExists("\\" & strComputer & "\c$\windows\system32\ccmsetup\ccmsetup.exe") Then
      spawnProcess strComputer, strSMSUninstallString
     Else
      WScript.Echo "Unable to locate ccmsetup executable for execution."
     End If
     
     WScript.Echo "Running ccmclean process on remote host."
     If objFSO.FileExists("\\" & strComputer & "\c$\temp\ccmclean.exe") Then
      spawnProcess strComputer, strSMSCleanString
     Else
      WScript.Echo "Unable to locate ccmclean executable for execution."
     End If
           
     iComputersSuccess = iComputersSuccess + 1
    Else    
     WScript.Echo "Error binding to WMI using the syntax:  winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2"
    End If
   Else
    iComputersOffline = iComputersOffline + 1
   End If
   iComputersTotal = iComputersTotal + 1
  End If
  If iComputersTotal Mod 5 = 0 Then
   WScript.Echo ""
   WScript.Echo "STATUS UPDATE:"
   WScript.Echo vbTab & "Hosts Successfully Uninstalled:  " & iComputersSuccess
   WScript.Echo vbTab & "Hosts Offline:  " & iComputersOffline
   WScript.Echo vbTab & "Total Hosts Evaluated:  " & iComputersTotal
   WScript.Echo ""
  Else
   WScript.Echo ""
  End If
 Next
End If



' ***********************************************************************************

Sub displayError(strMessage)
    'Display custom message and information from VBScript Err object.

    strError = VbCrLf & "ERROR:  " & strMessage & VbCrLf & _
      "Number (dec) : " & Err.Number & VbCrLf & _
      "Number (hex) : &H" & Hex(Err.Number) & VbCrLf & _
      "Description  : " & Err.Description & VbCrLf & _
      "Source       : " & Err.Source
    Err.Clear
    WScript.Echo strError

End Sub

Function Ping(strComputer)
 Dim objPing, strPing

 Set objPing = objShell.Exec("ping -n 1 -w 2000 " & strComputer & "")
 
 strPing = objPing.StdOut.ReadAll()
 
 If Instr(strPing, "Reply") <> 0 Then
  Ping = True
 Else
  Ping = False
 End If
End Function


Function getTextFile(strFilePath)
 If Not objFSO.FileExists(strFilePath) Then
  WScript.Echo "Could not locate text file:  " & strFilePath
  WScript.Quit
 End If
 
 Set objTextFile = objFSO.OpenTextFile(strFilePath, 1)
 strTemp = objTextFile.ReadAll
 objTextFile.Close
 
 getTextFile = strTemp
End Function

Sub killProcess(strComputer, strProcess)
 Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator") 
 objSWbemLocator.Security_.privileges.addasstring "sedebugprivilege", true
 Set objWMIService = objSWbemLocator.ConnectServer(strComputer, "root\CIMV2")
 Set colProcesses = objWMIService.ExecQuery("Select * From Win32_Process Where Name = '" & strProcess & "'")
 
 If colProcesses.Count = 0 Then
  log("Process not found to be running:  " & strProcess & vbCrLf)
 ElseIf colProcesses.Count > 0 Then
  For Each objProcess in colProcesses
   intReturn = objProcess.Terminate()
   log("Attempting to kill process (" & strProcess & ") returned error code:  " & intReturn & vbCrLf)
  Next
 Else
  log(".Count method returned an unexpected value while attempting to kill:  " & strProcess & vbCrLf)
 End If
End Sub

Sub spawnProcess(strComputer, strExec)
 intReturn = objWMIProcess.Create(strExec)
 Select Case intReturn
  Case 0 WScript.Echo "Process creation was a success"
  Case 2 WScript.Echo "Process creation returned Access Denied"
  Case 3 WScript.Echo "There were insufficient priviledges to complete the process"
  Case 8 WScript.Echo "Unknown failure"
  Case 9 WScript.Echo "Path not found"
  Case 21 WScript.Echo "Invalid Parameter"
  Case Else WScript.Echo "Process creation returned an unrecognized parameter"
 End Select
End Sub

Wednesday, October 20, 2010

Random Local Administrator Password Changer

Title:  Random Local Administrator Password Changer
Author:  Cameron Wilson (thepip3r)
Last Updated:  10/20/10
Date Developed: 03/15/06
Description:
Generates random passwords of the max complexity and length using the Microsoft
specifications for an account password.

The purpose of this script is to randomize the local administrator account password.
This was developed to be used in an domain/enterprise environment where you either never
want end-users logging in with the local admin account and/or you want a high random
complexity set for the local admin account.  Active Directory does not give a way
to control this value so to ensure it's not used by people we don't want to use it,
we rely on our Domain/Enterprise/Delegated Admin accounts for access.

FAQ:
Q:  What if I need to know the local admin password?
A:  A person with the appropriate rights level can remotely change the value of the
local admin password and then log in where necessary.
Q:  What if the computer has lost connectivity/trust to the domain?
A:  Rely on password cracking utilities to reset the password.
(e.g. ERD Commander, Linux Crack Disk, etc.)

Requirements:
 - Windows 2000 or better
 - MUST be run as a startup script via Group Policy

The commented-out values in generatePassword() are for a possible upcoming feature I just haven't gotten around to yet where you'll be able to specify (via command-line args) what complexity level of a password to generate (e.g. alphas, alphas+nums, alphas+nums+specials, etc.).

Remember that this is written to randomly generate an UNKNOWN password to set as the local admin password in order to give a best attempt that it won't be cracked remotely/interactively. As everyone knows though, if you have local-physical access to the machine, anyone will be able to simply overwrite this value using a bootable password cracking utility.

Examples of generated passwords at max length with max complexity (forgive the formatting issues with the blog):

g`Lp_Ogy[[D-\)>W7U=Dq\XMmh5[+6/CIb-0@QH!<]&G=+bqrox^R^9ONjpug8RE*ei2dk*;`waIxECtSrY`3atj/*RwH:3He=bL],#VY7Zcq_<LMJRz,9m*(DKOAl-z

#vb+ue#5qpZBq>TmMkRY,rmc(#KqAKEY^xCFVg^7Rr;]S@w-.+4thtOed&,1"Nh[@z$Hy'?Qu3w_4[X/i-ovIv0%E@g3^PI]!:_JZ)zSW5Xao]:IJGPx*6k'&BHM?j*w

70v@/y7I++oW,Sh'a%gnA,(w=8_+V`Yms2WZj!rKf-PqgU2AB?H.".cyx:@E7b"oT59\4<Tf0G1sHomD$B)0]1D:YT"Grd^r5Ot_o>5hkIlv*qN^_\e3>K%<;V]bS%?2

0(o8'r0A$#gO$KazYx_f9%zp50X#NXQfk+PRctkD_%Hi`M*:;8@'t'[rq29>/ZuhL-1U,4L^(@)lAhe<v:")V)=2RMt@j]Vj.GlWg6-`cBen"jGVWT]+7Cx43OUZLw7*

iaNq`Piz]\F.]*@Y8W>Er^YOni7\-70EJd/1BSJ#>^'H?,cstqy`S`:QPkrwh9TG+fj4em+=aybKzGDuUs[b5bvk1,SyI<5Ig&K6Fof?B!DM[I&563<dp"Wml.49+Vpc

PH4XG7OaCC-oDk'?y=%,YD@5UPwCnxq+1Jpr(:0c%Eh/%mJYZX`F:G!8x:AE7b#pT59\4<Tf0G1tIomD$B*1]1D:ZT"Hre^r5Ot_o>5hkJlv*rN^_\e3?K&<;W]bS%?2

(!g1zj(:vv_HwDYrRpX_2wsh.)PvFQJ^d#HK[lc<WxAbXF#2309ymyTji+16(Sm`E&*M%,DV!8"d9`^5n3t!N"5+JEm8cUNc&@eO`/&Y\:]gub?OPMU$/<p-,GNSDo0#

QI6YH9QbED.pEl(Az?&-ZFA7VQyDoyr-2Lqs*;2e&Fi0'nK[\YaH;H"98SZ_P!</mNRvMUm%IaJ3b/,]=[CJwJ^Ssn;a1$w1Oh3x.WN'*c,5C1hwxu$LXd?UTpv!m>XK

?8$H7'?Q33v_4[p/i-ovI40%E@g3]hau!:_br)zSn5Xyo]:IJGP6*6k'&BHM?j*w\<Ad<C[m8O9!PwuL+J18e9LBa\*Ozlez=W"fwF=psQt#2yVfgdl;FS-DB^ej[,G:

vnZ$m]u-iiS;j7MeEcKR%jf[!vCi:D=QWq<>O`W0Kk4UK9p&'$,l`mG^\x%)uFaT8sw@rz8Jn+oX-SQ(b&hoAo(x>8`,VIBVs3XCS"sLO.PZhV2BC@Iq#/dzy;AF7c#p

/'m7&p.@""fN#J_xXv^e8#yn4/V"MWPdj)OQariB^$Gh^L)897?%s&Zqo17<.YsgK,0S+3K]'>(j@fd;u9z'T(;1PKs?i[Ui,FkVf5,_b@cm!hEUVS\*6Bw32NTYJv6)

OG3WF6N`BB,nCj&>x<$+XC?4TOvBmwp*0Ioq'90b$Dg.$lIYYW_E9Fz75QX\Ny:-kLPsKSk#G^H1`,*[;Y@HtH[Qqk9_/!u/Lf1v,UL%(a)3A/euvs"JVb=SRntyj<VI

And here is the actual vbs:

' *************************************************************************
' Title:  Random Local Administrator Password Changer
' Author:  Cameron Wilson (thepip3r)
' Last Updated:  10/20/10
' Date Developed: 03/15/06
' Description:
'  Generates random passwords of the max complexity and length using the Microsoft
'  specifications for an account password.
'
'  The purpose of this script is to randomize the local administrator account password.
'  This was developed to be used in an domain/enterprise environment where you either never
'  want end-users logging in with the local admin account and/or you want a high random
'  complexity set for the local admin account.  Active Directory does not give a way
'  to control this value so to ensure it's not used by people we don't want to use it, 
'  we rely on our Domain/Enterprise/Delegated Admin accounts for access.
'
' FAQ:
'  Q:  What if I need to know the local admin password? 
'  A:  A person with the appropriate rights level can remotely change the value of the 
'   local admin password and then log in where necessary.
'  Q:  What if the computer has lost connectivity/trust to the domain?
'  A:  Rely on password cracking utilities to reset the password.
'   (e.g. ERD Commander, Linux Crack Disk, etc.)
'
' Requirements:
'  - Windows 2000 or better
'  - MUST be run as a startup script via Group Policy
'
' Link References:
'  http://blogs.technet.com/b/heyscriptingguy/archive/2005/07/22/how-can-i-determine-if-the-local-administrator-account-has-been-renamed-on-a-computer.aspx
'  http://blogs.technet.com/b/heyscriptingguy/archive/2007/07/03/how-can-i-change-the-local-administrator-password-on-all-my-computers.aspx
'  http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/windows_password_tips.mspx?mfr=true
' *************************************************************************


strPassword = generatePassword(127)
strAdminUser = getLocalAdminUser()
setAccountPassword ".", strAdminUser, strPassword


' *************************************************************************
' User Defined Functions
' *************************************************************************

Function generatePassword(iLength)

 If NOT IsNumeric(iLength) Then
  WScript.Echo "The value specified for the password generation must be a number."
  WScript.Quit
 End If

 ' Microsoft specifies that a password can be anywhere between 0 and 127 characters
 If iLength < 0 OR iLength > 127 Then
  WScript.Echo "The number specified for the password generation must be between 0-127."
  WScript.Quit
 End If

 'strSpecialCharacters = "33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,58,59,60,61,62,63,64,91,92,93,94,95,96,123,124,125,126"
 'strNumbers = "48,49,50,51,52,53,54,55,56,57"
 'strAlphaCap = "65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90"
 'strAlphaLower = "97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122"
 
 'arrSpecialCharacters = Split(strSpecialCharacters, ",")
 'arrNumbers = Split(strNumbers, ",")
 'arrAlphaCap = Split(strAlphaCap, ",")
 'arrAlphaLower = Split(strAlphaLower, ",")
 
 For i = 0 To iLength
  iRandomNumber = generateRandomInteger(33, 122)
  strTempPassword = strTempPassword & Chr(iRandomNumber)
 Next
 
 generatePassword = strTempPassword

End Function

' Generates a random integer between two given bounds
Function generateRandomInteger(iLower, iUpper)
 If Not IsNumeric(iLower) or Not IsNumeric(iUpper) Then
  WScript.Echo "The values passed to the random number generator function must be numbers."
  WScript.Quit
 End If
 
 ' Seed Rnd with a random value(Randomize) and then calculate the random value using the given bounds
 Randomize
 generateRandomInteger = Int((iUpper - iLower + 1) * Rnd + iLower)
End Function

' Find the local admin password based off of the indentifying SID attributes
Function getLocalAdminUser()
 strComputer = "."

 Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
 Set colAccounts = objWMIService.ExecQuery("Select * From Win32_UserAccount Where LocalAccount = TRUE")

 For Each objAccount in colAccounts
  If Left (objAccount.SID, 6) = "S-1-5-" and Right(objAccount.SID, 4) = "-500" Then
   strAdminAccountName = objAccount.Name
  End If
 Next
 
 getLocalAdminUser = strAdminAccountName
End Function

' Set the local admin account password based off of the random password generation params
Sub setAccountPassword(strDomain, strUser, strPassword)
 Set objUser = GetObject("WinNT://" & strDomain & "/" & strUser)
 objUser.SetPassword strPassword
End Sub