Avatar of itnifl
itnifl
Flag for Norway asked on

How to read target path of printer link with Visual Basic Script

The code below receives a printer link file path as an argument to the script, it then reads the link files target path and tries to connect to the printer that the target path points to. However, reading the link targetpath only works for a directory link and I assume a file link also. With the code below, I can't seem to be able to read the target path of a link that links to a printer. Does anyone here know how to do it?

Option Explicit
Dim strLinkFullname, strShortcut, strShortTarget, objNetwork, oShell

Set oShell = wscript.createObject("wscript.shell")
Set objNetwork = CreateObject("WScript.Network") 

strLinkFullname = WScript.Arguments(0)
Set strShortcut = oShell.CreateShortcut(strLinkFullname)
strShortTarget = strShortcut.TargetPath

Wscript.Echo "Trying to connect the printer: " & strShortTarget

objNetwork.AddWindowsPrinterConnection strShortTarget

Open in new window

VB ScriptScripting LanguagesMicrosoft Legacy OS

Avatar of undefined
Last Comment
itnifl

8/22/2022 - Mon
RobSampson

Pardon my ignorance, but what is a printer link?  Is that a file with an .lnk extension?  I just tried creating one, and it said it couldn't find the file, which I kind of expected.  How did you create one?

Have you tried opening it just with Notepad?  Maybe you could just use the FSO to read it as a flat file?

Regards,

Rob.
itnifl

ASKER
No ignorance perceived. The IT world is big, and I don't expect the experts here to never ask a question. The link links to a shared network printer on a unc path, not a local printer. To create a shortcut you right click the shared printer under \\servername and select Create Shortcut. Then selecting properties on such a link, I can see the target path, but I can not select it. The link is a lnk file.

The script is ultimately supposed to traverse folders with links to printers on terminal servers and connect them. This is to automate the process of connecting printers to  terminal servers. This process can be rather time consuming and tedious if it is done manually.

I did open the link with notepad, but I did not perceive the content to be parseable. This is because the printer name is not shown in cleartext, however the servername with double slashes is.
RobSampson

Interesting.  I'll look into it at some point tomorrow.

Do you mind me asking what the reason for the shortcuts is, as opposed to having the printer names in a script themselves? I know this may seem to be double-handling though.

On another thought, are they all on the same print server?  If so, the queue name could be read from the file name itself, as mine showed to the correct queue name, so tacking the print server name on the front of that would be easy.

One more thought, you could have the script read the advertised printers from a print server via WMI, and connect all available printers if you wanted to.  This only requires the knowledge of the print server name.

If those aren't options, I'll look into the .lnk tomorrow.  I don't think I'll have time today.

Regards,

Rob.
I started with Experts Exchange in 2004 and it's been a mainstay of my professional computing life since. It helped me launch a career as a programmer / Oracle data analyst
William Peck
itnifl

ASKER
We have several different customers with different printers on different terminal server environments. The different customers have different a set of printers to theyr environment. The printers are made available via the termibalservers and on the users startmenu on those terminalservers as shortcuts. To connect only the customers printers on a new customers terminalserver I use those shortcuts to avoid connecting all possible myriads of printers that are not relevant to that customer. I could read the servername fro the linkfile with fso and then get the printername from the linkname. This would however be dependendant on the link name having specific namestandard wich I guess someone might get the idea to break sometime.
RobSampson

Is it an option that instead of reading the .lnk files, you just "execute" them?

Set objShell = CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")
For Each objFile In objFSO.GetFolder(objShell.ExpandEnvironmentStrings("%USERPROFILE%") & "\Start Menu\Printers").Files
     objShell.Run objFile.Path, 1, False
Next

Open in new window


Otherwise, I can't find any way to read the path of a printer link.  They seem different to normal file links somehow.  The iShellLink interface in Powershell can't see the path of the printer link either, but it can of a normal file shortcut.

Regards,

Rob.
itnifl

ASKER
If you execute ut normally via the GUI, it just opens the printer queue and doesn't connect the printer. I will try anyway and see if it does the trick.
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
itnifl

ASKER
Option Explicit
Dim strLinkFullname, objShell, objFSO, objFile

strLinkFullname = WScript.Arguments(0)

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

For Each objFile In objFSO.GetFolder(strLinkFullname).Files
	 Wscript.Echo "Reading: " & objFile.Path
     objShell.Run objFile.Path, 1, False
Next

Open in new window


The variable names are a bit misleading here, the usage is as follows with the following results:

>cscript test.vbs "O:\"
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

Reading: O:\104055C67 - Canon iR C3080.lnk
\test.vbs(11, 6) (null): The
 system cannot find the file specified.
RobSampson

Sorry, it wasn't meant to be used by passing a .lnk path to the script.  You can pass a folder path that contains the .lnk files for it to enumerate and run each one.

Regards,

Rob.

Option Explicit
Dim strLinkFolderPath, objShell, objFSO, objFile

strLinkFolderPath = WScript.Arguments(0)

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

For Each objFile In objFSO.GetFolder(strLinkFolderPath).Files
   Wscript.Echo "Reading: " & objFile.Path
   objShell.Run objFile.Path, 1, False
Next

Open in new window

itnifl

ASKER
if you read my above answer again, you can ee by the output that I gave a folder as input to the script:

c:\path\blabla\>cscript test.vbs "O:\"
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

Reading: O:\104055C67 - Canon iR C3080.lnk
\test.vbs(11, 6) (null): The
 system cannot find the file specified.
Experts Exchange is like having an extremely knowledgeable team sitting and waiting for your call. Couldn't do my job half as well as I do without it!
James Murphy
RobSampson

Oh sorry, you're right.  I didn't read the output properly.

I wonder if it helps if we add quotes around it.  Change
     objShell.Run objFile.Path, 1, False

to
     objShell.Run """" & objFile.Path & """", 1, False

Regards,

Rob.
itnifl

ASKER
The result was:

\test.vbs(11, 6) msxml3.dll: Property name is invalid.

I believe connecting a printer and running the printer link are two different things. The first prompts to install eventual drivers if they are missing(wich is what I want), the second only opens the printer queue.
RobSampson

That's a very strange error to get from a straight VBScript file.  Double-clicking the printer shortcut will connect it though, won't it?
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
itnifl

ASKER
Yes, I can.
RobSampson

My apologies.  I finally got around to testing this, and although I couldn't manually connect my printer via the shortcut, the script now produced the same error, so hopefully on your system it will work.

Regards,

Rob.

Option Explicit
Dim strLinkFolderPath, objShell, objFSO, objFile, strShortPath

strLinkFolderPath = WScript.Arguments(0)

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

For Each objFile In objFSO.GetFolder(strLinkFolderPath).Files
	If LCase(Right(objFile.Name, 4)) = ".lnk" Then
		strShortPath = objFSO.GetFile(objFile.Path).ShortPath
		Wscript.Echo "Reading: """ & strShortPath & """"
		objShell.Run """" & strShortPath & """", 1, False
	End If
Next

Open in new window

itnifl

ASKER
Reading: "O:\123456~1.LNK"
printer2.vbs(13, 3) msxml3.dll:
Property name is invalid.

Same error. I also renamed the printer link so that it did not contain any space characters. That didn't help either.
Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes
RobSampson

Can you try it on another system, or make sure that msxml3.dll is properly registered?  Run this from an administrative command prompt first:
regsvr32 c:\windows\system32\msxml3.dll

That's a very strange error to be receiving....

Rob.
RobSampson

Also, is the printer in the link on the same local network?
RobSampson

OK, nevermind.  I think I've been barking up the wrong tree.  I have finally tested it on a Windows XP machine, and have discovered that the shortcut (when double-clicked) doesn't actually "connect" the printer.  It only open the print queue.  There is also no "Connect" option when you right click the shortcut, so I don't think we can read it properly.

I think you're safest bet is going to be to name the shortcut files such that you can read the file "names" and then map the printers.  For example, if you have the file name in the format of
HP Laserjet 2420 on YourPrintServer.lnk

Then you can read the server name from the last word, and the share name from the rest, and map it.  Is that feasible?

Regards,

Rob.
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
itnifl

ASKER
It would be if such a standard was established in our organization. I don't know if it would be achieveable to create such a standard and make people follow it.
RobSampson

Hi, I believe I have finally solved the problem!!!  I originally though the link file was unreadable by the VBScript FSO, but it turns out (after much trial and error) that the .lnk just contains invalid characters (ASCII code of zero).  So, I have figured out how to read the .lnk contents without erroring out on those, and can connect to the printer specified in it.

Give this a try.

Regards,

Rob.

Option Explicit
Dim strLinkFolderPath, objShell, objFSO, objNetwork, objFile, objShortcut, strContents, strPrinter

If WScript.Arguments.Count = 0 Then
	strLinkFolderPath = Replace(WScript.ScriptFullName, WScript.ScriptName, "")
Else
	strLinkFolderPath = WScript.Arguments(0)
End If

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

For Each objFile In objFSO.GetFolder(strLinkFolderPath).Files
	If LCase(Right(objFile.Name, 4)) = ".lnk" Then
		Set objShortcut = objFSO.OpenTextFile(objFile.Path, 1, False, 0)
		strContents = Replace(objShortcut.ReadAll, Chr(0), "")
		objShortcut.Close
		strPrinter = Mid(strContents, InStrRev(strContents, "\\"))
		objNetwork.AddWindowsPrinterConnection strPrinter
	End If
Next

Open in new window

itnifl

ASKER
printer.zipprinter.zipBefore line 19 I inserted this line:
WScript.Echo strContents

The output then shows:
L? Ûº¾104055C67
M:\...\Desktop\printer3.vbs(20, 3) Microsoft VB
Script runtime error: Invalid procedure call or argument: 'Mid'

In another example:
L
M:\...\Desktop\printer3.vbs(20, 3) Microsoft VB
Script runtime error: Invalid procedure call or argument: 'Mid'

Attaching a link to the printer here.
This is the best money I have ever spent. I cannot not tell you how many times these folks have saved my bacon. I learn so much from the contributors.
rwheeler23
RobSampson

OK, can you try this.  I couldn't see a valid path from your lnk file.  In mine, at the end of the contents, there's
\\printserver\mysharedprinter

but in yours, it looks like
%SystemRoot%\system32\imageres.dll

This script won't try to map the printer, but it will give you output on what it can see in the file.

Rob.

Option Explicit
Dim strLinkFolderPath, objShell, objFSO, objNetwork, objFile, objShortcut, strContents, strPrinter, strChr

If WScript.Arguments.Count = 0 Then
	strLinkFolderPath = Replace(WScript.ScriptFullName, WScript.ScriptName, "")
Else
	strLinkFolderPath = WScript.Arguments(0)
End If

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

For Each objFile In objFSO.GetFolder(strLinkFolderPath).Files
	If LCase(Right(objFile.Name, 4)) = ".lnk" Then
		Set objShortcut = objFSO.OpenTextFile(objFile.Path, 1, False, 0)
		While Not objShortcut.AtEndOfStream
			strChr = objShortcut.Read(1)
			'If Asc(strChr) >= 32 And Asc(strChr) <= 126 Then WScript.Echo strChr & ": " & Asc(strChr)
			If Asc(strChr) >= 32 And Asc(strChr) <= 126 Then strContents = strContents & strChr
		Wend
		objShortcut.Close
		WScript.Echo vbCrLf & "File: "
		WScript.Echo objFile.Name
		WScript.Echo vbCrLf & "Contents: "
		WScript.Echo strContents
		WScript.Echo vbCrLf & "Printer:"
		strPrinter = Mid(strContents, InStrRev(strContents, "\\"))
		WScript.Echo strPrinter
		'objNetwork.AddWindowsPrinterConnection strPrinter
	End If
Next

Open in new window

itnifl

ASKER
C:\...\Desktop>cscript printer4.vbs .\printer
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.


File:
100000C09 - Lexmark X560.lnk

Contents:
LF@-X,!PCsg<;I1SPS0%G`-servername-1SPS:7CD)-1SPSsCCOi3nN'":i+00 100000C09 C:\
Windows\system32\imageres.dll%SystemRoot%\system32\imageres.dll%SystemRoot%\syst
em32\imageres.dll

Printer:
M:\...\Desktop\printer4.vbs(28, 3) Microsoft VB
Script runtime error: Invalid procedure call or argument: 'Mid'
RobSampson

So does any of that text identify the printer the shortcut should be pointing to?  When you connect to the printer, what is the driver is uses?  Is it a server based printer, or a local one?

Can you try a shortcut to another printer that is on a print server?

Rob.
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
itnifl

ASKER
It is a printer connected to a print server and shared with network users.

LF@-X,!PCsg<;I1SPS0%G`-servername-1SPS:7CD)-1SPSsCCOi3nN'":i+00 100000C09 C:\
Windows\system32\imageres.dll%SystemRoot%\system32\imageres.dll%SystemRoot%\syst
em32\imageres.dll
I substituted servername with servername. Second bold mark is the printer.

The driver used is canon iR C3080/3480/3580 PCL5c

This problem with getting the UNC path to the printer is all the same with all printer links.
RobSampson

OK, so it's strange that yours are so different to mine, but maybe that's Terminal Server or Citrix or something like that.  So, the only way forward is to parse that output for known strings, which are hopefully consistent with all of your shortcuts.  So, hopfeully your server name is always
<hyphen><servername><hyphen>1SPS:

so I'll look for that string and grab the server name.  Similarly, I'll grab the share name before the string C:\Windows\system32\imageres.dll

Try this.

Regards,

Rob.

Option Explicit
Dim strLinkFolderPath, objShell, objFSO, objNetwork, objFile, objShortcut, strServer, strContents, strPrinter, strChr, intPos, intEnd, intStart

If WScript.Arguments.Count = 0 Then
	strLinkFolderPath = Replace(WScript.ScriptFullName, WScript.ScriptName, "")
Else
	strLinkFolderPath = WScript.Arguments(0)
End If

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

For Each objFile In objFSO.GetFolder(strLinkFolderPath).Files
	If LCase(Right(objFile.Name, 4)) = ".lnk" Then
		Set objShortcut = objFSO.OpenTextFile(objFile.Path, 1, False, 0)
		While Not objShortcut.AtEndOfStream
			strChr = objShortcut.Read(1)
			'If Asc(strChr) >= 32 And Asc(strChr) <= 126 Then WScript.Echo strChr & ": " & Asc(strChr)
			If Asc(strChr) >= 32 And Asc(strChr) <= 126 Then strContents = strContents & strChr
		Wend
		objShortcut.Close
		WScript.Echo vbCrLf & "File: "
		WScript.Echo objFile.Name
		WScript.Echo vbCrLf & "Contents: "
		WScript.Echo strContents
		WScript.Echo vbCrLf & "Printer:"
		'strPrinter = Mid(strContents, InStrRev(strContents, "\\"))
		'WScript.Echo strPrinter
		intPos = InStr(strContents, "-1SPS:")
		If intPos > 0 Then
			intEnd = intPos - 1
			intStart = InStrRev(strContents, "-", intEnd)
			If intStart > 0 Then
				intStart = intStart + 1
				strServer = Mid(strContents, intStart, intEnd - intStart + 1)
				intPos = InStr(strContents, " C:\Windows\system32\imageres.dll")
				If intPos > 0 Then
					intEnd = intPos - 1
					intStart = InStrRev(strContents, " ", intEnd)
					If intStart > 0 Then
						intStart = intStart + 1
						strPrinter = Mid(strContents, intStart, intEnd - intStart + 1)
						WScript.Echo "Would map printer to \\" & strServer & "\" & strPrinter
						'objNetwork.AddWindowsPrinterConnection strPrinter
					Else
						WScript.Echo "Unable to find start of printer name by space in" & Mid(strContents, intEnd - 30, 30)
					End If
				Else
					WScript.Echo "Unable to find end of printer name by C:\Windows\system32\imageres.dll"
				End If
			Else
				WScript.Echo "Unable to find start of server name by hyphen in " & Right(Left(strContents, intEnd), 30)
			End If
		Else
			WScript.Echo "Unable to find string -1SPS: in the link file."
		End If
	End If
Next

Open in new window

itnifl

ASKER
File:
printername - Canon iR C3080.lnk

Contents:
LFX`, :i+00GEntire Network3FMicrosoft Windows NetworkMicrosoft NetworkADomain NameMicro
soft Network*B\\servernameMicrosoft NetworkN'":i+00 printername

Printer:
Unable to find string -1SPS: in the link file.

Bold text is substituted text, real names are hidden to protect information.
Your help has saved me hundreds of hours of internet surfing.
fblack61
ASKER CERTIFIED SOLUTION
RobSampson

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
itnifl

ASKER
cscript printer6.vbs O:\
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.


File:
xxxxxxC19 - Canon IR.lnk

Contents:
LFX`, :i+00GEntire Network3FMicrosoft Windows NetworkMicrosoft NetworkADomainMicro
soft Network*B\\serverMicrosoft NetworkN'":i+00 printer

Printer:
Unable to find string -1SPS: in the link file.
Would map printer to \\server\printer

I tested the script against several other links also, and it seems it works. Good work, thanks! =)
RobSampson

Cool. Finally got there :-)

So you will get this message:
Unable to find string -1SPS: in the link file

for the first type of file that you posted, because was the identifying string in it.  If that can't be found, it looks for the "Microsoft Network" string, which is the format of the second one you posted, so you should have both versions covered.

Thanks for the grade.

Regards,

Rob.
itnifl

ASKER
You dd a good job, more then I would expect.
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
itnifl

ASKER