Microsoft VBScript runtime error '800a000d' Type mismatch: 'LastID' - vbscript

I do a function to assign an ID. But when I click button, this error comes out.
Microsoft VBScript runtime error '800a000d' Type mismatch: 'LastID'
Public function AssignSanctionID(DeptID,SectID,SanctionType)
REM obtain Transaction ID
dim CmdX
dim SQLX
dim RsX
dim Prefix
dim LastID
dim CurrID
dim NewCurrID
'- Set Connection
HariNi=now()
Tahun=year(HariNi)
Bulan=month(HariNi)
if len(bulan)=1 then
Bulan= "0" & Bulan
end if
If Cint(Tahun) < 2016 then
Pref1= DeptID & "/" & SectID & "/"
Prefix=DeptID & "/" & SectID & "/" & Tahun & "/" & Bulan & "/"
else
Pref1= DeptID & "/%/" & SectID
Prefix=DeptID & "/" & Tahun & "/" & Bulan & "/"
end if
set CmdX = server.CreateObject("ADODB.Command")
Set RSX = Server.CreateObject("ADODB.Recordset")
SQLX = " SELECT * FROM Sanction " _
& " WHERE SanctionID like '%" & Pref1 & "%' " _
& " ORDER BY ID DESC"
CmdX.ActiveConnection = objconn
CmdX.CommandText = SQLX
RsX.Open CmdX,,0,1
if not(RsX.BOF and RsX.EOF) then
If Cint(Tahun) < 2016 then
LastID = right(RsX("ID"),4)
else
LastID = mid(RsX("ID"),13,4)
end if
else
if Bulan="04" then
LastID=0
end if
end if
RsX.Close
set RsX = nothing
'Set ID
If LastID<>"" then
'CurrID = left(4)
CurrID=int(LastID)+1
end if
if len(currid)>0 then
select case len(currid)
case 1
newcurrid = "000" & currid
case 2
newcurrid = "00" & currid
case 3
newcurrid = "0" & currid
case 4
newcurrid = currid
end select
else
NewCurrID="0001"
end if
If Cint(Tahun) < 2016 then
NewCurrID=Prefix & NewCurrID
else
NewCurrID=Prefix & NewCurrID & "/" & SectID
end if
AssignSanctionID = NewCurrID
end function

Hard to help if I don't see the data.
From quick view of the code the issue is here:
CurrID=int(LastID)+1
You are trying to cast LastID but are you sure that it is convertible? Could list all possible values?

Short answer: CInt only works with Numerical values. If you have letters in your value, then Cint wont work.
Bit longer answer:
Having read the Blog that we should be more welcoming (https://stackoverflow.blog/2018/04/26/stack-overflow-isnt-very-welcoming-its-time-for-that-to-change/?cb=1), here is a very general answer, but that might lead you on the correct way to fix it yourself.
Type Mismatch is an error you can get when using a variable the wrong way. For example if you try to do numerical functions with Strings (which means the variable contains letters a-z etc) you will get "Type Mismatch" as you cant add or subtract text in a mathematical way... On the other hand you cant add Integer variables (the variable only contains a number AND isnt contained within "quote marks").
So below is a few ways to assigna a variable and what type it becomes:
LastID=1 'This makes LastID an INT (number)
LastID="1" 'This makes LastID a String but a CInt(LastID) can turn it into an INT because it ONLY contains numbers.
LastID="IT" 'This makes LastID a String that CANT in any way be cast to INT as it contains letters.
LastID=IT 'This row will either create an error except if you already have a variable called IT, then LastID will get the same value as the IT variable...
This should hopefully get you on your way to fix this issue...

Related

Invalid Parameter error when setting a registry multiStringValue using vbscript

This is in reference to an existing question I previously asked but same conditions are not working when doing another sub. All variables below are defined correct and as strings. I am getting error when setting values on this line:
objReg.setMultiStringValue HKCU,IE_Main,mStrSecStartPages,allURLs
The code is below;
return = objReg.getMultiStringValue (HKCU,IE_Main,mStrSecStartPages,multiStringValues)
'If values found in Secondary Start Pages
If return=0 Then
ReDim allURLs(0)
'Read all values and only store non intranet values to array
For Each itemname In multiStringValues
If itemname <> strFunctionIntranet1 And itemname <> strFunctionIntranet2 And itemname <> strFunctionIntranet3 And itemname <> strFunctionIntranet4 Then
ReDim Preserve allURLs(UBound(allURLs)+1)
allURLs(UBound(allURLs)) = itemname
End If
Next
'Remove current key holding existing values
objReg.DeleteValue HKCU,IE_Main,mStrSecStartPages
'Set new values based on values read and user's intranet
if UBound(allURLs)>=0 Then
wscript.echo "in setting"
objReg.setMultiStringValue HKCU,IE_Main,mStrSecStartPages,allURLs
End If
wscript.echo "out setting"
End If
Problem is even if there isn't any values in the REG_MULTI_SZ value you will still get an empty Array returned, which means when you then loop through the array and dynamically expand it using
ReDim Preserve allURLs(UBound(allURLs)+1)
You will always have a blank element in the first position in the array which when passed to
objReg.setMultiStringValue HKCU,IE_Main,mStrSecStartPages,allURLs
if it isn't the only element you will get
SWbemObjectEx: Invalid parameter
Here is some testing I did to prove this
Option Explicit
Const HKEY_LOCAL_MACHINE = &H80000002
Dim oReg
Dim strKeyPath, strValueName, arrStringValues
Dim strComputer: strComputer = "."
Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
strComputer & "\root\default:StdRegProv")
strKeyPath = "SOFTWARE\Microsoft\Internet Explorer\Main"
strValueName = "Default_Secondary_Page_URL"
Dim rtn
rtn = oReg.GetMultiStringValue(HKEY_LOCAL_MACHINE, strKeyPath, strValueName, arrStringValues)
Dim i
If rtn = 0 Then
If IsArray(arrStringValues) Then
For i = 0 To UBound(arrStringValues)
WScript.Echo "arrStringValues(" & i & ") = " & arrStringValues(i)
Next
Else
WScript.Echo "Not Array"
End If
Else
WScript.Echo "Failed to GetMultiStringValue - Return (" & rtn & ")"
End If
rtn = oReg.SetMultiStringValue(HKEY_LOCAL_MACHINE,strKeyPath,strValueName,arrStringValues)
WScript.Echo "SetMultiStringValue - Return (" & rtn & ")"
Output:
arrStringValues(0) =
SetMultiStringValue - Return (0)
Adding the following line to create two blank elements under the IsArray() check
ReDim Preserve arrStringValues(UBound(arrStringValues) + 1)
Output:
arrStringValues(0) =
arrStringValues(1) =
test36.vbs(31, 1) SWbemObjectEx: Invalid parameter
So SetMultiSringValue() will accept an Array that contains an empty element if it is the only element in the array, the minute you try to add more you will get the error as described above.
In relation to the original code
To stop creating the extra blank element at the beginning you could switch to using a For instead of a For Each that way you can tell the loop to only call
ReDim Preserve allURLs(UBound(allURLs)+1)
when the index of the Array is greater then 0
For i = 0 To UBound(multiStringValues)
itemname = multiStringValues(i)
If itemname <> strFunctionIntranet1 And itemname <> strFunctionIntranet2 And itemname <> strFunctionIntranet3 And itemname <> strFunctionIntranet4 Then
'Only expand if we have more then 1 value in multiStringValues
If i > 0 Then ReDim Preserve allURLs(UBound(allURLs)+1)
allURLs(UBound(allURLs)) = itemname
End If
Next
You can do this with a For Each of course but you would have to track the Array index manually using another variable, which in my opinion when you have For already seems pointless.

Error code 0x8000500D when trying to access PasswordLastChanged

I'm writing a VBScript that will simply check each user in AD if their password has been changed within a given number of days. When I was trying to get it working for a single user, I came up with the following working code:
Option Explicit
Dim objUser, strLDAPConnection, intPwdExpLimit
strLDAPConnection = "CN=Test User,OU=Test,OU=Employees,DC=domain,DC=com"
intPwdExpLimit = 90
Set objUser = GetObject("LDAP://" + strLDAPConnection)
WScript.Echo DaysSincePwdChange(objUser)
Function DaysSincePwdChange(objUserAccount)
DaysSincePwdChange = dateDiff("d", objUserAccount.PasswordLastChanged, Now)
End Function
So then I tried to get it to work by looping through all users in a Test OU with the following code:
Option Explicit
Const strOffice = "Test"
Dim objEmployeesOU, objUser, intPwdExpLimit
intPwdExpLimit = 90
Set objEmployeesOU = GetObject("LDAP://OU=" & strOffice & _
",OU=Employees,DC=domain,DC=com")
For Each objUser In objEmployeesOU
If objUser.class = "user" Then
If ((DaysSincePwdChange(objUser)) >= intPwdExpLimit) Then
MsgBox(objUser & ": Password Expired.")
Else
MsgBox(objUser & ": Password Current.")
End If
End If
Next
Function DaysSincePwdChange(objUserAccount)
DaysSincePwdChange = dateDiff("d", objUserAccount.PasswordLastChanged, Now)
End Function
The above code produces a 0x8000500D error and googling the error says that it can't find the property in the cache (referring to the PasswordLastSet property, see error description link here).
Any ideas why the first block of code works fine but the second has a problem accessing that property?
Error code 0x8000500d means E_ADS_PROPERTY_NOT_FOUND. The password of the user has never been changed, so the property is not set. You could handle the condition like this:
Function DaysSincePwdChange(objUserAccount)
On Error Resume Next
DaysSincePwdChange = dateDiff("d", objUserAccount.PasswordLastChanged, Now)
If Err Then
If Err.Number = &h8000500d Then
DaysSincePwdChange = -1
Else
WScript.Echo "Unexpected Error (0x" & Hex(Err.Number) & "): " & _
Err.Description
WScript.Quit 1
End If
End If
End Function
and modify the check like this:
passwordAge = DaysSincePwdChange(objUser)
If passwordAge >= intPwdExpLimit) Then
MsgBox(objUser & ": Password Expired.")
ElseIf passwordAge = -1 Then
MsgBox(objUser & ": Password never changed.")
Else
MsgBox(objUser & ": Password Current.")
End If

Trying to use Shell object and FileSystemObject in VBScript for file manipulation

I am trying to recursively loop through hundreds of directories, and thousands of JPG files to gather sort the files in new folders by date. So far, I am able to individually GetDetailsOf the files using the Shell NameSpace object, and I am also able to recursively loop through directories using the FileSystemObject. However, when I try to put them together in functions, etc, I am getting nothing back when I try to get the DateTaken attribute from the photo.
Here is my code so far:
sFolderPathspec = "C:\LocationOfFiles"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objDir = objFSO.GetFolder(sFolderPathspec)
Dim arrFiles()
getInfo(objDir)
Sub getInfo(pCurrentDir)
fileCount = 0
For Each strFileName In pCurrentDir.Files
fileCount = fileCount + 1
Next
ReDim arrFiles(fileCount,2)
i=0
For Each aItem In pCurrentDir.Files
wscript.Echo aItem.Name
arrFiles(i,0) = aItem.Name
strFileName = aItem.Name
strDir = pCurrentDir.Path
wscript.echo strDir
dateVar = GetDatePictureTaken(strFileName, strDir)
'dateVar = Temp2 & "_" & Temp3 & "_" & Temp1
arrFiles(i,1) = dateVar
WScript.echo i & "." & "M:" & monthVar & " Y:" & yearVar
WScript.echo i & "." & strFileName & " : " & arrFiles(i,1) & " : " & dateVar
i=i+1
Next
For Each aItem In pCurrentDir.SubFolders
'wscript.Echo aItem.Name & " passing recursively"
getInfo(aItem)
Next
End Sub
Function GetDatePictureTaken(strFileName, strDir)
Set objShell = CreateObject ("Shell.Application")
Set objCurrFolder = objShell.Namespace(strDir)
'wscript.Echo cstr(objCurrFolder.GetDetailsOf(strFileName, 12))
strFileNameDate = cstr(objCurrFolder.GetDetailsOf(strFileName, 12))
strFileNameDate = CleanNonDisplayableCharacters(strFileNameDate)
arrDate = split(strFileNameDate, "/")
'''FAILS HERE WITH A SUBSCRIPT OUT OF RANGE ERROR SINCE IT GETS NULL VALUES BACK FROM THE GET DETAILS OF FUNCTION'''
monthVar = arrDate(0)
yearVar = arrDate(1)
dayVar = arrDate(2)
GetDatePictureTaken = monthVar & "\" & dayVar & "\" & yearVar
End Function
Function CleanNonDisplayableCharacters(strInput)
strTemp = ""
For i = 1 to len(strInput)
strChar = Mid(strInput,i,1)
If Asc(strChar) < 126 and not Asc(strChar) = 63 Then
strTemp = strTemp & strChar
End If
Next
CleanNonDisplayableCharacters = strTemp
End Function
The "Subscript out of range" error when accessing arrDate(0) is caused by arrDate being empty (UBound(arrDate) == -1). As a Split on a non-empty string will return an array, even if the separator is not found, and an attempt to Split Null will raise an "Invalid use of Null" error, we can be sure that strFileNameDate is "".
Possible reason for that:
The index of "Date Picture Taken" is 25 (XP) and not 12 (Win 7) - or whatever came to Mr. Gates' mind for Win 8.
The DPT property is not filled in.
Your cleaning function messed it up.
You have to test for strFileNameDate containing a valid date and decide where to put the files without a valid DPT.
P.S. Instead of doing the recursive loopings, you should consider to use
dir /s/b path\*.jpg > pictures.txt
and to process that file.

Autogenerate an email in an outlook and attach the currently open word document with VBS

I want to write a VBS macro to auto generate an email in outlook and attach a word document. I currently have a macro that does this for excel, but I can't get it to work for Word. I can't figure out for the life of me what my "FName= " should be. Any suggestions or help would be greatly appreciated. Here is what I have:
Sub AutoEmail()
On Error GoTo Cancel
Dim Resp As Integer
Resp = MsgBox(prompt:=vbCr & "Yes = Review Email" & vbCr & "No = Immediately Send" & vbCr & "Cancel = Cancel" & vbCr, _
Title:="Review email before sending?", _
Buttons:=3 + 32)
Select Case Resp
'Yes was clicked, user wants to review email first
Case Is = 6
Dim myOutlook As Object
Dim myMailItem As Object
Set otlApp = CreateObject("Outlook.Application")
Set otlNewMail = otlApp.CreateItem(olMailItem)
FName = ActiveWord & "\" & ActiveWord.Name
With otlNewMail
.To = ""
.CC = ""
.Subject = ""
.Body = "Good Morning," & vbCr & vbCr & "" & Format(Date, "MM/DD") & "."
.Attachments.Add FName
.Display
End With
Set otlNewMail = Nothing
Set otlApp = Nothing
Set otlAttach = Nothing
Set otlMess = Nothing
Set otlNSpace = Nothing
'If no is clicked
Case Is = 7
Dim myOutlok As Object
Dim myMailItm As Object
Set otlApp = CreateObject("Outlook.Application")
Set otlNewMail = otlApp.CreateItem(olMailItem)
FName = ActiveWorkbook.Path & "\" & ActiveWorkbook.Name
With otlNewMail
.To = ""
.CC = ""
.Subject = ""
.Body = "Good Morning," & vbCr & vbCr & " " & Format(Date, "MM/DD") & "."
.Attachments.Add FName
.Send
'.Display
'Application.Wait (Now + TimeValue("0:00:01"))
'Application.SendKeys "%s"
End With
'otlApp.Quit
Set otlNewMail = Nothing
Set otlApp = Nothing
Set otlAttach = Nothing
Set otlMess = Nothing
Set otlNSpace = Nothing
'If Cancel is clicked
Case Is = 2
Cancel:
MsgBox prompt:="No Email has been sent.", _
Title:="EMAIL CANCELLED", _
Buttons:=64
End Select
End Sub
May it is a bit late, but I want to solve it for future use.
You want to have the active document as your file name (FName).
FName = Application.ActiveDocument.Path + "\" + Application.ActiveDocument.Name
' .Path returns only the Path where the file is saved without the file name like "C:\Test"
' .Name returns only the Name of the file, including the current type like "example.doc"
' Backslash is needed because of the missing backslash from .Path
otlNewMail.Attachements.Add FName
May you also want to save your current document before sending it via outlook, otherwise you will send the document without the changes made.
Function SaveDoc()
ActiveDocument.Save
End Function
I hope that this will help others, because the code from the question helped me a lot while scripting a similar script.

Passing objects as arguments in VBScript

I'm working on a project to capture various disk performance metrics using VBScript and would like to use a sub procedure with an object as an argument. In the following code samples the object I'm referring to is objitem.AvgDiskQueueLength which will provide a value for the disk queue length. I haven't found a way to make it work since it is recognized as a string and then doesn't capture the value. My goal is to make it easy for anyone to change the counters that are to be captured by only having to make a change in one location(the procedure call argument). The way I'm going about this may not be the best but I'm open to suggestions. The sub procedure call is below.
PerfCounter "Average Disk Queue Length", "disk_queueLength", "objItem.AvgDiskQueueLength"
The following code is the sub procedure.
Sub PerfCounter(CounterDescription, CounterLabel, CounterObject)
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_PerfFormattedData_PerfDisk_PhysicalDisk",,48)
args_index = args_index + 1
arrCriteria = split(command_line_args(args_index),",")
strDriveLetter = UCase(arrCriteria(0))
intCriticalThreshold = arrCriteria(1)
intWarningThreshold = arrCriteria(2)
For Each objItem in colItems
With objItem
WScript.Echo "objitem.name = " & objitem.name
If InStr(objItem.Name, strDriveLetter & ":") > 0 Then
intChrLocation = InStr(objItem.Name, strDriveletter)
strInstanceName = Mid(objItem.Name, intChrLocation, 1)
End If
If strDriveLetter = strInstanceName AND InStr(objItem.Name, strDriveLetter & ":") > 0 Then
If intActiveNode = 1 OR Len(intActiveNode) < 1 Then
WScript.Echo "CounterDescription = " & CounterDescription
WScript.Echo "CounterLabel = " & CounterLabel
WScript.Echo "CounterObject = " & CounterObject
If CInt(CounterOjbect) => CInt(intCriticalThreshold) Then
arrStatus(i) = "CRITICAL: " & strDriveLetter & ": " & CounterDescription
arrTrendData(i) = CounterLabel & "=" & CounterObject
intExitCode = 2
arrExitCode(i) = intExitCode
ElseIf CInt(CounterOjbect) => CInt(intWarningThreshold) AND CInt(CounterObject) < CInt(intCriticalThreshold) Then
arrStatus(i) = "WARNING: " & strDriveLetter & ": " & CounterDescription
arrTrendData(i) = CounterLabel & "=" & CounterObject
intExitCode = 1
arrExitCode(i) = intExitCode
Else
arrStatus(i) = "OK: " & strDriveLetter & ": " & CounterDescription
arrTrendData(i) = CounterLabel & "=" & CounterObject
intExitCode = 0
arrExitCode(i) = intExitCode
End If
Else
PassiveNode CounterDescription, CounterLabel
End If
End If
End With
Next
i = i + 1
ReDim Preserve arrStatus(i)
ReDim Preserve arrTrendData(i)
ReDim Preserve arrExitCode(i)
End Sub
Why cant you do this...
PerfCounter "Average Disk Queue Length", "disk_queueLength", objItem.AvgDiskQueueLength
To pass an object you have to pass an object, not a string. To make this method work as expected you would have to have the object prior to the procedure call, but in your code example it looks like you are trying to pass an object that you don't have. A working example:
Set objFSO = CreateObject("Scripting.FileSystemObject")
UseFileSystemObject objFSO
Sub UseFileSystemObject( objfso)
'Now I can use the FileSystemObject in this procedure.
End Sub
But calling the UseFileSystemObject procedure like this will not work,
UseFileSystemObject "objFSO"
because you are passing in a string not an object.
The only way I can think of to accomplish what you want is to use a select statement to write the appropriate attribute of the object, something like this.
Call PerfCounter "Average Disk Queue Length", "disk_queueLength", "AvgDiskQueueLength"
Sub PerfCounter(CounterDescription, CounterLabel, CounterObjectAttribute)
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_PerfFormattedData_PerfDisk_PhysicalDisk",,48)
For Each objItem in colItems
Select Case CounterObjectAttribute
Case "ObjectAttribute1"
Case "ObjectAttribute2"
Case "AvgDiskQueueLength"
Wscript.Echo objItem.AvgDiskQueueLength
End Select
Next
End Sub
So in the select you would have to add a case for each attribute that can be used, but it would allow you to pass a string into the procedure. I might be way off on this, but I don't know how you can pass an object if you don't have the object first.

Resources