Solved

Reading from a txt file and parsing information into separate reports

Posted on 2013-06-28
15
306 Views
Last Modified: 2013-08-15
So I found this script on the internet and for the life of me I cant seem to modify it.  I wish to basically read a list from a txt(list of computers) give me such as the location in the OU of active directory.  This script generates an HTML profile, but what happens when it runs agains multiple system will it generate a separate profile for each machine...

Here is the script
On Error Resume Next

' Get system name for output file name
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2") 
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_ComputerSystem")

' Open file for Writing
Dim fso, MyFile
Set fso = CreateObject("Scripting.FileSystemObject")
For Each objItem In colItems
	strComputerName = objItem.Name
Next

Set MyFile = fso.CreateTextFile(".\" & strComputerName & "_CONFIG.html", True)
MyFile.WriteLine("<!DOCTYPE HTML PUBLIC " & chr(34) & "-//W3C//DTD HTML 4.01//EN" & chr(34) & " " & chr(34) & "http://www.w3.org/TR/html4/strict.dtd" & chr(34) & ">")
MyFile.WriteLine("<html>")
MyFile.WriteLine("<head>")
MyFile.WriteLine("<title>Configuration for " & strComputerName)
MyFile.WriteLine("Generated: " & Date() & " " & Time() & "</title>")
MyFile.WriteLine("</head>")

' Get basic info & timestamp file and write headers
MyFile.WriteLine("<body>")
MyFile.WriteLine("<h1><center>File generated: " & Date() & " " & Time() & "</center></h1>")
MyFile.WriteLine("<hr>")

myFile.WriteLine("<table BORDER=1>")
MyFile.WriteLine("<tr><td align=center><b>System Name</b></td><td align=center><b>Make</b></td><td align=center><b>Model</b></td><td align=center><b>Serial Number</b></td></tr>")	
For Each objItem in colItems 
	MyFile.WriteLine("<tr>")
    MyFile.WriteLine( "<td>" & objItem.Name & "</td>")
    MyFile.WriteLine( "<td>" & objItem.Manufacturer & "</td>")
    MyFile.WriteLine( "<td>" & objItem.Model & "</td>")
Next

Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_BIOS",,48) 
For Each objItem in colItems 
    MyFile.WriteLine("<td>" & objItem.SerialNumber & "</td>")
	MyFile.WriteLine("</tr>")
Next
MyFile.WriteLine("</table><p>")

' Get current user
MyFile.WriteLine("<hr><p><h3>LOGGED-ON USER</h3><p>")
Set colComputer = objWMIService.ExecQuery("Select * from Win32_ComputerSystem",,48)
For Each objComputer in colComputer
    MyFile.WriteLine( "<b>Logged-on user: </b>" & objComputer.UserName & "<p>")
Next

' Get OS Version
MyFile.WriteLine( "<hr><p><h3>OPERATING SYSTEM</h3><p>")
Set dtmConvertedDate = CreateObject("WbemScripting.SWbemDateTime")
Set colOperatingSystems = objWMIService.ExecQuery("Select * from Win32_OperatingSystem",,48)
For Each objOperatingSystem in colOperatingSystems
    MyFile.WriteLine( "<b>Caption: </b>" & objOperatingSystem.Caption & "<p>")
    strOSCaption = objOperatingSystem.Caption
    dtmConvertedDate.Value = objOperatingSystem.InstallDate
    dtmInstallDate = dtmConvertedDate.GetVarDate
    MyFile.WriteLine( "<b>Install Date: </b>" & dtmInstallDate & "<p>")
    MyFile.WriteLine( "<b>Registered User: </b>" & objOperatingSystem.RegisteredUser & "<p>")
    MyFile.WriteLine( "<b>Serial Number: </b>" & objOperatingSystem.SerialNumber & "<p>")
    MyFile.WriteLine( "<b>Version: </b>" & objOperatingSystem.Version & "<p>")
	MyFile.Writeline( "<b>Service Pack: </b> SP " & objOperatingSystem.ServicePackMajorVersion & "<p>")
Next

' Get IP address
MyFile.WriteLine( "<hr><p><h3>IP ADDRESSES</h3><p>")
Set IPConfigSet = objWMIService.ExecQuery("Select * from Win32_NetworkAdapterConfiguration Where IPEnabled=TRUE",,48)
For Each IPConfig in IPConfigSet
    If Not IsNull(IPConfig.IPAddress) Then 
        For i=LBound(IPConfig.IPAddress) to UBound(IPConfig.IPAddress)
            MyFile.WriteLine("<b>IP Address: </b>" & IPConfig.IPAddress(i) & "<p>")
			MyFile.WriteLine("<b>MAC Address: </b>" & IPConfig.MACAddress & "<p>")
        Next
    End If
Next

' Get processor Info
MyFile.WriteLine("<hr><p><h3>PROCESSOR INFO</h3><p>")
Set colItems = objWMIService.ExecQuery("Select * from Win32_Processor",,48)
MyFile.WriteLine("<table BORDER=1>")
MyFile.WriteLine("<tr><td align=center><b>Manufacturer</b></td><td align=center><b>Name</b></td><td align=center><b>Description</b></td></tr>")
For Each objItem in colItems
	MyFile.WriteLine("<tr>")
    MyFile.WriteLine( "<td>" & objItem.Manufacturer & "</td>")
    MyFile.WriteLine( "<td>" & objItem.Name & "</td>")
    MyFile.WriteLine( "<td>" & objItem.Description & "</td>")
	MyFile.WriteLine("</tr>")
Next
MyFile.Write("</table><p>")

' Get memory stats
MyFile.WriteLine( "<hr><p><h3>INSTALLED MEMORY</h3><p>")
Set colItems = objWMIService.ExecQuery("Select * from Win32_PhysicalMemory",,48)
myFile.WriteLine("<table BORDER=1>")
myFile.WriteLine("<tr><td><b>Bank Label</b></td><td><b>Capacity </b></td><td><b>Description </b></td><td><b>Device Locator </b></td><td><b>Speed </b></td></tr>")
For Each objItem in colItems
	myFile.WriteLine("<tr>")
	MyFile.WriteLine( "<td>" & objItem.BankLabel & "</td>")
    MyFile.WriteLine( "<td align=right>" & objItem.Capacity/1024/1024 & "MB</td>")
	MyFile.WriteLine( "<td>" & objItem.Description & "</td>")
    MyFile.WriteLine( "<td>" & objItem.DeviceLocator & "</td>")
    MyFile.WriteLine( "<td align=right>" & objItem.Speed & "</td>")
	myFile.WriteLine("</tr>")
Next
myFile.WriteLine("</table><p>")

' Get Video controller info
MyFile.WriteLine("<hr><p><h3>VIDEO CARD SPECS</h3><p>")
Set colItems = objWMIService.ExecQuery("Select * from Win32_DisplayControllerConfiguration",,48)
myFile.WriteLine("<table BORDER=1>")
myFile.WriteLine("<tr><td align=center><b>Name</b></td><td align=center><b>Refresh rate</b></td><td align=center><b>Setting ID</b></td><td align=center><b>Video Mode </b></td></tr>")
For Each objItem in colItems
	MyFile.WriteLine("<tr>")
    MyFile.WriteLine( "<td>" & objItem.Name & "</td>")
    MyFile.WriteLine( "<td align=right>" & objItem.RefreshRate & "Hz</td>")
    MyFile.WriteLine( "<td>" & objItem.SettingID & "</td>")
    MyFile.WriteLine( "<td>" & objItem.VideoMode & "</td>")
	MyFile.WriteLine("</tr>")    
Next
myFile.WriteLine("</table><p>")

' Get hard drive specs
MyFile.WriteLine( "<hr><p><h3>HARD DRIVE SPECS</h3><p>")
Set colItems = objWMIService.ExecQuery("Select * from Win32_LogicalDisk where DriveType=3",,48)
MyFile.WriteLine("<table BORDER=1>")
MyFile.WriteLine("<tr><td><b>Drive letter</b></td><td><b>Volume name</b></td><td><b>File system</b></td><td><b>Total size</b></td><td><b>Free space</b></td></tr>")
For Each objDrive in colItems
	MyFile.WriteLine("<tr>")
	MyFile.WriteLine( "<td align=center>" & objDrive.DeviceID& ":" & "</td>")
	MyFile.WriteLine( "<td>" & objDrive.VolumeName & "</td>")
	MyFile.WriteLine( "<td>" & objDrive.FileSystem & "</td>")
	MyFile.WriteLine( "<td align=right>" & Round(objDrive.Size/1024/1024/1024,2) & "GB" & "</td>")
	MyFile.WriteLine( "<td align=right>" & Round(objDrive.FreeSpace/1024/1024/1024,2) & "GB" & "</td>")
	MyFile.WriteLine("</tr>")
Next
MyFile.WriteLine("</table><p>")

' Get CD-ROM drives info
MyFile.WriteLine( "<hr><p><h3>CD/DVD DRIVES</h3><p>")
Set colItems = objWMIService.ExecQuery("Select * from Win32_CDROMDrive",,48)
MyFile.WriteLine("<table BORDER=1>")
MyFile.WriteLine("<tr><td align=center><b>Drive</b></td><td align=center><b>Name</b></td><td align=center><b>Description</b></td><td align=center><b>Caption</b></td></tr>")
For Each objItem in colItems
	MyFile.WriteLine("<tr>")
    MyFile.WriteLine( "<td align=center>" & objItem.Drive & "</td>")
    MyFile.WriteLine( "<td>" & objItem.Name & "</td>")
    MyFile.WriteLine( "<td>" & objItem.Description & "</td>")
    MyFile.WriteLine( "<td>" & objItem.Caption & "</td>")
	MyFile.WriteLine("</tr>")
Next
MyFile.WriteLine("</table><p>")

' Determine if Office is installed
MyFile.WriteLine( "<hr><p><h3>Microsoft Office Status</h3><p>")

Dim objCountOfOffice
objCountOfOffice = 0
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_Product WHERE Caption Like '%Microsoft Office%'",,48) 
For Each objItem in colItems
	objCountOfOffice = 1
Next
if objCountOfOffice = 1 then
	MyFile.Writeline("Microsoft Office is installed.")
else
	MyFile.Writeline("No Microsoft Office version found.")
end if

' Determine if .NET 3.5 is installed
MyFile.WriteLine( "<hr><p><h3>.NET 3.5 Installation Status</h3><p>")
Const HKLM = &H80000002
Set oReg=GetObject("winmgmts:\\" & strComputerName & "\root\default:StdRegProv")
blnInstalled = False
If oReg.GetDWordValue(HKLM, "SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5", "Install", strValue) = 0 Then
	blnInstalled = True
End If
If blnInstalled = True Then
	MyFile.WriteLine("Microsoft .Net 3.5 is installed.")
Else
	MyFile.WriteLine("Microsoft .Net 3.5 is <b>not</b> installed.")
End If	

' Determine if AV is installed, active and up to date
' NOTE: There are two sets of code for different OSs

MyFile.WriteLine( "<hr><p><h3>Anti-virus Status</h3><p>")
myFile.WriteLine("<table BORDER=1>")
MyFile.WriteLine("<tr><td align=center><b>AV Author</b></td><td align=center><b>Display Name</b></td><td align=center><b>Version</b></td><td align=center><b>Instance GUID</b></td><td align=center><b>Product up to date</b></td></tr>")

If InStr(LCase(strOSCaption), "2000") > 0 Or  InStr(LCase(strOSCaption), "xp") > 0 Or InStr(LCase(strOSCaption), "2003") > 0 Then
	'This version works on Win2000/XP
	Set objWMIServiceAV = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputerName & "\root\SecurityCenter")
Else
	'This version works on Vista and newer operating systems
	Set objWMIServiceAV = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputerName & "\root\SecurityCenter2")
End If
Set colItems = objWMIServiceAV.ExecQuery ("Select * from AntiVirusProduct")
For Each objItem in colItems
	MyFile.WriteLine("<tr>")
	MyFile.WriteLine( "<td>" & objItem.companyName & "</td>")
	MyFile.WriteLine( "<td>" & objItem.displayName & "</td>")
	MyFile.WriteLine( "<td>" & objItem.versionNumber & "</td>")
	MyFile.WriteLine( "<td>" & objItem.instanceGuid & "</td>")
	MyFile.WriteLine( "<td>" & objItem.productUptoDate & "</td>")
	MyFile.WriteLine("</tr>")
Next
MyFile.WriteLine("</table><p>")

'Determine MSIE version
' NOTE: It currently returns the full version number; will need to work on splitting it into version and SP
MyFile.WriteLine( "<hr><p><h3>Microsoft Internet Explorer Version</h3><p>")
Set objFSO = CreateObject("Scripting.FileSystemObject")
MyFile.WriteLine("MSIE version is " & objFSO.GetFileVersion("\\" & strComputerName & "\c$\program files\internet explorer\en-us\iexplore.exe.mui") & "<p>")

' Get all MS Product IDs
MyFile.WriteLine( "<hr><p><h3>MS LICENSE KEYS</h3><p>")

strDecodedKey = sGetWindowsKey(strComputerName)
MyFile.WriteLine("<b>Operating System License Key: </b>" & strDecodedKey & "<p>")

strOSArchitecture = GetOSArchitecture(strComputerName)
If strOSArchitecture  = "64" Then
	strInitialLocation = "SOFTWARE\Wow6432Node\"
Else
	strInitialLocation = "SOFTWARE\"
End If
For Each strVersion In Array("11.0", "12.0")
	strDetails = GetOfficeKeys(strComputer, strInitialLocation & "Microsoft\Office\" & strVersion & "\Registration")
	arrDetails = Split(strDetails, "|")
	For intItem = LBound(arrDetails) To (UBound(arrDetails) - 1) Step 2
		strProductName = arrDetails(intItem)
		strDecodedKey = arrDetails(intItem + 1)
		MyFile.WriteLine("<b>" & strProductName & " License Key: </b>" & strDecodedKey & "<p>")
	Next
Next

oReg.GetBinaryValue HKLM, "SOFTWARE\Microsoft\Exchange\Setup", "DigitalProductId", bDigitalProductID
If IsNull(bDigitalProductID) = False Then
	strDecodedKey = DecodeOfficeKey(bDigitalProductID)
	If strDecodedKey <> "" Then
		MyFile.WriteLine("<b>Exchange 2003 License Key: </b>" & strDecodedKey & "<p>")
	End If
End If

' close the config file
MyFile.WriteLine("</body>")
MyFile.WriteLine("</html>")
MyFile.Close


'Start the collection of the key, product name and also call the key decoder!
'***************************************************
Function GetOfficeKeys(strComputer, strKeyPath)
	strVersionInfo = ""
	'Go to the registery and collect the subkeys from initial key path
	Const HKEY_LOCAL_MACHINE = &H80000002
	Set oReg=GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv")
	oReg.EnumKey HKEY_LOCAL_MACHINE, strKeyPath, arrSubKeys

	'Check to see if there is any subkeys, if not, do not run!
	If Not IsNull (arrSubkeys) Then
		For Each strSubkey In arrSubKeys
			If Left(strSubkey, 1) = "{" Then
				bDigitalProductID = Null
				oReg.GetBinaryValue HKEY_LOCAL_MACHINE, strKeyPath & "\" & strSubkey, "DigitalProductId", bDigitalProductID
				oReg.GetStringValue HKEY_LOCAL_MACHINE, strKeyPath & "\" & strSubkey, "ProductName", strProductName
				If Not IsNull(bDigitalProductID) Then
					If IsNull(strProductName) Then strProductName = "{UNKNOWN in " & strKeyPath & "\" & strSubkey & "}"
					strDecodedKey = DecodeOfficeKey(bDigitalProductID)
					If Len(strVersionInfo) = 0 Then
						strVersionInfo = strProductName & "|" & strDecodedKey
					Else
						strVersionInfo = strVersionInfo & "|" & strProductName & "|" & strDecodedKey
					End If
				End If
			End If
		Next
	End If
	GetOfficeKeys = strVersionInfo
End Function

'This function decodes the key from the registry into something more useful!
Function DecodeOfficeKey(bProductIDArray)
	szProductKey = ""
	Const rpkOffset=52:i=28
	szPossibleChars="BCDFGHJKMPQRTVWXY2346789"
	Do 'Rep1
		dwAccumulator=0 : j=14
		Do 
			dwAccumulator=dwAccumulator*256
			dwAccumulator=bProductIDArray(j+rpkOffset)+dwAccumulator
			bProductIDArray(j+rpkOffset)=(dwAccumulator\24) and 255
			dwAccumulator=dwAccumulator Mod 24
			j=j-1
		Loop While j>=0
		i=i-1 : szProductKey=mid(szPossibleChars,dwAccumulator+1,1)&szProductKey
		if (((29-i) Mod 6)=0) and (i<>-1) Then
			i=i-1 : szProductKey="-"&szProductKey
		End If
	Loop While i>=0 'Goto Rep1
	DecodeOfficeKey=szProductKey
End Function

Function sGetWindowsKey(sComputer)  
	'Read the value of: 
	'HKLM\SOFTWARE\MICROSOFT\Windows NT\CurrentVersion\DigitalProductId
	' or if that returns BBBBB-BBBBB-BBBBB-BBBBB-BBBBB then read
	'HKLM\SOFTWARE\MICROSOFT\Windows NT\CurrentVersion\DigitalProductId4
	Dim bDigitalProductID
	Dim bProductKey()
	Dim ilByte
	Dim lDataLen
	Dim hKey
	Const HKEY_LOCAL_MACHINE = &H80000002
	
	Dim oReg
	Set oReg = GetObject("winmgmts:\\" & sComputer & "\root\default:StdRegProv")
	For Each sValueName In Array("DigitalProductId", "DigitalProductId4")
		sCDKey = ""
		oReg.GetBinaryValue HKEY_LOCAL_MACHINE, "SOFTWARE\MICROSOFT\Windows NT\CurrentVersion", sValueName, bDigitalProductID
		
		lDataLen = 164 
		ReDim Preserve bDigitalProductID(lDataLen) 
		ReDim Preserve bProductKey(14) 
		
		For ilByte = 52 To 66 
			bProductKey(ilByte - 52) = bDigitalProductID(ilByte) 
		Next 
		
		'Now we are going to 'base24' decode the 
		'   Product Key 
		Dim bKeyChars
		bKeyChars = Array(Asc("B"),Asc("C"),Asc("D"),Asc("F"),Asc("G"),Asc("H"),Asc("J"),Asc("K"),Asc("M"),Asc("P"),Asc("Q"),Asc("R"),Asc("T"),Asc("V"),Asc("W"),Asc("X"),Asc("Y"),Asc("2"),Asc("3"),Asc("4"),Asc("5"),Asc("6"),Asc("7"),Asc("8"),Asc("9"))
		
		Dim nCur  
		Dim sCDKey 
		Dim ilKeyByte
		Dim ilBit  
		
		Dim blnValid
		blnValid = False
		For ilByte = 24 To 0 Step -1 
			'Step through each character in the CD key 
			nCur = 0
			
			For ilKeyByte = 14 To 0 Step -1 
				'Step through each byte in the Product Key 
				nCur = nCur * 256 Xor bProductKey(ilKeyByte) 
				bProductKey(ilKeyByte) = Int(nCur / 24) 
				nCur = nCur Mod 24 
			Next
			If bKeyChars(nCur) <> 66 Then blnValid = True
			sCDKey = Chr(bKeyChars(nCur)) & sCDKey 
			If ilByte Mod 5 = 0 And ilByte <> 0 Then sCDKey = "-" & sCDKey 
		Next
		If blnValid = True Then Exit For
	Next
	sGetWindowsKey = sCDKey 
	
End Function

Function GetOSArchitecture(strComputer)
	Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
	Set colOS = objWMI.ExecQuery("SELECT AddressWidth FROM Win32_Processor",, 48) 
    For Each objOS In colOS 
        intAddressWidth = objOS.AddressWidth
    Next
    GetOSArchitecture = intAddressWidth
End Function

Open in new window

0
Comment
Question by:erwin_miranda
  • 6
  • 4
  • 3
15 Comments
 
LVL 29

Expert Comment

by:fibo
ID: 39286897
It seems that at line 15 you explicitly create a different file for each computer....
0
 

Author Comment

by:erwin_miranda
ID: 39287145
And how do you do that..what about the reading from txt file and how would i get the loction to be printed out in active directory
0
 
LVL 29

Expert Comment

by:fibo
ID: 39287252
OK.
The loop that ends at line 13 should in fact close at thscripte end of the main
0
Space-Age Communications Transitions to DevOps

ViaSat, a global provider of satellite and wireless communications, securely connects businesses, governments, and organizations to the Internet. Learn how ViaSat’s Network Solutions Engineer, drove the transition from a traditional network support to a DevOps-centric model.

 

Author Comment

by:erwin_miranda
ID: 39287260
Come again.
0
 

Author Comment

by:erwin_miranda
ID: 39287265
Are you sure you are looking at the right script..becasue at the end of line 13 says Next, so what you are telling me is that Next should end line 15, is that correct..
0
 
LVL 43

Expert Comment

by:Rob
ID: 39287826
Unless I've missed something this can easily  done like this. First wrap your code in a function say:

Sub OutputStats(strComputer)
... put all your code you've posted above here BUT remove strComputer="."
End Sub
0
 
LVL 43

Accepted Solution

by:
Rob earned 300 total points
ID: 39287828
Then use this code to read from a text file
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Dim fso, MyFile, FileName, TextLine

Set fso = CreateObject("Scripting.FileSystemObject")

' Open the file for output.
FileName = "c:\computers.txt"

' Open the file for input.
Set MyFile = fso.OpenTextFile(FileName, ForReading)

' Read from the file and display the results.
Do While MyFile.AtEndOfStream <> True
    TextLine = MyFile.ReadLine
    OutputStats TextLine
Loop
MyFile.Close

Open in new window

0
 
LVL 29

Expert Comment

by:fibo
ID: 39287829
my point was that currently you loop on computers on lines 11-13.
I suggested that you do not close the loop at line 13 but lots further
0
 
LVL 43

Expert Comment

by:Rob
ID: 39287849
That loop is all the properties of the local computer ie strComputer="." Not a list of other computers so the loop is closed correctly.
The whole script needs to be run for each computer. Ie changing the variable strComputer, or as I suggested above wrapping it in a sub and passing the computer name read from a file while looping through the list of computer names
0
 

Author Comment

by:erwin_miranda
ID: 39295430
What about the finding the location of the computer on active directory within the script..can that be done.
0
 
LVL 43

Expert Comment

by:Rob
ID: 39295450
I'm not sure exactly what property it is and can't test unfortunately as i'm not connected to a domain.  You may want to open another questions regarding this?

As an aside, I've used a good program called LANSweeper that uses WMI to get all the info you'd ever need from your Windows machines.
0
 
LVL 43

Expert Comment

by:Rob
ID: 39295520
This needs to be run from the machine and not remotely but there may be another way to run it remotely:

http://blogs.technet.com/b/heyscriptingguy/archive/2006/12/06/how-can-i-determine-the-ou-the-local-computer-belongs-to.aspx
0
 
LVL 43

Expert Comment

by:Rob
ID: 39413429
Thanks Netminder :)
0

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Sed question 2 100
Need help editing script 3 78
Renaming multiple file extensions using Powershell 4 50
Bartender label printing - switch on and off graphics 3 54
Log files are useful in diagnosing and repairing problems.  This is a list of common log files and their standard locations that I've compiled.   While this is not exhaustive, it is a pretty good list that I've found to be useful.  I may update it f…
This is a little timesaver I have been using for setting up Microsoft Small Business Server (SBS) in the simplest possible way. It may not be appropriate for every customer. However, when you get a situation where the person who owns the server is i…
In this fifth video of the Xpdf series, we discuss and demonstrate the PDFdetach utility, which is able to list and, more importantly, extract attachments that are embedded in PDF files. It does this via a command line interface, making it suitable …
Video by: Mark
This lesson goes over how to construct ordered and unordered lists and how to create hyperlinks.

809 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question