Search This Blog

Monday, September 21, 2020

OneDrive Status and Central Monitoring

UPDATE 09/21/2020:
I have added language detection, which will cause the script to exit if there is any language other than English (en-US).
Also added detection of parentheses, as in "OneDrive - NYIT Support(1)" that was breaking the logging.



---------------------------

Good day,

after writing and using the previous script, i was not happy with the screen blanking, and the omni-present "OnDemandOrUnknown" status. I have decided to rewrite from scratch, not using any dll files.

Compiled Download Link

File hash: F79A6E032A652AA86A62127A090E6C3B14604BCD97944EB112BA0D8D77A618FC

This script is the equivalent of a user moving the mouse over the status bar and reading the status tooltip that comes up, and writes the output status to a text file:


.
The written text file (stored in ini format, with a .Error or .Healthy extensions) will contain 
  • The exact status from the tooltip (minus the "OneDrive - Organization Name" portion)
  • Any possible encountered errors with the variable names that caught them
  • Count of errors/potential issues. 
File will be named with a "UserName - ComputerName.Error" or a "UserName - ComputerName.Healthy" naming convention.

Script will also check for potential issue keywords that may be a sign that there is an underlying issue and if counted a preset amount of times, will change status to error from healthy. 
The script relies on an ini file that should be stored in the same folder as the script.

Credit, where credit is due:
The icon tooltip catching portion of script was partially based on 
https://www.autoitscript.com/forum/topic/138046-how-to-determine-if-computer-is-lockedunlocked/


Setup:
The following files are required:
OneDriveStatus.ini
OneDriveStatus.exe - compiled version of the script. Contact me for the file, or compile it yourself via AutoITScript/Scite Editor. Copy the OneDriveStatus.au3 file box contents below.

A share accessible with read access by users. Example \\SRV1\OneDriveStatus\

A sub folder of the share called Logs with change access for users. For example \\SRV1\OneDriveStatus\Logs\

Both can be stored separately, as long as a user account can access the exe and ini file to copy to the local machine, and a writable Logs folder, so that logs can be stored and updated. The Logs folder should also be accessible to a server that will run a notification script on a schedule.

The ini file should be named OneDriveStatus.ini and should have the following text:
[Settings]
;set LogPath without a backslash "\"
;FakeStatus is used for testing, bypassing actual icon check. Always leave blank.
;OneDriveOrgName is the first line of the OneDrive icon Tooltip.
OneDriveOrgName="OneDrive - NYIT Support"
LogPath="\\SRV1\OneDriveStatus\Logs"
PotentialAttempts=6
FakeStatus=

[Healthy_List]
; enter healthy status here
Healthy0="Up to date"
Healthy1="Online"
Healthy2=
Healthy3=
Healthy4=
Healthy5=
Healthy6=
Healthy7=
Healthy8=
Healthy9=
Healthy10=
Healthy11=
Healthy12=
Healthy13=
Healthy14=
Healthy15=
Healthy16=
Healthy17=
Healthy18=
Healthy19=

[Potential_List]
PotentialIssue0="Looking for changes"
PotentialIssue1="Signing In"
PotentialIssue2="Downloading"
PotentialIssue3="Processing"
PotentialIssue4=
PotentialIssue5=
PotentialIssue6=
PotentialIssue7=
PotentialIssue8=
PotentialIssue9=
PotentialIssue10=
PotentialIssue11=
PotentialIssue12=
PotentialIssue13=
PotentialIssue14=
PotentialIssue15=
PotentialIssue16=
PotentialIssue17=
PotentialIssue18=
PotentialIssue19=

OneDriveOrgName should be set to "OneDrive - your organization" or however your top line of the tooltip is written. For example:
OneDriveOrgName="OneDrive - NYIT Support"

LogPath should be set to "\\server\share\logs". For example:
LogPath="\\SRV1\OneDriveStatus\Logs"
PotentialAttempts should be set to a desired number, I set it to 6, as I run a scheduled task every 10 minutes, 10x6=60, so if a PotentialIssue is encountered and has not changed on the 6th try (1 hour), status should be changed from .Healthy to .Error.
An example of a potential issue is "Signing In" status, if it shows up for a short time while the script is executing, the status is likely healthy, however if it has stayed that way for over an hour, there is an issue that should be addressed.

FakeStatus should always be empty. It was created as a way to bypass the actual status check for troubleshooting, and force a keyword against the potential and healthy keyword list, or to test various functions of the script without actually encountering a real problem. This is only a toy.

Healthy0..19 should be set to desired status keyword that is always accepted as Healthy. For example:
Healthy0="Up to date"
Healthy18="beautiful day today"
The INI file above has been pre-configured with what i have observed thus far

PotentialIssue0..19 should be set to keywords that are usually a healthy indicator, unless they have not changed in awhile. For example:
PotentialIssue0="Looking for changes"
PotentialIssue1="Signing In"
PotentialIssue18="Downloading"
The INI file above has been pre-configured with what i have observed thus far

The OneDriveStatus.au3 file has the following code (compile it as an exe or run it as "autoit.exe OneDriveStatus.au3")

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Outfile_x64=c:\software\OneDriveStatus\OneDriveStatus.exe
#AutoIt3Wrapper_Compression=0
#AutoIt3Wrapper_Res_Fileversion=1.0.0.18
#AutoIt3Wrapper_Res_Fileversion_AutoIncrement=y
#AutoIt3Wrapper_Res_ProductName=OneDriveStatus
#AutoIt3Wrapper_Res_ProductVersion=1
#AutoIt3Wrapper_Run_Tidy=y
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <GuiToolBar.au3>
#include <array.au3>
#include <APIConstants.au3>
#include <WinAPIEx.au3>

#cs
	OneDriveStatus
	Alex Belenkiy © 2020
	ab@nyitsupport.com
	https://www.nyitsupport.com
	Created: 05/18/2020
	Last Update: 09/21/2020

	This script detects the status of the tooltip of the OneDrive icon in the task tray and writes the output status to a text file.
	The file will contain the exact status, and will be named with a "Username - Computername.Error(Healthy)" naming convention.
	Script will also check for potential issue keywords that may be a sign that there is an underlying issue and if counted a preset amount of times, will change status to error from healthy.
	Log path and healthy status keywords are defined through an ini file that must be present in the script folder and named to match the script.

	The icon tooltip catching portion of script was partially based on http://www.autoitscript.com/forum/topic/157933-hinttray-tip-how-to-get-text/?p=1145366

	Default INI file contents:
	;-----------------------------------------------------------------------------------------
	[Settings]
	;set LogPath without a backslash "\"
	;FakeStatus is used for testing, bypassing actual icon check. Always leave blank.
	;OneDriveOrgName is the first line of the OneDrive icon Tooltip.
	OneDriveOrgName="OneDrive - Organization Name"
	LogPath="\\servername\scripts\OneDriveStatus\Logs"
	PotentialAttempts=6
	FakeStatus=

	[Healthy_List]
	; enter healthy status here
	Healthy0="Up to date"
	Healthy1=
	Healthy2=
	Healthy3=
	Healthy4=
	Healthy5=
	Healthy6=
	Healthy7=
	Healthy8=
	Healthy9=
	Healthy10=
	Healthy11=
	Healthy12=
	Healthy13=
	Healthy14=
	Healthy15=
	Healthy16=
	Healthy17=
	Healthy18=
	Healthy19=

	[Potential_List]
	PotentialIssue0="Looking for changes"
	PotentialIssue1="Signing In"
	PotentialIssue2="Online"
	PotentialIssue3="Processing"
	PotentialIssue4="Downloading"
	PotentialIssue5=
	PotentialIssue6=
	PotentialIssue7=
	PotentialIssue8=
	PotentialIssue9=
	PotentialIssue10=
	PotentialIssue11=
	PotentialIssue12=
	PotentialIssue13=
	PotentialIssue14=
	PotentialIssue15=
	PotentialIssue16=
	PotentialIssue17=
	PotentialIssue18=
	PotentialIssue19=
	;-----------------------------------------------------------------------------------------


	Update 05/19-20/2020:
	Added fake status option for testing.
	Changed reporting as follows:
	If no keyword is matched, a .Error file is created
	If a healthy keyword is matched, the .Error file is deleted and a .Health file is created
	If a potential issue is matched
	.Error file is replaced with a .Healthy file. Status and PotentialIssueAttempts are written to the file.
	If the count reached the PotentialAttempts count, .Healthy is renamed to .Error. Once renamed to .Error, new iterations of the same status will just increase the count of attempts logged.

	Update 05/21/2020:
	Added count for error status
	Added locked status from https://www.autoitscript.com/forum/topic/138046-how-to-determine-if-computer-is-lockedunlocked/

	Update 05/26/2020:
	Added OneDriveOrgName variable to the INI file.
	Added detection of exe or .au3 runtime (prod vs dev)
	Fixed minor bug with error file missing a "." in a step

	Update 09/21/2020
	Added English language detection. Other languages result in odd issues.
	Added organization name instance detection "Company Name(1)"


#ce

; check for en-US language
If @OSLang <> 0409 Then Exit
If RegRead("HKCU\Keyboard Layout\Preload", 1) <> 0409 Then Exit

Opt("TrayIconHide", 1)

If _IsLocked() Then Exit

Global $mText
Global $iniLogPath

Global $iniCheckAttempts
Global $iniFakeStatus
Dim $errorlist[5]
Dim $ini_Healthy_List[20]
Dim $ini_Potential_List[20]
Dim $HealthMatch = 0 ; 0=error | 1=healthy | 2=potential issue
Dim $iniOneDriveOrgName

If StringRight(@ScriptName, 4) = ".exe" Then
	$iniName = StringReplace(@ScriptFullPath, ".exe", ".ini")
Else
	$iniName = StringReplace(@ScriptFullPath, ".au3", ".ini")
EndIf

If FileExists($iniName) Then
	INI_Load($iniName)
Else
	Exit
EndIf

If ProcessExists("OneDrive.exe") Then
	If $iniFakeStatus <> "" Then
		$mText = $iniFakeStatus
	Else
		$iniOneDriveOrgName = String($iniOneDriveOrgName)
		$mText = Get_SysTray_Icon_Text($iniOneDriveOrgName)

		;clean up Organization Name(1) here
		If StringInStr($mText, $iniOneDriveOrgName & "(") Then
			For $a = 1 To 20
				If StringInStr($mText, $iniOneDriveOrgName & "(" & $a & ")") Then $mText = StringReplace($mText, $iniOneDriveOrgName & "(" & $a & ")" & @LF, "")
			Next
		Else
			$mText = StringReplace($mText, $iniOneDriveOrgName & @LF, "")
		EndIf
	EndIf

	For $j = 0 To UBound($ini_Healthy_List) - 1
		If String(StringLeft($mText, Number(StringLen($ini_Healthy_List[$j])))) == String($ini_Healthy_List[$j]) Then $HealthMatch = 1
	Next
	If $HealthMatch = 0 Then
		For $k = 0 To UBound($ini_Potential_List) - 1
			If String(StringLeft($mText, Number(StringLen($ini_Potential_List[$k])))) == String($ini_Potential_List[$k]) Then $HealthMatch = 2
		Next
	EndIf
	StatusLogging($mText, _ArrayToString($errorlist), $HealthMatch)
	Exit
Else
	StatusLogging("OneDrive.exe Not Running", "", 0)
	Exit
EndIf

Func INI_Load($iniFile)
	$iniLogPath = IniRead($iniFile, "Settings", "LogPath", "")
	If $iniLogPath = "" Then Exit
	If Not FileExists($iniLogPath) Then Exit
	$iniCheckAttempts = IniRead($iniFile, "Settings", "PotentialAttempts", 6)
	$iniFakeStatus = IniRead($iniFile, "Settings", "FakeStatus", "")
	$iniOneDriveOrgName = IniRead($iniFile, "Settings", "OneDriveOrgName", "OneDrive")
	For $i = 0 To 19
		$iniHealthLine = IniRead($iniFile, "Healthy_List", "Healthy" & $i, "")
		If $iniHealthLine <> "" Then _ArrayPush($ini_Healthy_List, $iniHealthLine)
		$iniPotentialLine = IniRead($iniFile, "Potential_List", "PotentialIssue" & $i, "")
		If $iniPotentialLine <> "" Then _ArrayPush($ini_Potential_List, $iniPotentialLine)
	Next
	For $i = UBound($ini_Healthy_List) - 1 To 0 Step -1
		If StringStripWS($ini_Healthy_List[$i], 8) = "" Then _ArrayDelete($ini_Healthy_List, $i)
	Next
	For $i = UBound($ini_Potential_List) - 1 To 0 Step -1
		If StringStripWS($ini_Potential_List[$i], 8) = "" Then _ArrayDelete($ini_Potential_List, $i)
	Next

EndFunc   ;==>INI_Load

Func Get_SysTray_Icon_Text($mScriptName) ; http://www.autoitscript.com/forum/topic/157933-hinttray-tip-how-to-get-text/?p=1145366

	; Systray handle for "User Promoted Notification Area"
	Local $mSysTray_Handle = ControlGetHandle('[Class:Shell_TrayWnd]', '', '[Class:ToolbarWindow32;Instance:3]')
	If Not @error Then
	Else
		_ArrayPush($errorlist, "$mSysTray_Handle - System tray item not found: " & $mSysTray_Handle)
		;Exit
	EndIf
	; Systray handle for "Overflow Notification Area" (hidden up arrow icons)
	Local $mSysTray_Handle_Hidden = ControlGetHandle('[Class:NotifyIconOverflowWindow]', '', '[Class:ToolbarWindow32;Instance:1]')
	If Not @error Then
	Else
		_ArrayPush($errorlist, "$mSysTray_Handle_Hidden - System tray overflow notification icon not found: " & $mSysTray_Handle_Hidden)
		;Exit
	EndIf
	; Systray item count
	Local $mSysTray_ButCount = _GUICtrlToolbar_ButtonCount($mSysTray_Handle)
	If $mSysTray_ButCount = 0 Then
		_ArrayPush($errorlist, "$mSysTray_ButCount - No items found in system tray: " & $mSysTray_Handle)
		;Exit
	EndIf

	Local $mSysTray_ButtonText = ""
	; Look for wanted tooltip
	For $mSysTray_ButtonNumber = 0 To $mSysTray_ButCount - 1
		$mSysTray_ButtonText = _GUICtrlToolbar_GetButtonText($mSysTray_Handle, $mSysTray_ButtonNumber)
		If StringInStr($mSysTray_ButtonText, $mScriptName) Then Return $mSysTray_ButtonText
	Next
	Local $mSysTray_ButCount = _GUICtrlToolbar_ButtonCount($mSysTray_Handle_Hidden)
	If $mSysTray_ButCount = 0 Then
		_ArrayPush($errorlist, "$mSysTray_ButCount_hidden - No items found in overflow system tray: " & $mSysTray_Handle)
		;Exit
	EndIf
	Local $mSysTray_ButtonText = ""

	; Look for wanted tooltip
	For $mSysTray_ButtonNumber = 0 To $mSysTray_ButCount - 1
		$mSysTray_ButtonText = _GUICtrlToolbar_GetButtonText($mSysTray_Handle_Hidden, $mSysTray_ButtonNumber)
		If StringInStr($mSysTray_ButtonText, $mScriptName) Then Return $mSysTray_ButtonText
	Next
	;Return ""
EndFunc   ;==>Get_SysTray_Icon_Text

Func StatusLogging($ODstatus, $errorarray, $status)
	$mPath = $iniLogPath & "\" & @UserName & " - " & @ComputerName

	Select
		Case $status = 0 ;status 0 = error
			If FileExists($mPath & ".Healthy") Then FileDelete($mPath & ".Healthy")
			If FileExists($mPath & ".Error") Then ;.Error exists
				If IniRead($mPath & ".Error", "Status", "StatusText", "") = $ODstatus Then ;same status
					;IniWrite($mPath & ".Error", "Status", "StatusText", $ODstatus)
					IniWrite($mPath & ".Error", "Status", "ErrorArray", $errorarray)
					IniWrite($mPath & ".Error", "Status", "PotentialIssueAttempts", Number(IniRead($mPath & ".Error", "Status", "PotentialIssueAttempts", 0) + 1))
				Else ;different status
					IniWrite($mPath & ".Error", "Status", "StatusText", $ODstatus)
					IniWrite($mPath & ".Error", "Status", "ErrorArray", $errorarray)
					IniWrite($mPath & ".Error", "Status", "PotentialIssueAttempts", 1)
				EndIf
			Else ;.Error doesn't exist
				IniWrite($mPath & ".Error", "Status", "StatusText", $ODstatus)
				IniWrite($mPath & ".Error", "Status", "ErrorArray", $errorarray)
				IniWrite($mPath & ".Error", "Status", "PotentialIssueAttempts", 1)
			EndIf

		Case $status = 1 ;status 1 = healthy
			If FileExists($mPath & ".Error") Then FileDelete($mPath & ".Error")
			IniWrite($mPath & ".Healthy", "Status", "StatusText", $ODstatus)
			IniWrite($mPath & ".Healthy", "Status", "PotentialIssueAttempts", 1)
			IniWrite($mPath & ".Healthy", "Status", "ErrorArray", "")

		Case $status = 2 ;status 2 = potential issue
			If FileExists($mPath & ".Healthy") Then
				If IniRead($mPath & ".Healthy", "Status", "StatusText", "") = $ODstatus Then ;matched status
					IniWrite($mPath & ".Healthy", "Status", "PotentialIssueAttempts", Number(IniRead($mPath & ".Healthy", "Status", "PotentialIssueAttempts", 0) + 1))
					If IniRead($mPath & ".Healthy", "Status", "PotentialIssueAttempts", 0) = $iniCheckAttempts Then FileMove($mPath & ".Healthy", $mPath & ".Error", 9)

				Else ;different status
					IniWrite($mPath & ".Healthy", "Status", "StatusText", $ODstatus)
					IniWrite($mPath & ".Healthy", "Status", "PotentialIssueAttempts", 1)
					IniWrite($mPath & ".Healthy", "Status", "ErrorArray", "")
				EndIf
			Else ;.Healthy doesnt exist
				If FileExists($mPath & ".Error") Then ; check if .Error exists
					If IniRead($mPath & ".Error", "Status", "StatusText", "") = $ODstatus Then ;same status
						IniWrite($mPath & ".Error", "Status", "PotentialIssueAttempts", Number(IniRead($mPath & ".Error", "Status", "PotentialIssueAttempts", 0) + 1))
						IniWrite($mPath & ".Error", "Status", "ErrorArray", "")
					Else ;different status
						FileMove($mPath & ".Error", $mPath & ".Healthy", 9)
						IniWrite($mPath & ".Healthy", "Status", "StatusText", $ODstatus)
						IniWrite($mPath & ".Healthy", "Status", "PotentialIssueAttempts", 1)
						IniWrite($mPath & ".Healthy", "Status", "ErrorArray", "")

					EndIf
				Else ;.Error doesn't exist
					IniWrite($mPath & ".Healthy", "Status", "PotentialIssueAttempts", 1)
					IniWrite($mPath & ".Healthy", "Status", "StatusText", $ODstatus)
					IniWrite($mPath & ".Healthy", "Status", "ErrorArray", "")
				EndIf
			EndIf
	EndSelect
EndFunc   ;==>StatusLogging

Func _IsLocked()
	Local $fIsLocked = False
	Local Const $hDesktop = _WinAPI_OpenDesktop('Default', $DESKTOP_SWITCHDESKTOP)
	If @error = 0 Then
		$fIsLocked = Not _WinAPI_SwitchDesktop($hDesktop)
		_WinAPI_CloseDesktop($hDesktop)
	EndIf
	Return $fIsLocked
EndFunc   ;==>_IsLocked

Compile and place the exe and ini file into \\SRV1\OneDriveStatus

Create a OneDriveStatus GPO with the following settings:
Copy
\\SRV1\OneDriveStatus\OneDriveStatus.exe to c:\software\OneDriveStatus\OneDriveStatus.exe
\\SRV1\OneDriveStatus\OneDriveStatus.ini to c:\software\OneDriveStatus\OneDriveStatus.ini


Set each of the files with the following item level targeting settings under the Common tab:

Adjust as necessary in your environment. This was a quick bypass for not creating anything on servers.


Create a "Scheduled Task (At least Windows 7)" scheduled task in the GPO as follows:












In Group Policy Management Console (gpmc.msc) click on "Group Policy Objects\OneDriveStatus" and hit the "Delegation" tab. Click on "Domain Admins (ACME\DomainAdmins)" and hit "Deny on "Apply Group Policy". Repeat the same for Enterprise Admins and any other related groups that should be excluded.


The above steps can be adjusted for running the script straight from a network share instead of a local folder. I am not a fan of pulling exe/scripts across the lan/wan at 9am and every 10 minutes thereafter, but to each their own.

At this point we are gathering status files in the \\SRV1\OneDriveStatus\Logs folder
Now we move onto creating an email notification.
This part is borrowed from my last post, but repeated here.

Create a OneDriveStatusNotificaiton.ps1 file in the \\SRV1\OneDriveStatus\ folder with the following text:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# OneDriveStatusNotification.ps1
# Alex Belenkiy © 2020
# ab@nyitsupport.com
# https://www.nyitsupport.com

$ErrorActionPreference = "SilentlyContinue"

$ErrorFilesExist = test-path -path "c:\shares\OneDriveStatus\Logs\*.error"
if ($ErrorFilesExist)
{
	$SourcePath = "c:\shares\OneDriveStatus\Logs\"
	$newBody = ""
	$dir = Get-ChildItem -path $SourcePath -name -filter *.error -File

	$recipients = "CoolestAdmin@nyitsupport.com" ,"CoolAdmin@nyitsupport.com" # Change these
	
	$subject = "OneDriveStatus Notification: " + $dir.count + " Errors Detected"
		
	$body = ($dir|out-string).replace(".Error","") + "`r`n\\SRV1\scripts\OneDriveStatus\Logs" 
	
	foreach($i in $dir)
	{
		$a = $SourcePath + $i
		$nb = get-content $a -raw
		$newBody = $newBody + "`r`n" + $i.replace(".Error","") + "`r`n" + $nb + "`r`n"
	}		
	
	$newBody = $newBody + "`r`n\\SRV1\OneDriveStatus\Logs" 
	Send-MailMessage -SmtpServer 10.0.0.99 -From OneDriveStatusNotification@nyitsupport.com -To $recipients -Subject $subject -Body $NewBody # Change these
	
}


Dont forget to change the smtp server ip, log path and the destination addresses. Allow relaying on the email server for the source server where the notification script will execute from.

Create a scheduled task on the server that will host the log files (or send email) as follows:



Set a desired notification time:


Set the action to "Start a program" as follows:
Program/script: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Add arguments based on script location: -executionpolicy bypass -nologo -file c:\shares\OneDriveStatus\OneDriveStatusNotification.ps1



Enjoy the script(s). I hope they have helped you out with your transition to OneDrive/SharePoint/Office365. Hopefully this is a good starting point or a solution.
Let me know how it works out.


Notes:
The script has been tested on Windows 10. If you have an older operating system, you may need to play with the [Class:ToolbarWindow32;Instance:3] and [Class:ToolbarWindow32;Instance:1] sections in the script.
If Microsoft changes Windows 10 task tray "User Promoted Notification Area" or "Overflow Notification Area" locations, the script will not be able to retrieve information until the script is upated to reflect the changes.

If Microsoft makes changes to OneDrive tooltip status text, the script ini will need to be updated to reflect changes. If the OneDrive icon completely changes it's displayed information, we will need to update and recompile the scipt to reflect the changes.
The script only provides the information available in the tooltip, if it is not correct, the collected data will reflect that.







4 comments:

Unknown said...

The script works fine but some come back with the following error:
ErrorArray=||||$mSysTray_ButCount - No items found in system tray: 0x00010166


Do you know how to resolve this?

NYITSUPPORT said...

Hi, glad to see it works.

I have seen this a few times before, each time turned out to be a computer that has been running for a very long time with a possible Explorer.exe restart at some point.

A reboot and logging in of the user usually fixed it. (I know, reboot, the most useless and yet useful IT solution to all problems)

Also have seen some issues where a machine was in sleep mode for a prolonged period and then came back on without the user logging in (users work remotely and rdp in). In all cases the reboot/user logon helped.

I have also seen some issues with improper name of the organization "Company Name" vs "Company Name(1)" as an example, where logs kept repeating and filling up.

Recreating the OneDrive sync setup to remove the duplicate name should correct it.

NYITSUPPORT said...

The "Company Name" vs "Company Name(1)" issue, i am actually currently working on to resolve. Will post an updated script in a week or two. Very busy schedule.

NYITSUPPORT said...

The "Company Name" vs "Company Name(1)" issue has been fixed!