M
Michael R. Mastro II
Hello,
I am trying to modify a script from the Windows 2008 server resource kit
to fit my needs. I am wondering if anyone can help in this effort. Here is
what I have for the script:
'==========================================================================
'
' VBScript Source File -- Created with SAPIEN Technologies PrimalScript 2007
'
' NAME: UDS_UserFolders_Extended_Provision_DFS.vbs
'
' AUTHOR: Dan Holme , Intelliem
' DATE : 11/12/2007
'
' USAGE:
' cscript.exe UDS_UserFolders_Extended_Provision_DFS.vbs UserFolderPath
' [dfs:Y /server:<servername>
' /userfirstname:<first name> /userlastname:<last name>
'
' Creates a physical and DFS namespace for all user data stores.
' See the Windows Administration Resource Kit for documentation
'
' Neither Microsoft nor Intelliem guarantee the performance
' of scripts, scripting examples or tools.
'
' See www.intelliem.com/resourcekit for updates to this script
'
' (c) 2007 Intelliem, Inc
'==========================================================================
' CONFIGURATION BLOCK
' Because configuration is so significant for this script, it has been moved
to
' Sub Configuration ()
Option Explicit
Dim FSO, WSHShell
Dim sUsernameFolder
Dim sUsername, sCommand, sFolder
Dim arr, i, ret
Dim sUserDataServer, sUserFirst, sUserLast
Dim bDFSNamespaceMode, bQuiet
Dim DFSUTIL
Dim sUserDFSNamespace, sUserDataPath
Dim sUserDocsDFSFolder, sUserDocsShareName, sUserDocsPath
Dim sUserDesktopDFSFolder, sUserDesktopShareName, sUserDesktopPath
Dim sUserFavoritesDFSFolder, sUserFavoritesShareName, sUserFavoritesPath
Dim sUserMusicDFSFolder, sUserMusicShareName, sUserMusicPath
Dim sUserPicturesDFSFolder, sUserPicturesShareName, sUserPicturesPath
Dim sUserVideosDFSFolder, sUserVideosShareName, sUserVideosPath
Dim sUserProfileDFSFolder, sUserProfileShareName, sUserProfilePath
Dim sUserProfileV2DFSFolder, sUserProfileV2ShareName, sUserProfileV2Path
Dim sUserBackupsDFSFolder, sUserBackupsShareName, sUserBackupsPath
Dim sDomainNetBIOS, sTemplate_UserData
Dim bInheritanceError
Create_Common_Objects
Check_Arguments
Configuration
Create_Physical_Namespace
If bDFSNamespaceMode Then Create_DFS_Namespace
WScript.Echo sUsernameFolder & " provisioned."
Sub Create_Physical_Namespace()
'
=====================================================================================
' Create physical namespace for %username% folder and the user's data stores
beneath it
' %USERNAME% folder
' Physical path is passed to script as first argument
' and stored in sUsernameFolder variable
' Make sure it exists. If not, create it. If that fails, quit.
If Not FolderPath_Create(sUsernameFolder) Then
WScript.Echo "Folder could not be found and could not be created."
WScript.Quit
End If
' Determine the user name by looking at the last folder in the folder path
sUsername = FSO.GetFolder(sUsernameFolder).Name
' %USERNAME%\Data
' The parent folder of Documents and Desktop
' Create folder if it does not exist and, if successful, apply a quota.
sFolder = sUsernameFolder & "\" & sUserDataPath
If FolderPath_Create( sFolder ) Then
sCommand = "dirquota quota add /path:""" & sFolder & """
/sourcetemplate:""" & sTemplate_UserData & """"
arr = Execute_Capture(sCommand, 10, True)
End If
' %USERNAME%\Data\Documents
sFolder = sUsernameFolder & "\" & sUserDocsPath
If FolderPath_Create( sFolder ) Then
' Management logic here, if any
End If
' %USERNAME%\Data\Desktop
sFolder = sUsernameFolder & "\" & sUserDesktopPath
If FolderPath_Create( sFolder ) Then
' Management logic here, if any
End If
' %USERNAME%\Data\Favorites
sFolder = sUsernameFolder & "\" & sUserFavoritesPath
If FolderPath_Create( sFolder ) Then
' Management logic here, if any
End If
' %USERNAME%\Data\Music
sFolder = sUsernameFolder & "\" & sUserMusicPath
If FolderPath_Create( sFolder ) Then
' Management logic here, if any
End If
' %USERNAME%\Data\Pictures
sFolder = sUsernameFolder & "\" & sUserPicturesPath
If FolderPath_Create( sFolder ) Then
' Management logic here, if any
End If
' %USERNAME%\Data\Videos
sFolder = sUsernameFolder & "\" & sUserVideosPath
If FolderPath_Create( sFolder ) Then
' Management logic here, if any
End If
' %USERNAME%\Backups
sFolder = sUsernameFolder & "\" & sUserBackupsPath
If FolderPath_Create( sFolder ) Then
' Management logic here, if any
End If
' %USERNAME%\Profile
sFolder = sUsernameFolder & "\" & sUserProfilePath
If FolderPath_Create( sFolder ) Then
' Management logic here, if any
End If
' %USERNAME%\Profile.V2
sFolder = sUsernameFolder & "\" & sUserProfileV2Path
If FolderPath_Create( sFolder ) Then
' Management logic here, if any
End If
' INHERITANCE
' Ensure that inheritance is enabled for the %username% folder and the
profile folders
' If the roaming profile created the folder first, it will be off!
' WS2008 code using icacls.exe with the new /inheritance switch
sCommand = "icacls """ & sUsernameFolder & """ /inheritance:e"
arr = Execute_Capture(sCommand, 10, True)
if arr(0) > 0 then bInheritanceError = True
sCommand = "icacls """ & sUsernameFolder & "\" & sUserProfilePath & """
/inheritance:e"
arr = Execute_Capture(sCommand, 10, True)
If arr(0) > 0 then bInheritanceError = True
sCommand = "icacls """ & sUsernameFolder & "\" & sUserProfileV2Path & """
/inheritance:e"
arr = Execute_Capture(sCommand, 10, True)
if arr(0) > 0 then bInheritanceError = True
If bInheritanceError Then
WScript.Echo "There was an error enabling inheritance using icacls.exe." &
VbCrLf & VbCrLf & _
"If you are executing this script from a system that is not running" &
VbCrLf & _
"Windows Server 2008 or Windows Vista SP1, then the error is expected: "
& VbCrLf & _
"older versions of icacls.exe do not support the /inheritance switch." &
VbCrLf & VbCrLf & _
"Once the script is complete, you must check to ensure inheritance is
enabled" &VbCrLf & _
"on the following folders: " & VbCrLf & _
" - " & sUsernameFolder & VbCrLf & _
" - " & sUsernameFolder & "\Profile" & VbCrLf & _
" - " & sUsernameFolder & "\Profile.V2" & VbCrLf & VbCrLf & _
WScript.Echo
End If
' PERMISSIONS AND OWNERSHIP
' We've been creating all of these folders. We need to ensure the user has
full control and owns them.
' First, we give the user full control at the %username% folder.
' Inheritance should be enabled on all subfolders, allowing that permission
to apply down the tree.
sCommand = "icacls """ & sUsernameFolder & """ /grant " & sDomainNetBIOS
&"\" & sUsername & "CI)(OI)F"
arr = Execute_Capture(sCommand, 10, True)
' Log_Command sCommand, arr
' Then we grant ownership to the tree at the end of the routine, so we can
blast ownership down with the /T switch
sCommand = "icacls """ & sUsernameFolder & """ /setowner " & sDomainNetBIOS
&"\" & sUsername & " /T"
arr = Execute_Capture(sCommand, 10, True)
' Log_Command sCommand, arr
End Sub
Sub Create_DFS_Namespace()
'
=====================================================================================
' Create DFS namespace for %username% DFS folder and the user's data stores
beneath it
Dim sUserDFSFolder
' Define the top-level folder for the user within the DFS namespace
sUserDFSFolder = sUserDFSNamespace & "\" & sUsername
' %USERNAME%\Documents
sCommand = """" & DFSUTIL & """ link add " & _
sUserDFSFolder & "\" & sUserDocsDFSFolder & _
" \\" & sUserDataServer & "\" & sUserDocsShareName & _
"\" & sUsername & "\" & sUserDocsPath
arr = Execute_Capture( sCommand, 10, True)
Log_Command sCommand, arr
' %USERNAME%\Desktop
sCommand = """" & DFSUTIL & """ link add " & _
sUserDFSFolder & "\" & sUserDesktopDFSFolder & _
" \\" & sUserDataServer & "\" & sUserDesktopShareName & _
"\" & sUsername & "\" & sUserDesktopPath
arr = Execute_Capture( sCommand, 10, True)
Log_Command sCommand, arr
' %USERNAME%\Favorites
sCommand = """" & DFSUTIL & """ link add " & _
sUserDFSFolder & "\" & sUserFavoritesDFSFolder & _
" \\" & sUserDataServer & "\" & sUserFavoritesShareName & _
"\" & sUsername & "\" & sUserFavoritesPath
arr = Execute_Capture( sCommand, 10, True)
Log_Command sCommand, arr
' %USERNAME%\Music
sCommand = """" & DFSUTIL & """ link add " & _
sUserDFSFolder & "\" & sUserMusicDFSFolder & _
" \\" & sUserDataServer & "\" & sUserMusicShareName & _
"\" & sUsername & "\" & sUserMusicPath
arr = Execute_Capture( sCommand, 10, True)
Log_Command sCommand, arr
' %USERNAME%\Pictures
sCommand = """" & DFSUTIL & """ link add " & _
sUserDFSFolder & "\" & sUserPicturesDFSFolder & _
" \\" & sUserDataServer & "\" & sUserPicturesShareName & _
"\" & sUsername & "\" & sUserPicturesPath
arr = Execute_Capture( sCommand, 10, True)
Log_Command sCommand, arr
' %USERNAME%\Videos
sCommand = """" & DFSUTIL & """ link add " & _
sUserDFSFolder & "\" & sUserVideosDFSFolder & _
" \\" & sUserDataServer & "\" & sUserVideosShareName & _
"\" & sUsername & "\" & sUserVideosPath
arr = Execute_Capture( sCommand, 10, True)
Log_Command sCommand, arr
' %USERNAME%\Profile
sCommand = """" & DFSUTIL & """ link add " & _
sUserDFSFolder & "\" & sUserProfileDFSFolder & _
" \\" & sUserDataServer & "\" & sUserProfileShareName & _
"\" & sUsername & "\" & sUserProfilePath
arr = Execute_Capture( sCommand, 10, True)
Log_Command sCommand, arr
' %USERNAME%\Profile.V2
sCommand = """" & DFSUTIL & """ link add " & _
sUserDFSFolder & "\" & sUserProfileV2DFSFolder & _
" \\" & sUserDataServer & "\" & sUserProfileV2ShareName & _
"\" & sUsername & "\" & sUserProfileV2Path
arr = Execute_Capture( sCommand, 10, True)
Log_Command sCommand, arr
' %USERNAME%\Backups
sCommand = """" & DFSUTIL & """ link add " & _
sUserDFSFolder & "\" & sUserBackupsDFSFolder & _
" \\" & sUserDataServer & "\" & sUserBackupsShareName & _
"\" & sUsername & "\" & sUserBackupsPath
arr = Execute_Capture( sCommand, 10, True)
Log_Command sCommand, arr
' %USERNAME%
' The root DFS folder for the user, %username%, has subfolders
' with targets but does not itself have targets.
' So it cannot be created with DFSUTIL. Instead, it is created
' when a subfoder (with a target) is created.
' Therefore, we have to wait until a subfolder has been created
' to configure the COMMENT property
sCommand = """" & DFSUTIL & """ link comment set " & _
sUserDFSFolder & " """ & sUserLast & ", " & sUserFirst & """"
arr = Execute_Capture( sCommand, 10, True)
End Sub
Sub Create_Common_Objects()
Set FSO = CreateObject("Scripting.FileSystemObject")
Set WSHShell = CreateObject("Wscript.Shell")
End Sub
Sub Check_Arguments()
Dim sDFS
On Error Resume Next
If Right(" " & WScript.Arguments(0),1)="?" Then
Call Usage()
WScript.Quit(0)
End If
sUsernameFolder = WScript.Arguments(0)
If sUsernameFolder = "" Then
WScript.Echo "No parent folder provided"
WScript.Quit(501)
End If
On Error GoTo 0
' Check to see if we're running DFS Namespace creation mode
sDFS = WScript.Arguments.Named("dfs") & " "
bDFSNamespaceMode = (UCase(Left(sDFS,1))="Y")
sUserDataServer = WScript.Arguments.Named("server")
sUserFirst = WScript.Arguments.Named("userfirstname")
sUserLast = WScript.Arguments.Named("userlastname")
If (bDFSNamespaceMode And (sUserDataServer = "")) Then
WScript.Echo "Cannot run in DFS Namespace creation mode:
/server:<servername> argument required."
WScript.Quit(501)
End If
' Default for this script is quiet. Must specify /quiet:N to produce output.
bQuiet = Not(UCase(Left(WScript.Arguments.Named("quiet") & " ", 1)) = "N")
End Sub
Sub Configuration()
' Because the definition of the namespace is such a big block of code,
' it is separated into a Sub, allowing some script editing applications
' to "collapse" the Sub for readability
' It is assumed that namespaces are consistent across systems in a
' user data and settings framework.
' SMB share namespace:
' SHARES: users$, profiles$ and backups$
' all three shares target the same physical <root>
' Physical namespace:
' FOLDERS: <root>
' %username%
' Backups
' Data
' Documents
' Desktop
' Favorites
' Music
' Pictures
' Videos
' Profile
' Profile.V2
' The DFS namespace is created in this structure:
' DFS: <namespace/root>
' %username%
' Backups
' Documents
' Desktop
' Favorites
' Music
' Pictures
' Profile
' Profile.V2
' Videos
' All of the structure and assumptions above can be modified to some
' extent by changing configuration below. Also look at the code
' that *generates* the physical and DFS namespaces based on this
configuration
' if you need to do further customization
' CONFIGURATION BLOCK
' The physical root (e.g. E:\Users) is assumed to already exist, since
' it only has to be created and shared one time.
' Similarly, it is assumed that the root folder has been shared as
' users$ (caching emabled), profiles$ (caching disabled), and backups$
(caching disabled)
'
' The %username% folder is passed to the script as the first argument
' and is stored in the sUsernameFolder variable
' The parent folder in the physical namespace for Documents and Desktop
sUserDataPath = "Data"
' The DFS namespace within which to create the user's folders
' The DFS namespace must be created prior to running this script
sUserDFSNamespace = "\\contoso.com\users"
' DFSNamespace\%username%\Documents targets
\\<server>\users$\%username%\data\Documents
sUserDocsDFSFolder = "Documents"
sUserDocsShareName = "Users$"
sUserDocsPath = "Data\Documents"
' DFSNamespace\%username%\Desktop targets
\\<server>\users$\%username%\data\Desktop
sUserDesktopDFSFolder = "Desktop"
sUserDesktopShareName = "Users$"
sUserDesktopPath = "Data\Desktop"
' DFSNamespace\%username%\Favorites targets
\\<server>\users$\%username%\data\Favorites
sUserFavoritesDFSFolder = "Favorites"
sUserFavoritesShareName = "Users$"
sUserFavoritesPath = "Data\Favorites"
' DFSNamespace\%username%\Music targets
\\<server>\users$\%username%\data\Music
sUserMusicDFSFolder = "Music"
sUserMusicShareName = "Users$"
sUserMusicPath = "Data\Music"
' DFSNamespace\%username%\Pictures targets
\\<server>\users$\%username%\data\Pictures
sUserPicturesDFSFolder = "Pictures"
sUserPicturesShareName = "Users$"
sUserPicturesPath = "Data\Pictures"
' DFSNamespace\%username%\Videos targets
\\<server>\users$\%username%\data\Videos
sUserVideosDFSFolder = "Videos"
sUserVideosShareName = "Users$"
sUserVideosPath = "Data\Videos"
' DFSNamespace\%username%\Profile targets
\\<server>\profiles$\%username%\Profile
sUserProfileDFSFolder = "Profile"
sUserProfileShareName = "Profiles$"
sUserProfilePath = "Profile"
' DFSNamespace\%username%\Profile.V2 targets
\\<server>\profiles$\%username%\Profile.V2
' this is the Windows Vista user profile folder
sUserProfileV2DFSFolder = "Profile.V2"
sUserProfileV2ShareName = "Profiles$"
sUserProfileV2Path = "Profile.v2"
' DFSNamespace\%username%\Backups targets
\\<server>\backups$\%userprofile%\Backups
sUserBackupsDFSFolder = "Backups"
sUserBackupsShareName = "Backups$"
sUserBackupsPath = "Backups"
' Other configuration
' Your domain name
sDomainNetBIOS = "CONTOSO"
' The name of the template you want applied to the user's Data folder
sTemplate_UserData = "1 GB User Data Storage Limit with 100 MB Extension"
' The path to DFSUTIL.exe (include the full path if it is not in the system
path)
' DFSUTIL is installed with the administrative tools for the DFS role
DFSUTIL = "dfsutil.exe"
End Sub
Function FolderPath_Create(FolderPath)
' VERSION 070918
' Creates a folder path specified by FolderPath
' and returns True (success) or False (failure)
'
' Recursively create a folder path
' This is an "inside out" recursion that starts with the lowest level,
' works its way "up" to the nearest ancestor that exists, then
' creates folders down from there as it works its way out of recursions
'
' INPUT: FolderPath: desired folder path
' OUTPUT: FolderPath_Create: TRUE: success
' FALSE: failure
Dim bFolderExists
FolderPath_Create = False
On Error Resume Next
bFolderExists = FSO.FolderExists(FolderPath)
If Err.Number <> 0 Then
' This handles scenarios where a sharename in a UNC doesn't exist.
' I was getting Out of Memory errors on the FolderExists method.
FolderPath_Create = False
Exit Function
End If
If Not bFolderExists Then
' If the folder doesn't exist already, test its parent
' (RECURSIVE CALL TO SELF)
If FolderPath_Create(FSO.GetParentFolderName(FolderPath)) Then
' Create the folder
FolderPath_Create = True
Call FSO.CreateFolder(FolderPath)
End If
Else
' This level of folder does exist
FolderPath_Create = True
End If
End Function
Function Execute_Capture(ByVal sCommand, ByVal iTimeout, ByVal bTerminate)
' VERSION 070918
' Executes command in sCommand
' Times out after iTimeout and (optionally) terminates the process
' Returns exit code, StdOut & StdErr
'
' INPUTS: sCommand: Command to run
' iTimeout: Time (in seconds) to wait for process
' bTerminate: TRUE = terminate process after timeout
' FALSE = return from function
' RETURNS: Execute_Capture: *ARRAY*
' (0): Exit code of command
' 0.01 = timed out but NOT terminated
' 0.99 = timed out and TERMINATED
' (1): StdOut
' (2): StdErr
Dim oExec, iTimer, iExitCode, sOut, sErr
Set oExec = WSHShell.Exec(sCommand)
iTimer = 0
Do While oExec.Status = 0
WScript.Sleep 100
iTimer = iTimer + 100
If (iTimer/1000) > iTimeout Then Exit Do
Loop
If oExec.Status = 0 Then
' Not completed, but timed out
If bTerminate Then
' Terminate
oExec.Terminate
iExitCode = 0.99
Else
' Timeout but do not terminate
iExitCode = 0.01
End If
Else
' Completed
iExitCode = oExec.ExitCode
End If
sOut = oExec.StdOut.ReadAll
sErr = oExec.StdErr.ReadAll
Execute_Capture = Array(iExitCode, sOut, sErr)
End Function
Sub Log_Command(ByVal sCommand, arr)
If Not bQuiet And arr(0) <> 0 Then
WScript.Echo String(80,"-")
WScript.Echo sCommand
WScript.Echo "Exit Code: " & arr(0)
WScript.Echo "STD OUT"
WScript.Echo arr(1)
WScript.Echo "STD ERR"
WScript.Echo arr(2)
WScript.Echo String(80,"-")
WScript.Echo VbCrLf
End If
End Sub
Sub Usage()
WScript.Echo "UDS_UserFolders_Extended_Provision_DFS"
WScript.Echo "======================================"
WScript.Echo "Create user data stores and"
WScript.Echo "fully-enumerated DFS namespace for a user."
WScript.Echo
WScript.Echo "USAGE:"
WScript.Echo " cscript.exe UDS_UserFolders_Extended_Provision_DFS.vbs"
WScript.Echo " UserFolderPath"
WScript.Echo " [/DFS:Y /server:<servername>"
WScript.Echo " /userfirstname:<first name>
/userlastname:<last name>]"
WScript.Echo "WHERE:"
WScript.Echo
WScript.Echo "UserFolderPath"
WScript.Echo "--------------"
WScript.Echo "Full local or network path to a user's folder,"
WScript.Echo "e.g. E:\Users\jfine or \\server01\users$\jfine."
WScript.Echo "The user's folder will be created if it does not already
exist."
WScript.Echo "It is assumed that the last folder in the path (e.g. jfine)
is the user's"
WScript.Echo "pre-Windows 2000 Logon Name. That account must already
exist. It is given"
WScript.Echo "ownership and Full Control of the folder"
WScript.Echo
WScript.Echo "/DFS:Y"
WScript.Echo "Create a fully enumerated DFS namespace for the user."
WScript.Echo "If running in this mode, you also must provide these
parameters:"
WScript.Echo
WScript.Echo "/server:<servername> Server on which the user's data
is located"
WScript.Echo "/userfirstname:<first name> User's first name"
WScript.Echo "/userlastname:<last name> User's last name"
WScript.Echo
WScript.Echo "In DFS namespace mode, the DFSUTIL command must be in the
system path"
WScript.Echo "(%PATH%, e.g. System32). DFSUTIL is installed by the DFS
admin tools."
WScript.Echo
WScript.Echo "Run the script from a Windows Vista SP1 or Windows Server
2008 system."
WScript.Echo
WScript.Echo "Run locally on a Windows Server 2008 server as an
adminsitrator."
WScript.Echo "-or-"
WScript.Echo "Run remotely gainst a Windows Server 2008 or Windows Server
2003 system"
WScript.Echo "as a user with sufficient NTFS permissions to create the
folders,"
WScript.Echo "DFS namespace delegation to create the DFS namespace, and the"
WScript.Echo "Restore Files And Directories user right to transfer
ownership."
End Sub
Now I want to modify it so that the videos, pictures and music go to
different drives and folders than the rest. I would like to have the same
structure on those folders though. Where U:\Users\%username%\ would hold the
documents and others, I would like it to automatically put Videos in
I:\Videos\%username%\videos, and the others in the same structure. This
would all be unnoticable to the user since DFS would take care of the rest.
Any one know how?
I am trying to modify a script from the Windows 2008 server resource kit
to fit my needs. I am wondering if anyone can help in this effort. Here is
what I have for the script:
'==========================================================================
'
' VBScript Source File -- Created with SAPIEN Technologies PrimalScript 2007
'
' NAME: UDS_UserFolders_Extended_Provision_DFS.vbs
'
' AUTHOR: Dan Holme , Intelliem
' DATE : 11/12/2007
'
' USAGE:
' cscript.exe UDS_UserFolders_Extended_Provision_DFS.vbs UserFolderPath
' [dfs:Y /server:<servername>
' /userfirstname:<first name> /userlastname:<last name>
'
' Creates a physical and DFS namespace for all user data stores.
' See the Windows Administration Resource Kit for documentation
'
' Neither Microsoft nor Intelliem guarantee the performance
' of scripts, scripting examples or tools.
'
' See www.intelliem.com/resourcekit for updates to this script
'
' (c) 2007 Intelliem, Inc
'==========================================================================
' CONFIGURATION BLOCK
' Because configuration is so significant for this script, it has been moved
to
' Sub Configuration ()
Option Explicit
Dim FSO, WSHShell
Dim sUsernameFolder
Dim sUsername, sCommand, sFolder
Dim arr, i, ret
Dim sUserDataServer, sUserFirst, sUserLast
Dim bDFSNamespaceMode, bQuiet
Dim DFSUTIL
Dim sUserDFSNamespace, sUserDataPath
Dim sUserDocsDFSFolder, sUserDocsShareName, sUserDocsPath
Dim sUserDesktopDFSFolder, sUserDesktopShareName, sUserDesktopPath
Dim sUserFavoritesDFSFolder, sUserFavoritesShareName, sUserFavoritesPath
Dim sUserMusicDFSFolder, sUserMusicShareName, sUserMusicPath
Dim sUserPicturesDFSFolder, sUserPicturesShareName, sUserPicturesPath
Dim sUserVideosDFSFolder, sUserVideosShareName, sUserVideosPath
Dim sUserProfileDFSFolder, sUserProfileShareName, sUserProfilePath
Dim sUserProfileV2DFSFolder, sUserProfileV2ShareName, sUserProfileV2Path
Dim sUserBackupsDFSFolder, sUserBackupsShareName, sUserBackupsPath
Dim sDomainNetBIOS, sTemplate_UserData
Dim bInheritanceError
Create_Common_Objects
Check_Arguments
Configuration
Create_Physical_Namespace
If bDFSNamespaceMode Then Create_DFS_Namespace
WScript.Echo sUsernameFolder & " provisioned."
Sub Create_Physical_Namespace()
'
=====================================================================================
' Create physical namespace for %username% folder and the user's data stores
beneath it
' %USERNAME% folder
' Physical path is passed to script as first argument
' and stored in sUsernameFolder variable
' Make sure it exists. If not, create it. If that fails, quit.
If Not FolderPath_Create(sUsernameFolder) Then
WScript.Echo "Folder could not be found and could not be created."
WScript.Quit
End If
' Determine the user name by looking at the last folder in the folder path
sUsername = FSO.GetFolder(sUsernameFolder).Name
' %USERNAME%\Data
' The parent folder of Documents and Desktop
' Create folder if it does not exist and, if successful, apply a quota.
sFolder = sUsernameFolder & "\" & sUserDataPath
If FolderPath_Create( sFolder ) Then
sCommand = "dirquota quota add /path:""" & sFolder & """
/sourcetemplate:""" & sTemplate_UserData & """"
arr = Execute_Capture(sCommand, 10, True)
End If
' %USERNAME%\Data\Documents
sFolder = sUsernameFolder & "\" & sUserDocsPath
If FolderPath_Create( sFolder ) Then
' Management logic here, if any
End If
' %USERNAME%\Data\Desktop
sFolder = sUsernameFolder & "\" & sUserDesktopPath
If FolderPath_Create( sFolder ) Then
' Management logic here, if any
End If
' %USERNAME%\Data\Favorites
sFolder = sUsernameFolder & "\" & sUserFavoritesPath
If FolderPath_Create( sFolder ) Then
' Management logic here, if any
End If
' %USERNAME%\Data\Music
sFolder = sUsernameFolder & "\" & sUserMusicPath
If FolderPath_Create( sFolder ) Then
' Management logic here, if any
End If
' %USERNAME%\Data\Pictures
sFolder = sUsernameFolder & "\" & sUserPicturesPath
If FolderPath_Create( sFolder ) Then
' Management logic here, if any
End If
' %USERNAME%\Data\Videos
sFolder = sUsernameFolder & "\" & sUserVideosPath
If FolderPath_Create( sFolder ) Then
' Management logic here, if any
End If
' %USERNAME%\Backups
sFolder = sUsernameFolder & "\" & sUserBackupsPath
If FolderPath_Create( sFolder ) Then
' Management logic here, if any
End If
' %USERNAME%\Profile
sFolder = sUsernameFolder & "\" & sUserProfilePath
If FolderPath_Create( sFolder ) Then
' Management logic here, if any
End If
' %USERNAME%\Profile.V2
sFolder = sUsernameFolder & "\" & sUserProfileV2Path
If FolderPath_Create( sFolder ) Then
' Management logic here, if any
End If
' INHERITANCE
' Ensure that inheritance is enabled for the %username% folder and the
profile folders
' If the roaming profile created the folder first, it will be off!
' WS2008 code using icacls.exe with the new /inheritance switch
sCommand = "icacls """ & sUsernameFolder & """ /inheritance:e"
arr = Execute_Capture(sCommand, 10, True)
if arr(0) > 0 then bInheritanceError = True
sCommand = "icacls """ & sUsernameFolder & "\" & sUserProfilePath & """
/inheritance:e"
arr = Execute_Capture(sCommand, 10, True)
If arr(0) > 0 then bInheritanceError = True
sCommand = "icacls """ & sUsernameFolder & "\" & sUserProfileV2Path & """
/inheritance:e"
arr = Execute_Capture(sCommand, 10, True)
if arr(0) > 0 then bInheritanceError = True
If bInheritanceError Then
WScript.Echo "There was an error enabling inheritance using icacls.exe." &
VbCrLf & VbCrLf & _
"If you are executing this script from a system that is not running" &
VbCrLf & _
"Windows Server 2008 or Windows Vista SP1, then the error is expected: "
& VbCrLf & _
"older versions of icacls.exe do not support the /inheritance switch." &
VbCrLf & VbCrLf & _
"Once the script is complete, you must check to ensure inheritance is
enabled" &VbCrLf & _
"on the following folders: " & VbCrLf & _
" - " & sUsernameFolder & VbCrLf & _
" - " & sUsernameFolder & "\Profile" & VbCrLf & _
" - " & sUsernameFolder & "\Profile.V2" & VbCrLf & VbCrLf & _
WScript.Echo
End If
' PERMISSIONS AND OWNERSHIP
' We've been creating all of these folders. We need to ensure the user has
full control and owns them.
' First, we give the user full control at the %username% folder.
' Inheritance should be enabled on all subfolders, allowing that permission
to apply down the tree.
sCommand = "icacls """ & sUsernameFolder & """ /grant " & sDomainNetBIOS
&"\" & sUsername & "CI)(OI)F"
arr = Execute_Capture(sCommand, 10, True)
' Log_Command sCommand, arr
' Then we grant ownership to the tree at the end of the routine, so we can
blast ownership down with the /T switch
sCommand = "icacls """ & sUsernameFolder & """ /setowner " & sDomainNetBIOS
&"\" & sUsername & " /T"
arr = Execute_Capture(sCommand, 10, True)
' Log_Command sCommand, arr
End Sub
Sub Create_DFS_Namespace()
'
=====================================================================================
' Create DFS namespace for %username% DFS folder and the user's data stores
beneath it
Dim sUserDFSFolder
' Define the top-level folder for the user within the DFS namespace
sUserDFSFolder = sUserDFSNamespace & "\" & sUsername
' %USERNAME%\Documents
sCommand = """" & DFSUTIL & """ link add " & _
sUserDFSFolder & "\" & sUserDocsDFSFolder & _
" \\" & sUserDataServer & "\" & sUserDocsShareName & _
"\" & sUsername & "\" & sUserDocsPath
arr = Execute_Capture( sCommand, 10, True)
Log_Command sCommand, arr
' %USERNAME%\Desktop
sCommand = """" & DFSUTIL & """ link add " & _
sUserDFSFolder & "\" & sUserDesktopDFSFolder & _
" \\" & sUserDataServer & "\" & sUserDesktopShareName & _
"\" & sUsername & "\" & sUserDesktopPath
arr = Execute_Capture( sCommand, 10, True)
Log_Command sCommand, arr
' %USERNAME%\Favorites
sCommand = """" & DFSUTIL & """ link add " & _
sUserDFSFolder & "\" & sUserFavoritesDFSFolder & _
" \\" & sUserDataServer & "\" & sUserFavoritesShareName & _
"\" & sUsername & "\" & sUserFavoritesPath
arr = Execute_Capture( sCommand, 10, True)
Log_Command sCommand, arr
' %USERNAME%\Music
sCommand = """" & DFSUTIL & """ link add " & _
sUserDFSFolder & "\" & sUserMusicDFSFolder & _
" \\" & sUserDataServer & "\" & sUserMusicShareName & _
"\" & sUsername & "\" & sUserMusicPath
arr = Execute_Capture( sCommand, 10, True)
Log_Command sCommand, arr
' %USERNAME%\Pictures
sCommand = """" & DFSUTIL & """ link add " & _
sUserDFSFolder & "\" & sUserPicturesDFSFolder & _
" \\" & sUserDataServer & "\" & sUserPicturesShareName & _
"\" & sUsername & "\" & sUserPicturesPath
arr = Execute_Capture( sCommand, 10, True)
Log_Command sCommand, arr
' %USERNAME%\Videos
sCommand = """" & DFSUTIL & """ link add " & _
sUserDFSFolder & "\" & sUserVideosDFSFolder & _
" \\" & sUserDataServer & "\" & sUserVideosShareName & _
"\" & sUsername & "\" & sUserVideosPath
arr = Execute_Capture( sCommand, 10, True)
Log_Command sCommand, arr
' %USERNAME%\Profile
sCommand = """" & DFSUTIL & """ link add " & _
sUserDFSFolder & "\" & sUserProfileDFSFolder & _
" \\" & sUserDataServer & "\" & sUserProfileShareName & _
"\" & sUsername & "\" & sUserProfilePath
arr = Execute_Capture( sCommand, 10, True)
Log_Command sCommand, arr
' %USERNAME%\Profile.V2
sCommand = """" & DFSUTIL & """ link add " & _
sUserDFSFolder & "\" & sUserProfileV2DFSFolder & _
" \\" & sUserDataServer & "\" & sUserProfileV2ShareName & _
"\" & sUsername & "\" & sUserProfileV2Path
arr = Execute_Capture( sCommand, 10, True)
Log_Command sCommand, arr
' %USERNAME%\Backups
sCommand = """" & DFSUTIL & """ link add " & _
sUserDFSFolder & "\" & sUserBackupsDFSFolder & _
" \\" & sUserDataServer & "\" & sUserBackupsShareName & _
"\" & sUsername & "\" & sUserBackupsPath
arr = Execute_Capture( sCommand, 10, True)
Log_Command sCommand, arr
' %USERNAME%
' The root DFS folder for the user, %username%, has subfolders
' with targets but does not itself have targets.
' So it cannot be created with DFSUTIL. Instead, it is created
' when a subfoder (with a target) is created.
' Therefore, we have to wait until a subfolder has been created
' to configure the COMMENT property
sCommand = """" & DFSUTIL & """ link comment set " & _
sUserDFSFolder & " """ & sUserLast & ", " & sUserFirst & """"
arr = Execute_Capture( sCommand, 10, True)
End Sub
Sub Create_Common_Objects()
Set FSO = CreateObject("Scripting.FileSystemObject")
Set WSHShell = CreateObject("Wscript.Shell")
End Sub
Sub Check_Arguments()
Dim sDFS
On Error Resume Next
If Right(" " & WScript.Arguments(0),1)="?" Then
Call Usage()
WScript.Quit(0)
End If
sUsernameFolder = WScript.Arguments(0)
If sUsernameFolder = "" Then
WScript.Echo "No parent folder provided"
WScript.Quit(501)
End If
On Error GoTo 0
' Check to see if we're running DFS Namespace creation mode
sDFS = WScript.Arguments.Named("dfs") & " "
bDFSNamespaceMode = (UCase(Left(sDFS,1))="Y")
sUserDataServer = WScript.Arguments.Named("server")
sUserFirst = WScript.Arguments.Named("userfirstname")
sUserLast = WScript.Arguments.Named("userlastname")
If (bDFSNamespaceMode And (sUserDataServer = "")) Then
WScript.Echo "Cannot run in DFS Namespace creation mode:
/server:<servername> argument required."
WScript.Quit(501)
End If
' Default for this script is quiet. Must specify /quiet:N to produce output.
bQuiet = Not(UCase(Left(WScript.Arguments.Named("quiet") & " ", 1)) = "N")
End Sub
Sub Configuration()
' Because the definition of the namespace is such a big block of code,
' it is separated into a Sub, allowing some script editing applications
' to "collapse" the Sub for readability
' It is assumed that namespaces are consistent across systems in a
' user data and settings framework.
' SMB share namespace:
' SHARES: users$, profiles$ and backups$
' all three shares target the same physical <root>
' Physical namespace:
' FOLDERS: <root>
' %username%
' Backups
' Data
' Documents
' Desktop
' Favorites
' Music
' Pictures
' Videos
' Profile
' Profile.V2
' The DFS namespace is created in this structure:
' DFS: <namespace/root>
' %username%
' Backups
' Documents
' Desktop
' Favorites
' Music
' Pictures
' Profile
' Profile.V2
' Videos
' All of the structure and assumptions above can be modified to some
' extent by changing configuration below. Also look at the code
' that *generates* the physical and DFS namespaces based on this
configuration
' if you need to do further customization
' CONFIGURATION BLOCK
' The physical root (e.g. E:\Users) is assumed to already exist, since
' it only has to be created and shared one time.
' Similarly, it is assumed that the root folder has been shared as
' users$ (caching emabled), profiles$ (caching disabled), and backups$
(caching disabled)
'
' The %username% folder is passed to the script as the first argument
' and is stored in the sUsernameFolder variable
' The parent folder in the physical namespace for Documents and Desktop
sUserDataPath = "Data"
' The DFS namespace within which to create the user's folders
' The DFS namespace must be created prior to running this script
sUserDFSNamespace = "\\contoso.com\users"
' DFSNamespace\%username%\Documents targets
\\<server>\users$\%username%\data\Documents
sUserDocsDFSFolder = "Documents"
sUserDocsShareName = "Users$"
sUserDocsPath = "Data\Documents"
' DFSNamespace\%username%\Desktop targets
\\<server>\users$\%username%\data\Desktop
sUserDesktopDFSFolder = "Desktop"
sUserDesktopShareName = "Users$"
sUserDesktopPath = "Data\Desktop"
' DFSNamespace\%username%\Favorites targets
\\<server>\users$\%username%\data\Favorites
sUserFavoritesDFSFolder = "Favorites"
sUserFavoritesShareName = "Users$"
sUserFavoritesPath = "Data\Favorites"
' DFSNamespace\%username%\Music targets
\\<server>\users$\%username%\data\Music
sUserMusicDFSFolder = "Music"
sUserMusicShareName = "Users$"
sUserMusicPath = "Data\Music"
' DFSNamespace\%username%\Pictures targets
\\<server>\users$\%username%\data\Pictures
sUserPicturesDFSFolder = "Pictures"
sUserPicturesShareName = "Users$"
sUserPicturesPath = "Data\Pictures"
' DFSNamespace\%username%\Videos targets
\\<server>\users$\%username%\data\Videos
sUserVideosDFSFolder = "Videos"
sUserVideosShareName = "Users$"
sUserVideosPath = "Data\Videos"
' DFSNamespace\%username%\Profile targets
\\<server>\profiles$\%username%\Profile
sUserProfileDFSFolder = "Profile"
sUserProfileShareName = "Profiles$"
sUserProfilePath = "Profile"
' DFSNamespace\%username%\Profile.V2 targets
\\<server>\profiles$\%username%\Profile.V2
' this is the Windows Vista user profile folder
sUserProfileV2DFSFolder = "Profile.V2"
sUserProfileV2ShareName = "Profiles$"
sUserProfileV2Path = "Profile.v2"
' DFSNamespace\%username%\Backups targets
\\<server>\backups$\%userprofile%\Backups
sUserBackupsDFSFolder = "Backups"
sUserBackupsShareName = "Backups$"
sUserBackupsPath = "Backups"
' Other configuration
' Your domain name
sDomainNetBIOS = "CONTOSO"
' The name of the template you want applied to the user's Data folder
sTemplate_UserData = "1 GB User Data Storage Limit with 100 MB Extension"
' The path to DFSUTIL.exe (include the full path if it is not in the system
path)
' DFSUTIL is installed with the administrative tools for the DFS role
DFSUTIL = "dfsutil.exe"
End Sub
Function FolderPath_Create(FolderPath)
' VERSION 070918
' Creates a folder path specified by FolderPath
' and returns True (success) or False (failure)
'
' Recursively create a folder path
' This is an "inside out" recursion that starts with the lowest level,
' works its way "up" to the nearest ancestor that exists, then
' creates folders down from there as it works its way out of recursions
'
' INPUT: FolderPath: desired folder path
' OUTPUT: FolderPath_Create: TRUE: success
' FALSE: failure
Dim bFolderExists
FolderPath_Create = False
On Error Resume Next
bFolderExists = FSO.FolderExists(FolderPath)
If Err.Number <> 0 Then
' This handles scenarios where a sharename in a UNC doesn't exist.
' I was getting Out of Memory errors on the FolderExists method.
FolderPath_Create = False
Exit Function
End If
If Not bFolderExists Then
' If the folder doesn't exist already, test its parent
' (RECURSIVE CALL TO SELF)
If FolderPath_Create(FSO.GetParentFolderName(FolderPath)) Then
' Create the folder
FolderPath_Create = True
Call FSO.CreateFolder(FolderPath)
End If
Else
' This level of folder does exist
FolderPath_Create = True
End If
End Function
Function Execute_Capture(ByVal sCommand, ByVal iTimeout, ByVal bTerminate)
' VERSION 070918
' Executes command in sCommand
' Times out after iTimeout and (optionally) terminates the process
' Returns exit code, StdOut & StdErr
'
' INPUTS: sCommand: Command to run
' iTimeout: Time (in seconds) to wait for process
' bTerminate: TRUE = terminate process after timeout
' FALSE = return from function
' RETURNS: Execute_Capture: *ARRAY*
' (0): Exit code of command
' 0.01 = timed out but NOT terminated
' 0.99 = timed out and TERMINATED
' (1): StdOut
' (2): StdErr
Dim oExec, iTimer, iExitCode, sOut, sErr
Set oExec = WSHShell.Exec(sCommand)
iTimer = 0
Do While oExec.Status = 0
WScript.Sleep 100
iTimer = iTimer + 100
If (iTimer/1000) > iTimeout Then Exit Do
Loop
If oExec.Status = 0 Then
' Not completed, but timed out
If bTerminate Then
' Terminate
oExec.Terminate
iExitCode = 0.99
Else
' Timeout but do not terminate
iExitCode = 0.01
End If
Else
' Completed
iExitCode = oExec.ExitCode
End If
sOut = oExec.StdOut.ReadAll
sErr = oExec.StdErr.ReadAll
Execute_Capture = Array(iExitCode, sOut, sErr)
End Function
Sub Log_Command(ByVal sCommand, arr)
If Not bQuiet And arr(0) <> 0 Then
WScript.Echo String(80,"-")
WScript.Echo sCommand
WScript.Echo "Exit Code: " & arr(0)
WScript.Echo "STD OUT"
WScript.Echo arr(1)
WScript.Echo "STD ERR"
WScript.Echo arr(2)
WScript.Echo String(80,"-")
WScript.Echo VbCrLf
End If
End Sub
Sub Usage()
WScript.Echo "UDS_UserFolders_Extended_Provision_DFS"
WScript.Echo "======================================"
WScript.Echo "Create user data stores and"
WScript.Echo "fully-enumerated DFS namespace for a user."
WScript.Echo
WScript.Echo "USAGE:"
WScript.Echo " cscript.exe UDS_UserFolders_Extended_Provision_DFS.vbs"
WScript.Echo " UserFolderPath"
WScript.Echo " [/DFS:Y /server:<servername>"
WScript.Echo " /userfirstname:<first name>
/userlastname:<last name>]"
WScript.Echo "WHERE:"
WScript.Echo
WScript.Echo "UserFolderPath"
WScript.Echo "--------------"
WScript.Echo "Full local or network path to a user's folder,"
WScript.Echo "e.g. E:\Users\jfine or \\server01\users$\jfine."
WScript.Echo "The user's folder will be created if it does not already
exist."
WScript.Echo "It is assumed that the last folder in the path (e.g. jfine)
is the user's"
WScript.Echo "pre-Windows 2000 Logon Name. That account must already
exist. It is given"
WScript.Echo "ownership and Full Control of the folder"
WScript.Echo
WScript.Echo "/DFS:Y"
WScript.Echo "Create a fully enumerated DFS namespace for the user."
WScript.Echo "If running in this mode, you also must provide these
parameters:"
WScript.Echo
WScript.Echo "/server:<servername> Server on which the user's data
is located"
WScript.Echo "/userfirstname:<first name> User's first name"
WScript.Echo "/userlastname:<last name> User's last name"
WScript.Echo
WScript.Echo "In DFS namespace mode, the DFSUTIL command must be in the
system path"
WScript.Echo "(%PATH%, e.g. System32). DFSUTIL is installed by the DFS
admin tools."
WScript.Echo
WScript.Echo "Run the script from a Windows Vista SP1 or Windows Server
2008 system."
WScript.Echo
WScript.Echo "Run locally on a Windows Server 2008 server as an
adminsitrator."
WScript.Echo "-or-"
WScript.Echo "Run remotely gainst a Windows Server 2008 or Windows Server
2003 system"
WScript.Echo "as a user with sufficient NTFS permissions to create the
folders,"
WScript.Echo "DFS namespace delegation to create the DFS namespace, and the"
WScript.Echo "Restore Files And Directories user right to transfer
ownership."
End Sub
Now I want to modify it so that the videos, pictures and music go to
different drives and folders than the rest. I would like to have the same
structure on those folders though. Where U:\Users\%username%\ would hold the
documents and others, I would like it to automatically put Videos in
I:\Videos\%username%\videos, and the others in the same structure. This
would all be unnoticable to the user since DFS would take care of the rest.
Any one know how?