Update Line from LANDesk Actions.ini File

email me

This will uppdate the line containing SDCLIENTRECONNECT from the LANDesk actions.ini file. It adds missing double quotes.

From

SDCLIENTRECONNECT=C:\Program Files (x86)\LANDesk\LDClient\sdclient.exe /policyfile=”” /reconnect

To

SDCLIENTRECONNECT=C:\Program Files (x86)\LANDesk\LDClient\sdclient.exe /policyfile=”” /reconnect

Option Explicit 

Dim txtFile, oFSO, oFile, txtLine, modifiedFile, modLineContaining, replacementLine

Const ForReading = 1
Const ForWriting = 2

txtFile = "C:\Program Files (x86)\LANDesk\Shared Files\cbaroot\actions.ini"
modLineContaining = "SDCLIENTRECONNECT"

replacementLine = "SDCLIENTRECONNECT=""C:\Program Files (x86)\LANDesk\LDClient\sdclient.exe"" /policyfile="""" /reconnect"

Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oFile = oFSO.OpenTextFile(txtFile, ForReading)

Do Until oFile.AtEndOfStream
    txtLine = oFile.ReadLine
    If InStr(txtLine, modLineContaining) = 0 Then
        modifiedFile = modifiedFile & txtLine & vbCrLf
	else
		modifiedFile = modifiedFile & replacementLine & vbCrLf
    End If
Loop

oFile.Close

Set oFile = oFSO.OpenTextFile(txtFile, ForWriting)

oFile.Write modifiedFile
oFile.Close

'session clean up
txtFile = ""
txtLine = ""
txtLine = ""
modifiedFile = ""
modLineContaining = "" 
replacementLine = ""
set oFSO = Nothing
set oFile = Nothing

WScript.Quit(0)

 
Also see Remove Line from LANDesk Actions.ini File

 
Notes

Client Issue

When a LANDesk package is pushed and there is a pending update, the SDCLIENTRECONNECT line is generated.

Once this line exists, no other packages can be pushed until one of two things happen:

#1 The machine is rebooted. Once rebooted, the SDCLIENTRECONNECT line is cleared and packages can be pushed.

#2 Add quotes around Program Files (x86), just like the other lines. When quotes are added, packages can be pushed.

 
Technical Problem

Missing quotes on the SDCLIENTRECONNECT line if forcing unnecessary reboots.

 
Solution

Add quotes to generated line.

Screenshot

Remove Line from LANDesk Actions.ini File

email me

This will remove the line containing SDCLIENTRECONNECT from the LANDesk actions.ini file

Option Explicit 

Dim txtFile, oFSO, oFile, txtLine, modifiedFile, delLine

Const ForReading = 1
Const ForWriting = 2

txtFile = "C:\Program Files (x86)\LANDesk\Shared Files\cbaroot\actions.ini"
delLine = "SDCLIENTRECONNECT"

Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oFile = oFSO.OpenTextFile(txtFile, ForReading)

Do Until oFile.AtEndOfStream
    txtLine = oFile.ReadLine
    If InStr(txtLine, delLine) = 0 Then
        modifiedFile = modifiedFile & txtLine & vbCrLf
    End If
Loop


oFile.Close

Set oFile = oFSO.OpenTextFile(txtFile, ForWriting)

oFile.Write modifiedFile
oFile.Close

'session clean up
txtFile = ""
delLine = ""
txtLine = ""
modifiedFile = ""
set oFSO = Nothing
set oFile = Nothing

WScript.Quit(0)

Also see Update Line from LANDesk Actions.ini File File

 
Notes

Client Issue

When a LANDesk package is pushed and there is a pending update, the SDCLIENTRECONNECT line is generated.

Once this line exists, no other packages can be pushed until one of two things happen:

#1 The machine is rebooted. Once rebooted, the SDCLIENTRECONNECT line is cleared and packages can be pushed.

#2 Add quotes around Program Files (x86), just like the other lines. When quotes are added, packages can be pushed.

 
Technical Problem

Missing quotes on the SDCLIENTRECONNECT line if forcing unnecessary reboots.

 
Solution

Add quotes to generated line.

Screenshot

Add/Remove User from Local Admin, based upon AD Group; User Aware

email me

This script will add or remove a domain user from the local admin group based upon their membership to an Active Directory group. You basically just drop the user into the specified group, and the script does the rest. If the user is removed from the AD group, they will be removed from the local admin group.

I tested this in the System Account, so it can be deployed using desktop management software (preferably as a regular policy), or even as part of a login script.

Things to note:

  • Was tested in W7 and W10.
  • Was tested in the system account security context.
  • Tested locally and in desktop management software.
  • If user is not logged in, the script will exit.
  • To acquire the current user from the system account, I query the explorer.exe process and return the user.
  • It does work with nested AD groups.
  • Compile this script, if used in production.

 

'I've left some simple logging in place, 
'which I used for testing in the SYSTEM ACCOUNT
'you can remove it if not needed

Option Explicit
'on error resume next

Dim objRootDSE, objDBConnection, objRecord, objList, strDomain, strADGroup, strDB
Dim StrGroupDN, strSpace, strCurrentUser, MembershipStatus, strComputer, Return
Dim strNameOfUser, ReturnedUserName, objShell, strUserDomain, colProcesses, objProcess
Set objShell = CreateObject("Wscript.Shell")


'IS USER LOGGED IN?
UserLoggedInStatus()


'AD GROUP - AD GROUP TO QUERY - GROUPS CAN BE NESTED
'SYSTEM ACCOUNT: NO ISSUES
strADGroup = "AD_Group_Name_Here"


'COMPUTERNAME
'SYSTEM ACCOUNT: NO ISSUES
'set this computer name
strComputer = objShell.ExpandEnvironmentStrings("%COMPUTERNAME%")
strComputer = trim(strComputer)
strComputer = lcase(strComputer)


'DOMAIN OR WORKGROUP
'SYSTEM ACCOUNT: NO ISSUES
strUserDomain = objShell.ExpandEnvironmentStrings("%USERDOMAIN%")
strUserDomain = trim(strUserDomain)
strUserDomain = lcase(strUserDomain)

'used for logging - can be removed if not needed
objShell.run "cmd / md c:\setup",0,true

'WORKGROUP STATUS
'IF WORKGROUP IS FOUND, EXIT
'return in user context
if strUserDomain = strComputer then
	objShell.run "cmd /c echo user context workgroup>C:\setup\_ComputerType.txt",0,false
	Leave()
'return in SYSTEM ACCOUNT
elseif strUserDomain = "workgroup" then	
	objShell.run "cmd /c echo system account workgroup>C:\setup\_ComputerType.txt",0,false
	Leave()
elseif strUserDomain = "OtherWorkgroupName" then
	objShell.run "cmd /c echo system account workgroup>C:\setup\_ComputerType.txt",0,false
	Leave()
else
	objShell.run "cmd /c echo " & strUserDomain & ">C:\setup\_ComputerType.txt",0,false
end if



'DOMAIN
'SYSTEM ACCOUNT: NO ISSUES
Set objRootDSE = GetObject("LDAP://RootDSE")
strDomain = Trim(objRootDSE.Get("DefaultNamingContext"))



'USERNAME
'SYSTEM ACCOUNT: NO ISSUES
'Returns username from explorer.exe process
GetUserName()
strCurrentUser = ReturnedUserName
strCurrentUser = trim(strCurrentUser)
strCurrentUser = lcase(strCurrentUser)
objShell.run "cmd /c echo " & strCurrentUser & ">C:\setup\_CurrentUser.txt",0,false
'some simple validation
if strCurrentUser = strComputer & "$" then Leave()
if strCurrentUser = "" then Leave()
if strCurrentUser = "system" then Leave()

'Group membership is false(disabled) by default
MembershipStatus = "False"


'SET AD DB 
strDB = "Select ADsPath From 'LDAP://" & strDomain & "' Where ObjectCategory = 'Group' AND Name = '" & strADGroup & "'"

Set objDBConnection = CreateObject("ADODB.Connection")
objDBConnection.Provider = "ADsDSOObject":	objDBConnection.Open "Active Directory Provider"
Set objRecord = CreateObject("ADODB.Recordset")

'CONNECT TO AD
objRecord.Open strDB, objDBConnection

'TEST CONNECTION
'Can't find group - exiting now
if objRecord.EOF = True then
	Leave()
end if

'SCAN THROUGH TO END OF GROUPS
'if at end, leave
If objRecord.EOF Then
	'Group not found
	on error resume next

'If not at end, access next group
Elseif Not objRecord.EOF Then	
	on error resume next	
	objRecord.MoveLast:	objRecord.MoveFirst
	While Not objRecord.EOF		
		StrGroupDN = Trim(objRecord.Fields("ADsPath").Value)
		Set objList = CreateObject("Scripting.Dictionary")
		strSpace = " "
		NestedADMembers StrGroupDN, strSpace, objList, strCurrentUser
		Set objList = Nothing		
		objRecord.MoveNext
	Wend
End If


'ONCE COMPLETE, CHECK MEMBERSHIP STATUS
If MembershipStatus = "True" then 
	AccessGranted()
Else
	RemoveAccess()
end if

'Exit
Leave()




'MY SUBs AND FUNCTIONS

'Grant admin access
Sub AccessGranted()
	on error resume next
	'SYSTEM ACCOUNT: NO ISSUES
	objShell.run "cmd /c echo GRANT ACCESS>C:\setup\_AccessStatus.txt",0,false	
	objShell.run "net localgroup administrators " & strUserDomain & "\" & strCurrentUser & " /add",0,false
	WScript.Sleep 2000	
end sub


'Remove admin access
Sub RemoveAccess()
	on error resume next
	'SYSTEM ACCOUNT: NO ISSUES
	objShell.run "cmd /c echo REMOVE ACCESS>C:\setup\_AccessStatus.txt",0,false	
	objShell.run "net localgroup administrators " & strUserDomain & "\" & strCurrentUser & " /delete",0,false
	WScript.Sleep 2000
end sub


'Exit
Sub Leave()
	on error resume next	
	objRecord.Close:	Set objRecord = Nothing
	objDBConnection.Close:	Set objDBConnection = Nothing
	Set objRootDSE = Nothing
	WScript.Sleep 5000
	WScript.Quit
end sub


'Cycles through main Group
Sub MainADGroup(ADPath, strSpace, objList, strCurrentUser)
	on error resume next
	Dim objADGroup, objADMember, strADMember
	Set objADGroup = GetObject(ADPath)	
	For Each objADMember In objADGroup.Members		
		strADMember = trim(objADMember.sAMAccountName)
		strADMember = lcase(strADMember)
		
		'SYSTEM ACCOUNT: NO ISSUES
		objShell.run "cmd /c echo " & strADMember & ">>C:\setup\_GroupMembers.txt",0,false
		
		if strADMember = strCurrentUser then
			MembershipStatus = "True"
		end if
	Next	
End Sub


'Cycle through Nested Groups
Function NestedADMembers (ADPath, strSpace, objList, strCurrentUser)
	on error resume next
	Dim objGroup, objMember, strGroupMember
	Set objGroup = GetObject(ADPath)	
	Set objShell = CreateObject("Wscript.Shell")
	
	For Each objMember In objGroup.Members		
		strGroupMember = trim(objMember.sAMAccountName)
		strGroupMember = lcase(strGroupMember)
		
		'SYSTEM ACCOUNT: NO ISSUES
		objShell.run "cmd /c echo " & strGroupMember & ">>C:\setup\_GroupMembers.txt",0,false
		
		if strGroupMember = strCurrentUser then
			MembershipStatus = "True"			
		end if
		
		If Strcomp(Trim(objMember.Class), "Group", vbTextCompare) = 0 Then
			If objList.Exists(objMember.ADsPath) Then	
				'do nothing
			Else
				objList.Add objMember.ADsPath, 1
				MainADGroup objMember.ADsPath, strSpace & " ", objList, strCurrentUser				
			End If
		End If
	Next
End Function


'Returns Username from explorer.exe
Function GetUserName()
	on error resume next
	strComputer = "." 
	Set objShell = CreateObject("Wscript.Shell")
	Set colProcesses = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2").ExecQuery("Select * from Win32_Process Where Name = 'explorer.exe'")
	For Each objProcess in colProcesses 
		Return = objProcess.GetOwner(strNameOfUser)
		'SYSTEM ACCOUNT: NO ISSUES
		objShell.run "cmd /c echo " & strNameOfUser & ">C:\setup\_ExplorerProcessUser.txt",0,false
		If Return <> 0 Then 
			'no owner
		Else 		
			ReturnedUserName = strNameOfUser
		End If 
	Next 
End function


'Returns if user is logged on
Function UserLoggedInStatus()
	on error resume next
	Dim LoggedInStatus, objWMIService, colItems, strComputer, objshell, objItem
	Set objShell = CreateObject("Wscript.Shell")

	strComputer = "."

	Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
	Set colItems = objWMIService.ExecQuery("Select * from Win32_ComputerSystem",,48)

	For Each objItem in colItems
		LoggedInStatus = trim(objItem.UserName) & ""
	next

	if LoggedInStatus = "" then 
		'SYSTEM ACCOUNT: NO ISSUES
		UserLoggedInStatus = FALSE
		objShell.run "cmd /c echo " & UserLoggedInStatus & ">C:\setup\_LogonStatus.txt",0,false
		WScript.Quit(0)
	end if


	if LoggedInStatus <> "" then 
		'SYSTEM ACCOUNT: NO ISSUES
		UserLoggedInStatus = TRUE
		objShell.run "cmd /c echo " & UserLoggedInStatus & ">C:\setup\_LogonStatus.txt",0,false
	end if

	Set objItem = Nothing
	Set colItems = Nothing
	Set objWMIService = Nothing
End function

Generate Report of Last Boot Time from Computers.txt

email me

This can be used to return Last Boot Time on remote computers. Just add computer names into computers.txt, and run script. A report will be generated, as well as each computer’s info displayed in a pop up. You can disable the pop up if not needed.

VBScript

Option Explicit

Dim objFSO, txtComputers, txtReport, RemoteComputer, objWMI, varBootup
Dim varLastBootTime, varSystemUptime, colOS, objOS, txtCName, txtRName

'computers text file
txtCName = "_Computers.txt"

'report text file
txtRName = "_Boot_Report.txt"


Const ForReading = 1 
Set objFSO = CreateObject("Scripting.FileSystemObject")  
    
Set txtComputers = objFSO.OpenTextFile(txtCName, ForReading) 
Set txtReport = objFSO.CreateTextFile(txtRName) 
Do Until txtComputers.AtEndOfStream  
    RemoteComputer = txtComputers.Readline 
    Set objWMI = GetObject ("winmgmts:\\" & RemoteComputer & "\root\cimv2") 
    Set colOS = objWMI.ExecQuery ("Select * from Win32_OperatingSystem") 
    For Each objOS in colOS 
        varBootup = objOS.LastBootUpTime
        varLastBootTime = DateTranslation(varBootup)     
        'Writes to report
        txtReport.WriteLine "Remote Computer: " & RemoteComputer 
        txtReport.WriteLine "Last Reboot: " & varLastBootTime 
        varSystemUptime = DateDiff("h", varLastBootTime, Now)    
        txtReport.WriteLine "System online since " & varSystemUptime & " hours" & vbCrLf
        'Display pop up
        msgbox RemoteComputer & ": " & varLastBootTime,,"Last Boot"
    Next 

Loop 

'close write to text file
txtComputers.Close 

'done
MsgBox "Done! Report name  " & chr(34) & txtRName & chr(34) & "  was created.",64,"Report"
WScript.Quit(0)

'clear session
set objFSO = Nothing
set txtComputers = Nothing
set txtReport = Nothing
set objWMI = Nothing
set colOS = Nothing
varBootup = ""
RemoteComputer = ""
varLastBootTime = ""
varSystemUptime = "" 
objOS = ""

'translates boot time
Function DateTranslation(varBootup) 
    DateTranslation = CDate(Mid(varBootup, 5, 2) & "/" & Mid(varBootup, 7, 2) & "/" & Left(varBootup, 4) _ 
         & " " & Mid (varBootup, 9, 2) & ":" & Mid(varBootup, 11, 2) & ":" & Mid(varBootup, 13, 2)) 
End Function

 

PowerShell

Clear-Host
 
$txtComputers = "C:\Report\_Computers.txt"
$txtReport = "C:\Report\_Boot_Report.txt"
 
 
#Returns computer names
$computers = Get-Content $txtComputers
 
#Cycles through
foreach ($RemoteComputer in $computers)
    {     
    #Is computer online
    If (Test-Connection -ComputerName $RemoteComputer -ErrorAction SilentlyContinue -Quiet -Count 2) {
        #Returns boot time
        Get-WmiObject Win32_OperatingSystem -ComputerName $RemoteComputer).LastBootUpTime  
        #Convert the last boot time to a reader friendly date time format 
        $time = [System.Management.ManagementDateTimeConverter]::ToDateTime($objWMI)
        #output to console
        $RemoteComputer + "`n" + $time + "`n"
        #output to file
        "$RemoteComputer" + " " + "$time" | Out-file -FilePath $txtReport -Append
    }
    }

	Start-Sleep 5

# Clear session
$txtComputers = ""
$txtReport = ""
$computers = ""
$computer = ""
$objWMI = ""

 

Batch

cls
@Echo off
Title Last Reboot
color 0a
Setlocal EnableDelayedExpansion

:: Report name
Set report=Boot_Report.txt

:: Enter name of computer text file
Set PCList=Computers.txt

cls
Echo Searching for boot times...

:: PROGRAM ROUTINE
:CYCLE
for /f "tokens=* delims= "%%a in (%PCList%) do (
ping %%a | find "Reply" > nul
if errorlevel 1 (
echo %%a>> "_offline.txt"
echo.
%windir%\system32\ping.exe -n 2 127.0.0.1>nul
) else (
echo.
for /f "tokens=1,2,3,4" %%g in ('dir /a:h \\%%a\c$\pagefile.sys ^|find "pagefile.sys"') do (
set bTime=%%a %%g %%h %%i
echo !bTime!
echo !bTime!>>%report%
echo.>>%report%
echo.
)
)
)
pause
endlocal
exit /b 0

:: NOTES
:: you could also script network statistics workstation
:: command: net statistics workstation
:: output: Statistics since 2/21/2017 7:49:38 PM
::
:: or use WMIC for /f %%A in ('WMIC OS GET LASTBOOTUPTIME ^| find "."') DO set DTS=%%A

Verify Credentials of AD User

email me

These scripts would be a great addition to any form, where you’re passing AD credentials. These allow you to verify the credentials are correct before continuing.

VBScript

'These values will come from a form
strDomain = "YourDomain"
strUsername = "YourUserName"
strUserPassword = InputBox("","Password")

'Returns True or False
msgbox CheckAccess(strDomain,strUsername,strUserPassword)

Function CheckAccess(strDomain, strUsername, strUserPassword)

	Dim objAD, objADUser, strADPath

	Const ADS_SECURE_AUTHENTICATION = &h0001
	Const ADS_CHASE_REFERRALS_ALWAYS = &H60


	strADPath = "LDAP://" & strDomain & "/OU=Users,DC=" & strDomain

	On Error Resume Next
	set objAD = GetObject("LDAP:")
	set objADUser = objAD.OpenDSObject (strADPath, strUsername, strUserPassword, ADS_SECURE_AUTHENTICATION OR ADS_CHASE_REFERRALS_ALWAYS)
	if Err.Number <> 0 then    
		CheckAccess = False
	else
		CheckAccess = True
	end if
	
	Err.Clear
	On Error Goto 0

	set objAD = Nothing
	set objADUser = Nothing
	set strADPath = Nothing
	strUserPassword = ""
	strUsername = ""
	strDomain = ""        

End Function

PowerShell

$strUserName = "YourUsername"
$strUserPassword = "UserPassword"

CheckAccess $strUserName $strUserPassword 


Function CheckAccess {
   
    if (!($strUserName) -or !($strUserPassword)) {
        Write-Warning 'Please verify your username and password!'
    } else {
        Add-Type -AssemblyName System.DirectoryServices.AccountManagement
        $objAD = New-Object System.DirectoryServices.AccountManagement.PrincipalContext('domain')
        $objAD.ValidateCredentials($strUserName, $strUserPassword)
    }
}

LANDesk Creating Numerous C:\Users Profiles

email me

Here is a weird one for you. We’re upgrading to the latest version of LANDesk, and for some reason, numerous LD profile folders are being generated in C:\users (I’m thinking is has to do with the ALS service/LANDesk account). The folders either start with ALS_SVC or TEMP.%computername%.

Two things you’ll need to do

#1 Remove LD profiles from C:\users

#2 Remove LD profiles from the registry path:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList

* see updates below

* see Steps to Disable Agentless Scanning, to completely disable it

Screenshot

 

Solution

Initially, I wrote scripts in PowerShell and VB that looked at folder size and removed 0 byte sizes, the problem was…while they worked in other folders just fine, they could not read all of the C:\users folders—-no access (certain vb and ps objects just could not access the folders). So, I went low tech with this one. And, guess what? It worked. I wrote this batch and compiled it into an EXE. Once launched, it found the 0 byte size folders and removed them.

@echo off
title LANDesk Cleanup
setlocal enabledelayedexpansion

set DName=
set FSize=0

C:
cd\users

:: return objects in directory
for /f “tokens=*” %%A in (‘dir c:\users /a /b’) do (
set DName=c:\users\%%A
echo Checking !DName!…

:: scan through all folders
:: set total size of folder to cumulative file sizes
for /f “tokens=3-4” %%B in (‘dir “!DName!” /s ^| find /i “file(s)”‘) do (
set FSize=%%B
)
:: if no files were returned, this directory has a size 0
:: if size 0, then remove folder and all subfolders
:: log the action
if !FSize! EQU 0 rd /q /s “!DName!” && echo %Date% !DName! !FSize!>>C:\users\removal_log.txt
echo.
)
endlocal

 

* Update 02/20/2017

So, come to find out, NOT all the LANDesk profile folders were 0 byte. So, I ended up writing a new script to just delete ALS_SVC* and TEMP.* folders

@echo off
title LANDesk Cleanup
setlocal enabledelayedexpansion

c:
cd\users
cls

set DName=
set FSize=
set CName=%computername%
set str1=ALS_SVC
set str2=TEMP.
set found=false

:: GET FOLDER
For /d %%A in (*) Do (
set found=false
set DName=c:\users\%%A

:: UPDATE TIMESTAMP
for /F “TOKENS=*” %%T in (‘Time /t’) do set NowT=%%T

:: FIND FOLDER SIZE
for /f “tokens=3-4” %%S in (‘dir “!DName!” /s ^| find /i “file(s)”‘) do set FSize=%%S

:: DELETE ALS_SVC*
echo %%A | find /i “%str1%”>nul && (

echo DELETE: “!DName!”
rd /q /s “!DName!” && echo DELETED %Date% !NowT! “!DName!” !FSize!>>c:\users\removal_log.txt
set found=true
)

:: DELETE TEMP.*
echo %%A | find /i “%str2%”>nul && (

echo DELETE: “!DName!”
rd /q /s “!DName!” && echo DELETED %Date% !NowT! “!DName!” !FSize!>>c:\users\removal_log.txt
set found=true
)

IF NOT ALS OR TEMP, LOG
if !found! EQU false echo NOT_DELETED %Date% !NowT! “!DName!” !FSize!>>c:\users\removal_log.txt

)

set DName=
set FSize
set CName=
set str1=
set str2=

endlocal
exit /b 0

 

* Update 02/21/2017

Yet another update. It was requested that the amount of folders being deleted, a timestamp of the last run date of the deployment package, and total times the package has run, all be tracked. So, I modified the script above to add counters for the package and for the folders being deleted. These variables are added to the registry, which are then scanned via our desktop management software.

The reg keys that are added

In LANDesk, these are published to clients

The final result, an updated inventory record with tracking info

The modified script – this was compiled

@echo off
title LANDesk Cleanup
setlocal enabledelayedexpansion

c:
cd\users
cls

:: folders to look for
set str1=ALS_SVC
set str2=TEMP.

:
: directory name
set DName=

:: directory size
set FSize=

:: bool: if folder matches logic
set found=false

set fCount=
set rCount1=0
set rCount2=0

:: reg key
set AppName=ProfileCleanup
set RegKey1=”HKLM\SOFTWARE\LANDesk\Tracking\%AppName%” /v “Counter”
set RegKey2=”HKLM\SOFTWARE\LANDesk\Tracking\%AppName%” /v “Last_Run”
set RegKey3=”HKLM\SOFTWARE\LANDesk\Tracking\%AppName%” /v “Folders_Deleted”

:: REMOVE ALL ALS_SVC* FOLDERS
For /d %%A in (*) Do (
set found=false
set DName=c:\users\%%A
for /F “TOKENS=*” %%T in (‘Time /t’) do set NowT=%%T

for /f “tokens=3-4” %%S in (‘dir “!DName!” /s ^| find /i “file(s)”‘) do set FSize=%%S

echo %%A | find /i “%str1%”>nul && (
echo DELETE: “!DName!”
rd /q /s “!DName!” && echo DELETED %Date% !NowT! “!DName!” !FSize!>>c:\users\removal_log.txt
set found=true
set /a fCount+=1
)

echo %%A | find /i “%str2%”>nul && (
echo DELETE: “!DName!”
rd /q /s “!DName!” && echo DELETED %Date% !NowT! “!DName!” !FSize!>>c:\users\removal_log.txt
set found=true
set /a fCount+=1
)

if !found! EQU false echo NOT_DELETED %Date% !NowT! “!DName!” !FSize!>>c:\users\removal_log.txt
)
:: if counter key doesn’t exist, create it
%windir%\sysnative\REG QUERY %RegKey1%
if %ERRORLEVEL% EQU 0 goto :Main
if %ERRORLEVEL% EQU 1 goto :Add
ping -n 4 127.0.0.1>nul

:Add
cls
echo Key not found. Adding Key…
%windir%\sysnative\REG ADD %RegKey1% /d 0 /reg:64 /f
%windir%\sysnative\REG ADD %RegKey3% /d 0 /reg:64 /f
ping -n 4 127.0.0.1>nul

:: retrieve current count and add 1
:: this is how many times the script has run
:Main
cls
echo Retrieving Reg Count…
FOR /f “tokens=1,2,3” %%a In (‘%windir%\sysnative\REG QUERY %RegKey1% /reg:64’) do (
set rCount1=%%c
set /a rCount1+=1 && %windir%\sysnative\REG ADD %RegKey1% /d !rCount1! /reg:64 /f
ping -n 4 127.0.0.1>nul
)

:: this is how many folders have been deleted
cls
echo Retrieving Folder Count…
FOR /f “tokens=1,2,3” %%a In (‘%windir%\sysnative\REG QUERY %RegKey3% /reg:64’) do (
set rCount2=%%c
set /a “rCount2=!rCount2!+!fCount!” && %windir%\sysnative\REG ADD %RegKey3% /d !rCount2! /reg:64 /f
)
:: add timestamp to registry
%windir%\sysnative\REG ADD %RegKey2% /d “%date% %time%” /reg:64 /f

:: clear session
set RegKey1=
set RegKey2=
set RegKey3=
set fCount=
set rCount1=
set rCount2=
set AppName=

set DName=
set FSize
set str1=
set str2=
set NowT=

:: clean up registry keys
cls
echo Removing LANDesk ALS profiles…
for /f “tokens=1,2 delims==” %%s IN (‘WMIC path win32_useraccount where name^=’administrator’ get sid /value ^| find /i “SID”‘) do set SID=%%t
set RootSID=%SID:~0,-5%
set RegPath=HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList

set /a counter=3
:loop1
if %counter% lss 10 (
reg delete “%regPath%\%RootSID%-100%counter%” /f /reg:64
set /a counter+=1
goto :loop1
)

set /a counter=10
:loop2
if %counter% lss 100 (
reg delete “%regPath%\%RootSID%-10%counter%” /f /reg:64
set /a counter+=1
goto :loop2
)

set /a counter=100
:loop3
if %counter% lss 999 (
reg delete “%regPath%\%RootSID%-1%counter%” /f /reg:64
set /a counter+=1
goto :loop3
)

endlocal
exit /b 0

* Note how %windir%\sysnative was used. You’ll use %windir%\system32 if using a 64bit compiler or running script not compiled

 

Notes

As for what’s causing the issue, beyond the ALS account, LANDesk is still trying to figure it out.

Some C# code I was working on to do the task above.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

class LANDeskProfileCleanup
{
    public static void Main(string[] args)
    {
        try
        {
            string dirPath = @"c:\users\";

            List<string> dirs List<string>(Directory.EnumerateDirectories(dirPath));

            foreach (var dir in dirs)
            {
                long length = Directory.GetFiles(dir, "*", SearchOption.AllDirectories).Sum(t =&amp;amp;gt; (new FileInfo(t).Length));
                Console.WriteLine("{0}", dir.Substring(dir.LastIndexOf("\\") + 1));
            }
            //Console.WriteLine("{0} Folders found.", dirs.Count);
        }
        catch (UnauthorizedAccessException UAEx)
        {
            Console.WriteLine(UAEx.Message);
        }
        catch (PathTooLongException PathEx)
        {
            Console.WriteLine(PathEx.Message);
        }
        Console.ReadLine();
    }


    public static long DirSize(DirectoryInfo dir)
    {
        return dir.GetFiles().Sum(fi => fi.Length) +
               dir.GetDirectories().Sum(di => DirSize(di));
    }
}

Tableau Reader App GUIDs

email me

Perhaps this may be of some use to someone out there. These are some Tableau Reader GUIDs. I pulled them right from the MSIs.

10.1.1
{20BC57B6-94CA-476C-A74D-6E7B59E98EE2}

10.1.3
{622F9674-0444-4521-BC0E-FD95E6FCE021}

10.1.4
{C50413C2-7230-4068-98E3-C0D616D20CCF}

10.1.5
{26AA4283-AB5A-4E4B-A4A5-3A5BB018251D}

10.2.113
{745E628E-24B3-4152-B0EA-DFFFDCCE3247}

12.2.907
{5A1533E5-FF05-4E5C-8B4E-DDAA46A38487}

10.3.551
{86336B9B-0A65-4C47-8727-7DAE556379E7}

Older ones
{601C7D83-2B27-424A-82A4-A7F2768508F4}
{CAFF89F1-3C19-4F86-84A9-9410BC014EB4}
{3D054388-8F96-4BDD-BC9D-9889FC7C2892}
{7A03EDE8-74DE-4C02-94BF-333C5B49C474}

Juniper Pulse Disconnecting Users – Shared Install

email me

Problem

Multiple users report intermittent disconnects with the Pulse Secure Desktop client. There is no specific interval when this issue will occur as it will depend if the multiple user are attempting to login to the computer with the same machine guid.


Cause

This issue will occur when Pulse Secure Desktop client is preinstalled on a base image which is used to deploy to multiple machines. If this is true, the local machine ID stored in the connection store file may be the same on multiple machine.

When a Pulse Secure Desktop client connects to the PCS device, some session data is sent including the local machine identifier in the connection store file. The Pulse Connect Secure device identifies each user sessions by the local machine identifier and expects this value to be unique. If multiple connections are sending the same machine identifier, the PCS device will terminate the oldest session for security reasons.

Screenshot of Connstore.dat and Registry (click to zoom)


Solution

If you already have users that have the Pulse client installed, I recommend doing two things.

#1 Delete this reg key
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Juniper Networks\Device Id

#2 Use Orca to modify the Pulse.msi and change SHAREDINSTALL from 0 to 1. Reinstall this modified client using a simple script or your desktop management software.

Orca – Property Table – Property SHAREDINSTALL

A reboot will most likely be required to reload all the Juniper services.

 

Notes

The Junos Pulse connection store file is located
C:\ProgramData\Pulse Secure\ConnectionStore\connstore.dat

The reg key is located
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Juniper Networks\Device Id]

Also see: Deploying Pulse Client

 

Bookshelf 7.1.2

email me

The Bookshelf Application


When trying to package…


Locate the MSI in the %TEMP%, once you launch the EXE

setup.msi /qn /norestart

Or, just use the EXE

setup.exe /v”/qn”

You will run into a snag with the application eula; not the setup eula, but the actual application eula. The settings are stored in the user profile.

Even if you run the setup silently, this happens upon app launch:

App Eula (you don’t want to see this)

This setting, along with several others, are stored in the BookShelf Prefs file.

BookShelf Prefs

I captured the Bookmark Prefs from a reference machine and added it to a compiled package. I used this script I created a while back to actually copy the file to each user profile:

on error resume next

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

Const HKEY_LOCAL_MACHINE = &H80000002
Const OverwriteExisting = TRUE
Const POPUP_TITLE = "User To SID Conversion"
'SETS CURRENT DIRECTORY TO VARIABLE
strCurrentDirectory = objShell.CurrentDirectory
strComputer = "."

Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set objRegistry=GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv")
strKeyPath = "SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\ProfileList"
objRegistry.EnumKey HKEY_LOCAL_MACHINE, strKeyPath, arrSubkeys
For Each objSubkey In arrSubkeys
on error resume next
strValueName = "ProfileImagePath"
strSubPath = strKeyPath & "\" & objSubkey
objRegistry.GetExpandedStringValue HKEY_LOCAL_MACHINE,strSubPath,strValueName,strValue

Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set objAccount = objWMIService.Get("Win32_SID.SID='" & objSubkey & "'")
strUser = objAccount.AccountName
'strDomain = objAccount.ReferencedDomainName'returns referenced domain

'DISPLAY PROFILE NAME & SID
objSubkey = trim(objSubkey)'trims whitespace
strUser = trim(strUser)'trims whitespace
'msgbox "objSubkey: " & objSubkey'returns SID
'msgbox strUser'returns username

'LOGIC TO DETERMINE IF REGISTRY ACCOUNT IS TO BE LOADED
if strUser = "SYSTEM" then strUser=""
if strUser = "LOCAL SERVICE" then strUser=""
if strUser = "NETWORK SERVICE" then strUser=""
'if strUser = "ADMINISTRATOR" then strUser=""
if strUser <> "" then
on error resume next
Wscript.Sleep 1000

target = "C:\Users\" & strUser & "\Documents\My Books\VitalSource Bookshelf\User Data\"

'Copy file
If (objFSO.FileExists(strCurrentDirectory & "\Bookshelf Prefs")) Then
objShell.Run "%comspec% /c copy /y " & chr(34) & strCurrentDirectory & "\Bookshelf Prefs" & chr(34) & " " & chr(34) & target & chr(34),0,true
end if

end if

Next

VBScript – Determine Domain and Do Something

email me

This can be used to determine a domain, in a multi-domain enterprise. If a specific domain, do something.

Option Explicit

Dim objWMISvc, ColItems, objItem, strComputerDomain

Set objWMISvc = GetObject( "winmgmts:\\.\root\cimv2" )
Set colItems = objWMISvc.ExecQuery( "Select * from Win32_ComputerSystem", ,48 )
For Each objItem in colItems
	strComputerDomain = objItem.Domain
		If objItem.PartOfDomain Then
			'DOMAIN 1
			if strComputerDomain = "DOMAIN1.com" then
				'do something here
				msgbox "Domain 1"
			'DOMAIN 2
			elseif strComputerDomain = "DOMAIN2.com" then
				'do something here
				msgbox "Domain 2"
			'EVERYONE ELSE
			else
				'do something here
				msgbox "Everyone Else"
			end if
		end if
next

'CLEAR SESSION
Set objWMISvc = Nothing
Set colItems = Nothing
objItem = ""
strComputerDomain = ""