VBScript教程-第三章. 腳本的組成部分

第三章. 腳本的組成部分

本章重點

 

從你開始使用Windows系統開始, 就必須學習使用各種Windows的組成元素, 例如如何最小化, 如何使用鼠標等等. 腳本語言也是一樣的, 在本章中你將學習到如何去分析一個腳本以及關於腳本組成的一些術語.

 

每本書都要有一個結構. 例如這個教程, 包括了一些介紹性的章節. 本教程大部分的章節用在瞭解釋性的章節和示例. 還有一個附錄, 一個索引和目錄. 所有這些基本元素共同組成了教程.

 

同樣的腳本也要有一個結構. 腳本的主體有些像一個目錄, 一個告訴你腳本將怎樣工作的組織結構. 函數和Subroutine(請原諒, 我是在不知道該如何用中文定義他)實際上就是一個腳本實際工作的部分, 就像書中的章節一樣. 還有一些命令和文本, 它們就像索引一樣幫助你理解腳本代碼.

 

真的需要知道這些看起來很枯燥的東西才能完成我們自己的腳本嗎? 其實也不是. 實際上, 如果你的目標是儘快開始編寫腳本, 那麼我推薦你直接等待下一章教程吧. 但是, 更好的理解腳本的結果, 可以使你的腳本有更高的可讀性和可用性, 畢竟磨刀不誤砍柴工.

 

一個典型的腳本

 

下面的腳本作爲本章使用的示例腳本. 實際上這是一個提前出現的腳本, 在下一章中你會看到各種各樣的腳本. 現在, 大家先不過多考慮這個腳本是如何工作的, 只要考慮它是什麼樣子的就可以了.

腳本: LoginScript.vbs 在本章中我們都將使用這個示例.

'Display Message

MsgBox "Welcome to BrainCore.Net. You are now logged on."

'Map N: Drive

If IsMemberOf("Domain Users") Then

MapDrive("N:","\\Server\Users")

End If

'Map S: Drive

If IsMemberOf("Research") Then

MapDrive("R:","\\Server2\Research")

End If

'Map R: Drive

If IsMemberOf("Sales") Then

MapDrive("S:","\\Server2\SalesDocs")

End If

'Get IP address

sIP = GetIP()

'Figure out 3rd octet

iFirstDot = InStr(0,sIP,".")

iSecondDot = InStr(iFirstDot+1,sIP,".")

iThirdDot = InStr(iSecondDot+1,sIP,".")

sThirdOctet = Mid(sIP, iSecondDot+1, _

Len(sIP)-iThirdDot)

'Map printer based on octet

Select Case sThirdOctet

Case "100"

MapPrinter "\\NYDC\HPColor3"

Case "110"

MapPrinter "\\LADC\HP6"

Case "120"

MapPrinter "\\TXDC1\LaserJet"

End Select

'--------------------------------------------

' FUNCTIONS

'--------------------------------------------

Sub MapDrive(sLetter, sUNC)

Set oNet = WScript.CreateObject("WScript.Network")

oNet.MapNetworkDrive sLetter, sUNC)

End Sub

Function GetIP()

Set myObj = GetObject("winmgmts:" & _

"{impersonationLevel=impersonate}" & _

"!//localhost".ExecQuery _

("select IPAddress from " & _

"Win32_NetworkingAdapterConfiguration" & _

" where IPEnabled=TRUE")

'Go through the addresses

For Each IPAddress in myObj

If IPAddress.IPAddress(0) <> "0.0.0.0" Then

LocalIP = IPAddress.IPAddress(0)

Exit For

End If

Next

GetIP = LocalIP

End Function

Sub MapPrinter(sUNC)

Set oNet = WScript.CreateObject("WScript.Network")

oNet.AddWindowsPrinterConnection sUNC

oNet.SetDefaultPrinter sUNC

End Sub

Function IsMemberOf(sGroupName)

Set oNetwork = CreateObject("WScript.Network")

sDomain = oNetwork.UserDomain

sUser = oNetwork.UserName

bIsMember = False

Set oUser = GetObject("WinNT://" & sDomain & "/" & _

sUser & ",user")

For Each oGroup In userObj.Groups

If oGroup.Name = sGroupName Then

bIsMember = True

Exit For

End If

Next

IsMemberOf = bIsMember

End Function

 

請注意這個腳本不是爲了運行而編寫的(下一章你就會知道他是如何工作的以及需要對其做哪些更改). 相反, 這個腳本僅僅是爲展示一個好的腳本結構是什麼樣的.

函數

函數是腳本工作的重要組成部分. 函數執行一系列操作, 並返回結果給腳本主體. 例如, VBScript中有一個內置的Date()函數來返回當前的日期.

在你編寫腳本時會用到很多內置函數以及自定義函數. 它們之間實際上沒有太多的差異, 差別只是內置函數是微軟些的自定義函數是你自己寫的. 示例腳本中就有一些自定義函數.

Function GetIP()

Set myObj = GetObject("winmgmts:" & _

"{impersonationLevel=impersonate}" & _

"!//localhost".ExecQuery _

("select IPAddress from " & _

"Win32_NetworkingAdapterConfiguration" & _

" where IPEnabled=TRUE")

'Go through the addresses

For Each IPAddress in myObj

If IPAddress.IPAddress(0) <> "0.0.0.0" Then

LocalIP = IPAddress.IPAddress(0)

Exit For

End If

Next

GetIP = LocalIP

End Function

Function IsMemberOf(sGroupName)

Set oNetwork = CreateObject("WScript.Network")

sDomain = oNetwork.UserDomain

sUser = oNetwork.UserName

bIsMember = False

Set oUser = GetObject("WinNT://" & sDomain & "/" & _

sUser & ",user")

For Each oGroup In oUser.Groups

If oGroup.Name = sGroupName Then

bIsMember = True

Exit For

End If

Next

IsMemberOf = bIsMember

End Function

你會發現, 所有這些函數開始時都會聲明函數名的. 它們也可以接受參數的輸入, 就像IsMemberOf 這個函數一樣, 括號中的sGroupName 就是參數. 函數是有返回值的, 在每一個函數的最後一行都有 函數名=變量 這樣的語句, 當然這些函數的返回動作也是可以返回其他變量或者常量的.

如果你無法理解上一段話, 不用擔心. 從現在開始, 只要知道一些函數關鍵字就可以了, 在以後的章節中會有很詳細的說明.

爲什麼要使用函數呢? 函數的本質是讓腳本有更高的可用性, 就像示例中的IsMemberOf一樣, 它告訴我們當前用戶是不是一個指定域的成員. 實際上這花了整整幾個小時才弄清楚這個不起眼的小把戲, 但是在未來我們可以使用複製就可以輕鬆的在其他腳本中引用這個函數了, 也就是說省了幾個小時的時間. 把一些功能整理成函數是很必要的, 它讓我們很輕鬆的應付艱難的工作.

Subroutines

示例腳本中有兩個Subroutine. 它們看起來很想上一節所說的函數, 但是Subroutine僅僅是執行並沒有返回值.

Sub MapDrive(sLetter, sUNC)

Set oNet = WScript.CreateObject("WScript.Network")

oNet.MapNetworkDrive sLetter, sUNC)

End Sub

Sub MapPrinter(sUNC)

Set oNet = WScript.CreateObject("WScript.Network")

oNet.AddWindowsPrinterConnection sUNC

oNet.SetDefaultPrinter sUNC

End Sub

這些Subroutine是以Sub關鍵字定義的. 和函數一樣, 這兩個Subroutine也可以接受參數. 與函數不同的是Subroutine一定不是一個具體的數值, 因爲它們根本沒有返回值.

VBScript有內置的Subroutine. 例如Beep(), 它僅僅是製造電腦提示音.

Subroutine和函數的本質是一樣的: 雖然映射網絡驅動器或打印機並不是意見難事, 幾行代碼就能實現, 但是我們沒有理由反覆的輸入代碼. 製作成一個Subroutine很明顯的會提升我們的工作效率.

腳本主體

實際上這裏說的基本就是整個腳本.

'Display Message

MsgBox "Welcome to BrainCore.Net. You are now logged on."

'Map N: Drive

If IsMemberOf("Domain Users") Then

MapDrive("N:","\\Server\Users")

End If

'Map S: Drive

If IsMemberOf("Research") Then

MapDrive("R:","\\Server2\Research")

End If

'Map R: Drive

If IsMemberOf("Sales") Then

MapDrive("S:","\\Server2\SalesDocs")

End If

'Get IP address

sIP = GetIP()

'Figure out 3rd octet

iFirstDot = InStr(0,sIP,".")

iSecondDot = InStr(iFirstDot+1,sIP,".")

iThirdDot = InStr(iSecondDot+1,sIP,".")

sThirdOctet = Mid(sIP, iSecondDot+1, _

Len(sIP)-iThirdDot)

'Map printer based on octet

Select Case sThirdOctet

Case "100"

MapPrinter "\\NYDC\HPColor3"

Case "110"

MapPrinter "\\LADC\HP6"

Case "120"

MapPrinter "\\TXDC1\LaserJet"

End Select

腳本的主體是一個有序的排列, 組織整個腳本的執行流. 請注意示例中的MapDrive和MapPrinter的使用, 以及IsMemberOf和GetIP這兩個函數的使用. 腳本主體還利用了一些VBScript的內置功能, 如InStr()和MID().

接下來會介紹一些腳本主體的組成部分.

使用自定義函數和Subroutine

在哪些地方調用了自定義的函數和Subroutine? 我會用加粗的字體來標註.

'Display Message

MsgBox "Welcome to BrainCore.Net. You are now logged on."

'Map N: Drive

If IsMemberOf("Domain Users") Then

MapDrive("N:","\\Server\Users")

End If

'Map S: Drive

If IsMemberOf("Research") Then

MapDrive("R:","\\Server2\Research")

End If

'Map R: Drive

If IsMemberOf("Sales") Then

MapDrive("S:","\\Server2\SalesDocs")

End If

'Get IP address

sIP = GetIP()

'Figure out 3rd octet

iFirstDot = InStr(0,sIP,".")

iSecondDot = InStr(iFirstDot+1,sIP,".")

iThirdDot = InStr(iSecondDot+1,sIP,".")

sThirdOctet = Mid(sIP, iSecondDot+1, _

Len(sIP)-iThirdDot)

'Map printer based on octet

Select Case sThirdOctet

Case "100"

MapPrinter "\\NYDC\HPColor3"

Case "110"

MapPrinter "\\LADC\HP6"

Case "120"

MapPrinter "\\TXDC1\LaserJet"

End Select

你可以看到函數和Subroutine節省了大量的代碼和控件. 就像如果沒有函數IsMemberOf, 這個腳本將不堪入目.

'Display Message

MsgBox "Welcome to BrainCore.Net. You are now logged on."

'Map N: Drive

Set oNetwork = CreateObject("WScript.Network")

sDomain = oNetwork.UserDomain

sUser = oNetwork.UserName

Set oUser = GetObject("WinNT://" & sDomain & "/" & _

sUser & ",user")

For Each oGroup In oUser.Groups

If oGroup.Name = "Domain Users" Then

MapDrive("N:","\\Server\Users")

Exit For

End If

Next

'Map R: Drive

For Each oGroup In oUser.Groups

If oGroup.Name = "Research" Then

MapDrive("R:","\\Server2\ResearchDocs")

Exit For

End If

Next

'Map S: Drive

For Each oGroup In oUser.Groups

If oGroup.Name = "Sales" Then

MapDrive("S:","\\Server2\SalesDocs")

Exit For

End If

Next

'Get IP address

sIP = GetIP()

'Figure out 3rd octet

iFirstDot = InStr(0,sIP,".")

iSecondDot = InStr(iFirstDot+1,sIP,".")

iThirdDot = InStr(iSecondDot+1,sIP,".")

sThirdOctet = Mid(sIP, iSecondDot+1, _

Len(sIP)-iThirdDot)

'Map printer based on octet

Select Case sThirdOctet

Case "100"

MapPrinter "\\NYDC\HPColor3"

Case "110"

MapPrinter "\\LADC\HP6"

Case "120"

MapPrinter "\\TXDC1\LaserJet"

End Select

正如你所看到的一樣, 這個腳本沒有把重複使用的代碼整理成一個函數. 假設在你編寫腳本時發現Bug, 如果腳本中有函數你只需要修複函數中的代碼即可, 如果沒有函數你將不得不在很多的代碼中到處尋找需要修復的語句. 假設所有的For Each oGroup in oUser.Groups. 這一段都有問題. 在我們的示例中, 只需要修復IsMemberOf()函數即可. 在我上面的沒有函數的腳本中就不得不修復三處不連續的代碼.

使用內置函數

腳本中都有哪裏使用了內置函數? 我會讓加粗的字體來告訴你.

'Display Message

MsgBox "Welcome to BrainCore.Net. You are now logged on."

'Map N: Drive

If IsMemberOf("Domain Users") Then

MapDrive("N:","\\Server\Users")

End If

'Map S: Drive

If IsMemberOf("Research") Then

MapDrive("R:","\\Server2\Research")

End If

'Map R: Drive

If IsMemberOf("Sales") Then

MapDrive("S:","\\Server2\SalesDocs")

End If

'Get IP address

sIP = GetIP()

'Figure out 3rd octet

iFirstDot = InStr(0,sIP,".")

iSecondDot = InStr(iFirstDot+1,sIP,".")

iThirdDot = InStr(iSecondDot+1,sIP,".")

sThirdOctet = Mid(sIP, iSecondDot+1, _

 

Len(sIP)-iThirdDot)

'Map printer based on octet

Select Case sThirdOctet

Case "100"

MapPrinter "\\NYDC\HPColor3"

Case "110"

MapPrinter "\\LADC\HP6"

Case "120"

MapPrinter "\\TXDC1\LaserJet"

End Select

大家應該可以看出這些內置的函數在腳本中是沒有類似於自定義函數的定義語句的. 如果你對內置函數很感興趣, 那麼多多查閱VBScript的幫助文檔, 或者期待我們下面的章節吧.

腳本的註釋說明

註釋並說明一下你的腳本代碼是一個很好的主意. 雖然在你編寫腳本時感覺腳本是完美的易讀的, 但是一年以後, 甚至幾個月後再找出這個腳本的時候.你有可能就不這樣認爲了.

看看下面的腳本, 你知道它每部分的功能嗎?

腳本: AddUsersFromXLS.vbs 這個腳本是從Excel中讀取用戶並自動創建.

 

Set oCN = CreateObject("ADODB.Connection")

oCN.Open "Excel"

Set oRS = oCN.Execute("SELECT * FROM [Sheet1$]")

Set oDomain = GetObject("WinNT://NT4PDC")

Set oFSO = CreateObject("Scripting.FileSystemObject")

Set oTS = oFSO.CreateTextFile("c:\passwords.txt",True)

sHomePath = "\\iridis1\c$\users\"

Do Until oRS.EOF

sUserID = oRS("UserID")

sFullName = oRS("FullName")

sDescription = oRS("Description")

sHomeDir = oRS("HomeDirectory")

sGroups = oRS("Groups")

sDialIn = oRS("DialIn")

sPassword = Left(sUserID,2) & DatePart("n",Time) & _

DatePart("y",Date) & DatePart("s",Time)

Set oUserAcct = oDomain.Create("user",sUserID)

oUserAcct.SetPassword sPassword

oUserAcct.FullName = sFullName

oUserAcct.Description = sDescription

oUserAcct.HomeDirectory = sHomeDir

If sDialIn = "Y" Then

oUserAcct.RasPermissions = 9

Else

oUserAcct.RasPermissions = 1

End If

oUserAcct.SetInfo

Set oUserAcct = GetObject("WinNT://NT4PDC/" & sUserID & ",user")

oTS.Write sUserID & "," & sPassword & vbCrLf

sGroupList = Split(sGroups, ",")

For iTemp = 0 To uBound(sGroupList)

Set oGroup = GetObject("WinNT://NT4PDC/" & _

sGroupList(iTemp) & ",group")

oGroup.Add oUserAcct.ADsPath

Set oGroup = Nothing

Next

Set oFolder = oFSO.CreateFolder(sHomePath & sUserID)

Set oUserAcct = Nothing

oRS.MoveNext

Loop

oRS.Close

oTS.Close

WScript.Echo "Passwords have been written to c:\passwords.txt."

是不是很難找到每行每段的功能? 那麼我們來看一下下面的腳本吧.

腳本: AddUsersFromXLS-Comments.vbs

' PART 1: 打開Excel表

' using ActiveX Data Objects

Dim oCN

Set oCN = CreateObject("ADODB.Connection")

oCN.Open "Excel"

Dim oRS

Set oRS = oCN.Execute("SELECT * FROM [Sheet1$]")

' PART 2: 使用ADSI從Windows域中獲取信息

Dim oDomain

Set oDomain = GetObject("WinNT://NT4PDC")

' PART 3: 打開輸出文件

' to store users' initial passwords

Dim oFSO, oTS

Set oFSO = CreateObject("Scripting.FileSystemObject")

Set oTS = oFSO.CreateTextFile("c:\passwords.txt",True)

' PART 4: 在recordset中輪詢每個對象,

' 添加中胡, 設置正確的帳號屬性

' 添加用戶到設當的組中

' 創建必要的用戶變量

Dim sUserID, sFullName, sDescription

Dim sHomeDir, sGroups, sDialIn

Dim sPassword, oUserAcct, oFolder

Dim sGroupList, iTemp, oGroup

' 定義帳號定義基本的Home路徑

' directories to be created in

Dim sHomePath

sHomePath = "\\iridis1\c$\users\"

' 指針移動到recordset的第一行

Do Until oRS.EOF

' 獲取帳號的信息

sUserID = oRS("UserID")

sFullName = oRS("FullName")

sDescription = oRS("Description")

sHomeDir = oRS("HomeDirectory")

sGroups = oRS("Groups")

sDialIn = oRS("DialIn")

' 設定新密碼

sPassword = Left(sUserID,2) & DatePart("n",Time) & _

DatePart("y",Date) & DatePart("s",Time)

' 創建用戶帳號

Set oUserAcct = oDomain.Create("user",sUserID)

' 設置用戶屬性

oUserAcct.SetPassword sPassword

oUserAcct.FullName = sFullName

oUserAcct.Description = sDescription

oUserAcct.HomeDirectory = sHomeDir

' 設定RAS權限

If sDialIn = "Y" Then

oUserAcct.RasPermissions = 9

Else

oUserAcct.RasPermissions = 1

End If

' 保存並提交帳號信息

oUserAcct.SetInfo

' 獲取新帳號的信息

' 獲取可用的SID和其他信息

Set oUserAcct = GetObject("WinNT://NT4PDC/" & _

sUserID & ",user")

' 密碼寫入到文本中

oTS.Write sUserID & "," & sPassword & vbCrLf

' PART 4A: 添加用戶到組

' 是用 Split函數分割出組的列表寫如到數組中

sGroupList = Split(sGroups, ",")

' 通過數組把用戶添加到各個組中

For iTemp = 0 To uBound(sGroupList)

' 獲取組的對象

Set oGroup = GetObject("WinNT://NT4PDC/" & _

sGroupList(iTemp) & ",group")

' 添加用戶帳號

oGroup.Add oUserAcct.ADsPath

' 釋放組的對象

Set oGroup = Nothing

Next

' PART 4B: 創建帳號的 Home目錄

' (引用UserID設定路徑變量)

Set oFolder = oFSO.CreateFolder(sHomePath & sUserID)

' PART 5: 完成

' 釋放帳號對象

Set oUserAcct = Nothing

' 指針移動到recordset的最後

oRS.MoveNext

Loop

' PART 6: 關閉連接.

oTS.CloseoRS.Close

WScript.Echo "Passwords have been written to c:\passwords.txt."

怎麼樣? 知道這個腳本的每一段都是做什麼的了吧? 那些用’開頭的文字就是註釋.

實際上VBScript本身並不關心這些註釋, 這些註釋對程序執行完全沒有影響, 但是我認爲一個好的腳本還是要使用註釋的, 理由是什麼? 當你積累一段時間的腳本後你自然就明白了.

本章總結

本章只是介紹腳本的組成部分, 大家都記下了吧? 沒記下沒關係, 實際上本章想說的就是如何讓你的腳本有更高的可用性, 移植性行, 和可讀性, 你只要記住你的腳本要有這些特徵就可以了. 畢竟這些對腳本的執行沒有太大的關係, 只是一些概念性的東西而已.

接下來的內容

哈哈, 已經忽悠大家3章的內容了, 每一章的最後我都會說下一章就會開始真正的腳本了. 這裏我承認自己實際上是在說謊的, 但是目的僅僅是讓大家有興趣學習這些概念性的東西. 下一章我保證我們真的要開始了……Come on script guys.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章