Hackviking He killed Chuck Norris, he ruled dancing so he took up a new hobby…

24Mar/130

PSC: Move share

shareerrorI have decided what the Power of scripting script should do! If you move a share by moving it in windows explorer the share will stop work. If you move the folder with File System Object from vbscript the share will still be there but will be pointing at the old path that no longer exists. So how to solve this?

I know a few ways that you don't. First attempt was to use the winnt://localhost/lanmanserver/ object to try updating the path of the share. No luck the property is read only!

Next attempt was using WMI instead. Same thing, unable to update the path. So i thought I delete the share and then create it again. Well enough that worked how ever I didn't manage to get the rights for the share to come along to the new one. There is methods to extract the access mask for the share and supply it when creating a new one, so I think it can be solved. I didn't have the time to do so this time and I think I proved my point about the power of scripting.

At the same time I have learned or realized a few things that I didn't thought about. Most scripts I have written in the past has been for controlled environments.  By that I mean a system where a specific task was asked from the script and the run was always with the same parameters. Here I'm writing a script that should run on different versions of the operating system and with several different variables.

So some of the limitations I ran into can be expressed in the words: Access Denied! It was issues with running some of the commands from the script without running it with elevation. This is no issue running it from the command prompt with cscript moveshare.vbs as long as you start the cmd with elevation (right-click and select Run As Administrator). There are ways around this even with the "double-click execution" of scripts that are discussed in detail here.

So the window version of the script is pretty useless with a standard setup. How ever if you run the script with elevation from the cmd you will be able to move shares around on the disk. The script is pretty ruff around the edges and some more error handling and stuff needs to be added. There probably will be solvable to get the share to keep it's access list as well. This script should be seen as a proof of concept.

'********************************************************************************************
'*
'*		Power of scripting challange!	
'*
'*		moveshare.vbs
'*
'*		Purpose: Move a shared folder from one location to another
'*		without losing the share!
'*
'*		Written by Kristofer Källsbo 
'*
'*		http://www.hackviking.com
'*
'********************************************************************************************
Option explicit
Dim FSO

'Get the filesystem object ready
Set FSO = CreateObject("Scripting.FileSystemObject")

'First check if we are running in console mode or window mode
If (InStr(1, WScript.FullName, "cscript", vbTextCompare)) Then
    InitConsole
ElseIf (InStr(1, WScript.FullName, "wscript", vbTextCompare)) Then
    InitWindow
Else
	' Hope this never fires! 🙂
    wscript.echo "How the hell did you start this script?"
End If

'Clean up
Set FSO = Nothing

'Handles the command line run of the script
Sub InitConsole()
	'Check if we have any parameters
	If (Wscript.Arguments.Count < 2) Then
		'Display help
		wscript.echo "Move share script"
		wscript.echo ""
		wscript.echo "Use: cscript moveshare.vbs {source} {destination}"
		wscript.echo ""
		wscript.echo "source = complete path of the shared folder"
		wscript.echo "destination = full path of the folder where the shared folder should be moved"
		wscript.echo ""
		wscript.echo "moveshare.vbs		Kristofer Källsbo	http://www.hackviking.com"
	Else
		'Verrify the parameters
		Dim sourcePath, destPath
		sourcePath = Wscript.Arguments(0)
		destPath = Wscript.Arguments(1)
		
		If Not (FSO.FolderExists(sourcePath)) Then
			'Display error
			wscript.echo "Source path was not found!"
			Exit Sub
		End If
		
		If Not (FSO.FolderExists(destPath)) Then
			'Display error
			wscript.echo "Destination path was not found!"
			
			'End this execution run
			Exit Sub
		End If
		
		'Do the move
		wscript.echo MoveShare(sourcePath, destPath)
	End If
End Sub

'Handles the double click run of the script
Sub InitWindow()
	Dim sourcePath, destPath, msgboxRetval
	
	'Get source path from user
	sourcePath = InputBox("This script will move an entire shared folder to a new location withou losing the share!" & vbNewLine & vbNewLine & "Enter path of share:", "Move Share Script")
	
	'Validate source path
	If (sourcePath = "") Then
		'Display error and end it
		msgboxRetval = MsgBox("Source path not entered or cancel was clicked!", vbOKOnly+vbCritical, "Source path error!")
		Exit Sub
	Else
		'Check that path exists
		If Not (FSO.FolderExists(sourcePath)) Then
			'Display error
			msgboxRetval = MsgBox("Source path was not found!", vbRetryCancel+vbCritical+vbDefaultButton1, "Source path error!") 
			
			'Check if user wants to retry
			If (msgboxRetval = 4) Then
				InitWindow
			End If
			
			'End this execution run
			Exit Sub
		End If
	End if
	
	'Get destination path from user
	destPath = InputBox("Enter destination path of share:", "Move share script")
	
	'Validate destination path
	If (destPath = "") Then
		'Display error and end it
		msgboxRetval = MsgBox("Destination path not entered or cancel was clicked!", vbOKOnly+vbCritical, "Destination path error!")
		Exit Sub
	Else
		'Check that path exists
		If Not (FSO.FolderExists(destPath)) Then
			'Display error
			msgboxRetval = MsgBox("Destination path was not found!", vbRetryCancel+vbCritical+vbDefaultButton1, "Destination path error!") 
			
			'Check if user wants to retry
			If (msgboxRetval = 4) Then
				InitWindow
			End If
			
			'End this execution run
			Exit Sub
		End If
	End If
	
	'We are all good to go, lets move
	wscript.echo MoveShare(sourcePath, destPath)
End Sub	

	
Function MoveShare(sourcePath, destPath)
	Dim retval, objWMI, objInstances, objInstance, sourceFolder, sourceName, AccessMask, AllowMaximum, Caption, Description, MaximumAllowed, Name, shareType, delRetval, objNewShare, createRetval

	'Add a \ to the destpath, making shure it will be treated as a folder
	destPath = destPath & "\"
	
	'Get the shares
	Set objWMI = GetObject("winmgmts://./root\cimv2")
	Set objInstances = objWMI.InstancesOf("Win32_Share",48)
	
	'Get the correct folder path with upper and lower cases
	Set sourceFolder = FSO.GetFolder(sourcePath)
	sourcePath = sourceFolder.Path
	sourceName = sourceFolder.Name
	
	'Get the share
	'On Error Resume Next
	For Each objInstance in objInstances
		If(objInstance.Path = sourcePath) Then
			'Store all the options
			With objInstance
				AccessMask = .AccessMask
				AllowMaximum = .AllowMaximum
				Caption = .Caption
				Description = .Description
				MaximumAllowed = .MaximumAllowed
				Name = .Name
				shareType = .Type
			End With
			
			'Delete the share
			delRetval = objInstance.Delete()
			
			'Check that delete worked
			If Not(delRetval = 0) Then
				retval = "Error: Unable to delete share!" & vbNewLine & "Error code: " & delRetval
				MoveShare = retval
				Exit Function
			End If
		End If
	Next
	On Error Goto 0
	
	'Move the folder
	FSO.MoveFolder sourcePath, destPath
	
	'Setup the share in the new location
	Set objNewShare = objWMI.Get("Win32_Share") 
	createRetval = objNewShare.Create(destPath & sourceName, Name, shareType, MaximumAllowed, Description, null, null)
	
	'Check that the new share was created
	If Not(createRetval = 0) Then
		retval = "Error: New share not created!"
	End If
	
	'Return result
	MoveShare = retval
End Function	
23Mar/130

PSC: Basic script

So the challenge was accepted! Follow it here! One of the conditions was that the script has to perform like a program or command line tool to be exact! But why go for one when you can go for both! Still not sure what the final script will do but I have to detect how the script is started and act accordingly.

I always use Option explicit, makes troubleshooting so much easier!

Option explicit

Check if the script is running from console or windows mode by checkking the WScript.FullName string.

If InStr(1, WScript.FullName, "cscript", vbTextCompare) Then
    InitConsole
ElseIf InStr(1, WScript.FullName, "wscript", vbTextCompare) Then
    InitWindow
Else
	' Hope this never fires! 🙂
    wscript.echo "How the hell did you start this script?"
End If

Sub for handling the command line version. Checks for command line arguments, if none displays help.

Sub InitConsole()
	'Check if we have any parameters
	If Wscript.Arguments.Count = 0 then
		'Display help
		wscript.echo "You didn't supply any command line parameters... At least one parameter is required!"
	Else
		'Verrify the parameters
		wscript.echo "You supplied " & Wscript.Arguments.Count & " arguments!"
	End If
End Sub

Sub for handling if the user double clicks the script...

Sub InitWindow()
	wscript.echo "You are running this by dubble click..."
End Sub

Stay tuned for the next version!

26Feb/130

Script: List users homedir size

I compiled a vbscript that loops through all the sub folders of a given folder and print out the size. The script takes the folder name and searches the Active Directory for a corresponding user. If found it prints the name of the user in the output.

Use:

cscript homedirsize.vbs

Three input boxes will appear...

  1. Path where the homedir folders are located. Ex. d:\home
  2. Width, in characters, of the first output column.
  3. Width, in characters, of the second output column.

Download script here: 

'****************************************************************************************
'
' Name: Homedirsize.vbs
' 
' Retrieves the size of each subdirectory and matches them to an AD account.
' Outputs a list of directories, username and size.
'
' Written by: Kristofer Källsbo
' 2013-02-26 - http://www.hackviking.com
'
'****************************************************************************************
Option explicit
dim path, column1, column2, objRoot, domainname, fso, partline, i, rootFolder, folder

' get path of homedirs
path = inputbox("Enter path of homedirs:")

' get column widths
column1 = Cint(inputbox("Enter width of first output column:"))
column2 = Cint(inputbox("Enter width of second output column:"))

' get the current domain
Set objRoot = GETOBJECT("LDAP://RootDSE")
domainname = objRoot.GET("defaultNamingContext")

' get the file system object
Set fso = CreateObject("Scripting.FileSystemObject")

' print description lines
wscript.echo "homedirsize.vbs runned on " & Date & " - " & Time
wscript.echo ""
wscript.echo LeftJustified("Foldername", column1) & LeftJustified("Username", column2) & "Size (Mb)"

for i = 0 to column1 + column2 + 8
	partline = partline & "-"
next

wscript.echo partline

' start looping all the subfolders
Set rootFolder = fso.GetFolder(path)
For Each folder in rootFolder.SubFolders
	Dim folderSize
	folderSize = folder.Size
			
	wscript.echo LeftJustified(folder.Name, column1) & LeftJustified(FindUser(folder.Name, domainname), column2) & FormatNumber(((folderSize/1024)/1024),2) & " Mb"
Next

Set fso = Nothing

FUNCTION FindUser(BYVAL UserName, BYVAL Domain) 
	Dim cn,cmd,rs
	SET cn = CREATEOBJECT("ADODB.Connection")
	SET cmd = CREATEOBJECT("ADODB.Command")
	SET rs = CREATEOBJECT("ADODB.Recordset")

	cn.open "Provider=ADsDSOObject;"
	
	cmd.activeconnection=cn
	cmd.commandtext="SELECT Name FROM 'LDAP://" & Domain & _
			 "' WHERE sAMAccountName = '" & UserName & "'"
	
	SET rs = cmd.EXECUTE

	IF err<>0 THEN
		FindUser = 2
		wscript.echo "Error connecting to Active Directory Database:" & err.description
	ELSE
		IF NOT rs.BOF AND NOT rs.EOF THEN
     			rs.MoveFirst
     			FindUser = rs.Fields("Name").Value
		ELSE
			FindUser = "N/A"
		END IF
	END IF
	cn.close
END FUNCTION

Function LeftJustified(ColumnValue, ColumnWidth)
   If(ColumnWidth < Len(ColumnValue) OR ColumnWidth = Len(ColumnValue)) then
		LeftJustified = Left(ColumnValue, ColumnWidth - 1) & " "
	else
		LeftJustified = ColumnValue & Space(ColumnWidth - Len(ColumnValue))
	End if
End Function
20Feb/130

Script: NTFS rights on user home directories

Have a normal Windows setup where the user have a home folder on the file server. All the users is connected to there \\fileserver\home$\%username% via GPO on logon. How ever we found that some of the folders had rights that where messed up. So i wrote a quick script that loopes through all folders and checks if there is a user account in the domain if not it will move the directory to __unconnected__ folder. For all know users it uses cacls command to set rights for the user and admins only. If you need something else you can just edit the cacls command before you run it! Script is provided as is and feel free to modify it...

Download script here:

Option Explicit
'ON ERROR RESUME NEXT
Dim path, objRoot, domainname, fso, rootFolder, folder, objShell, intRunError
path = inputbox("Enter path of homedirs:")

' Get current domain
IF domainname = "" THEN
	SET objRoot = GETOBJECT("LDAP://RootDSE")
	domainname = objRoot.GET("defaultNamingContext")
END IF

' Setup FSO connection
Set fso = CreateObject("Scripting.FileSystemObject")
Set rootFolder = fso.GetFolder(path)
Set objShell = WScript.CreateObject( "WScript.Shell" )

' Go through all homedir folders
For Each folder in rootFolder.SubFolders
	if(FindUser(folder.Name, domainname) = 1) Then
		' Folder found reset the permissions
		wscript.echo folder.Name + " - has a user connected! Reseting the permissions..."
		intRunError = objShell.Run("%COMSPEC% /c Echo Y| cacls " & folder.Path & " /t /c /g Administrators:F ""Domain Admins"":F " & folder.Name & ":F", 1, True)
		If intRunError <> 0 Then
			wscript.echo folder.Name + " - ERROR assigning rights!"
			wscript.echo intRunError
		else
			wscript.echo folder.Name + " - Rights asigned!"
		End If
	elseif(FindUser(folder.Name, domainname) = 0) then
		' This folder isn't connected move it
		If(folder.Name <> "__unconnected__") then
			wscript.echo folder.Name + " - doesn't have a user connected! Moving to .\__unconnected__"
			fso.MoveFolder folder.Path, rootFolder.Path + "\__unconnected__\"
		End If
	else
		wscript.echo "ERROR: Connection to AD failed!"
	End If
Next

Set objRoot = Nothing
Set fso = Nothing
Set rootFolder = Nothing
Set objShell = Nothing

' Function to check if user exists
FUNCTION FindUser(BYVAL UserName, BYVAL Domain) 
	Dim cn,cmd,rs
	SET cn = CREATEOBJECT("ADODB.Connection")
	SET cmd = CREATEOBJECT("ADODB.Command")
	SET rs = CREATEOBJECT("ADODB.Recordset")

	cn.open "Provider=ADsDSOObject;"
	
	cmd.activeconnection=cn
	cmd.commandtext="SELECT ADsPath FROM 'LDAP://" & Domain & _
			 "' WHERE sAMAccountName = '" & UserName & "'"
	
	SET rs = cmd.EXECUTE

	IF err<>0 THEN
		FindUser = 2
		wscript.echo "Error connecting to Active Directory Database:" & err.description
	ELSE
		IF NOT rs.BOF AND NOT rs.EOF THEN
     			rs.MoveFirst
     			FindUser = 1
		ELSE
			FindUser = 0
		END IF
	END IF
	cn.close
END FUNCTION
16Apr/102

IIS 7 FTP access denied while uploading files

I got this strange problem yesterday at work. One of our developers was trying to upload files to e new server and he got 500 access denied each time he tried. After he spent hours double checking all the NTFS rights and IIS settings he asked me for help. At the first look I thought the IIS server had been messed up some how. After verifying everything that he told me was OK, after all he is a coder and they usually don't understand servers, I really didn't know what to do next. So I thought about it for a moment and then I started from scratch, checked the entire solution from the bigger picture.

So with the system blueprint in front of me it all started to clear up. The server was situated in our server center across town and all his traffic was passing through a VPN tunnel between our two ISA 2006 servers. The ISA server sets all the FTP rules to "Read-Only" by default but I didn't realise that this was a problem for the VPN site to site tunnel also. After checking the routing rule and then the access rule for the communication between the two networks I found the settings for FTP traffic between the two ISA servers. After I unchecked the "Read-Only" check box for the FTP traffic on the VPN site to site access rule it all worked as designed.