Archive

Archive for the ‘Scripting’ Category

Powershell – Downloading and extracting Zip files from FTP

December 5th, 2010 2 comments

Recently I had the need to routinely check for zip files on a remote FTP server, if there were new files download them and extract them into a particular directory. Dreading the addition of yet another manual process I set out to build a Powershell script to accomplish this task for me. I had become quickly frustrated with the lack of native FTP support in the .Net framework, I know you could pass the ftp credentials as a parametrized URL and download single files. However, I needed to perform a directory listing to see which files existed and had not been downloaded previously. In my search I came across the Indy Project an Open Source group that wrote and maintains the Indy Sockets library which includes and FTP client socket among other things. I will also distribute the Indy.Sockets library with my script.

In this script the $workingPath refers to the location that you want to store the files after downloading and extracting them. This script provides some basic logging functionality, the log file will be written to C:\FTPUtil\FTPUtil.log.

# Downloads files from an FTP server and unzips them.
# The script will only download new files that have not
# been previously downloaded and extracted into the
# working directory. This can be setup as a scheduled
# task to automate script run-time. Basic logging is
# is written into the FTPUtil.log text file in the 
# application directory.
#
# Created by Dustin Berube on 11/16/2010.
# Requires Indy.Sockets.dll and Mono.Security.dll version=1.0.5000.0
 
# Base Location of Files to work with
$workingPath = 'x:\path\to\your\file\location'
 
# File Extension
$fileExt = '.ZIP' # File extension of file you are downloading.
 
# FTP Information
$ftpDir 	= "/directory"  			# Directory path to folder on ftp server
$ftpServer 	= "ftp.yourserver.com"		# FTP Server address
$ftpUser 	= "username" 				# FTP Username
$ftpPass 	= "password" 				# FTP Password
 
# Application Directory - Usually C:\FTPUtil unless installed to different directory
$appDir = 'C:\FTPUtil'
 
#
# DO NOT CHANGE ANYTHING BELOW THIS LINE
#
 
set-location $workingPath
$shell = new-object -com shell.application
 
function unzip-Files {
	$location = $shell.namespace($workingPath)
	$zipFiles = get-childitem *.zip
 
	if (Test-Path ($workingPath + "\*$fileExt")) {
	foreach ($zipFile in $ZipFiles) {
		$destDirectory = ($workingPath + "\" + $zipFile.name.Trim($fileExt))
		if (!(Test-Path -path $destDirectory)) {
			[IO.Directory]::CreateDirectory($destDirectory) | out-null
			$location = $shell.namespace($destDirectory)
			$zipFolder = $shell.namespace($zipFile.fullname)
 
			$location.copyhere($zipFolder.items())
			((get-date).ToString() + " --- " + $zipFile.name + " extracted to $destDirectory") | out-file "$appDir\FTPUtil.log" -append
		}
	}
	Remove-ZipFiles
	}
	else {
		((get-date).ToString() + " --- NO FILES DOWNLOADED AND UNZIPPED") | out-file "$appDir\FTPUtil.log" -append
	}
}	
 
function Remove-ZipFiles {
	set-location $workingPath
	$location = $shell.namespace($workingPath)
	remove-item "*$fileExt"
}
 
function Open-FTPConnection {
	# Load Indy Sockets Library
	[Reflection.Assembly]::LoadFrom("C:\ftputil\Indy.Sockets.dll") | Out-Null
 
	$ftp = new-object Indy.Sockets.FTP
	$ftp.Disconnect()
 
	# Connect to FTP Server
	$ftp.Host = $ftpServer
	$ftp.Username = $ftpUser
	$ftp.Password = $ftpPass
	$ftp.Connect()
 
	# Set PASV mode
	$ftp.Passive = $true
 
	return $ftp
}
 
function Close-FTPConnection($ftp) {
	$ftp.Disconnect()
}
 
function Download-FTPFile($ftp) {
	$ls = new-object System.Collections.Specialized.StringCollection
	$ftp.List($ls, $ftpDir, $false)
	foreach($file in $ls) {
		$fileName = $file.Trim("$ftpDir/")
		if (!(Test-Path -path ($workingPath + "\" + $fileName.Trim($fileExt)))) {
			 $ftp.Get($file, ($workingPath + "\$fileName"), $true, $false)
			 ((get-date).ToString() + " --- $fileName Downloaded and saved to $workingPath") | out-file "$appDir\FTPUtil.log" -append
		}
	}
}
 
$f = Open-FTPConnection
Download-FTPFile $f 
Close-FTPConnection $f
unzip-Files

After downloading this script, extract the contents to C:\FTPUtil. You can download the FTPUtil script from here http://www.dustinberube.com/files/FTPUtil.zip. As always I take no responsibility for any problems that arise from the use of this script, it has been tested and used in my development and production environments without issue.

Remove Network Printers via WMI

November 29th, 2010 No comments

Earlier this year I needed to migrate all of my users to a new print server. I essentially had two options for removing the old printers. Option one included visiting each workstation and removing the printers manually. The second option, which is the road that I chose was to script the removal of these old printers. I came up with this quick VB Script to accomplish this mundane task.

'Created by Dustin Berube on 3/22/2010 Version 2.0
'Documented on 3/22/2010

' This script will loops through all installed
' network printers on a workstation and removes
' them. Recommend running this as a Logoff script.

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
 
Set colInstalledPrinters =  objWMIService.ExecQuery _
    ("Select * from Win32_Printer Where Network = TRUE")
 
For Each objPrinter in colInstalledPrinters
    objPrinter.Delete_
Next

In my case I ran the script through Group Policy as a log off script. The reasoning for that was at the end of the day I had all my users log off of their workstations (which triggered this script to remove all network printers from their workstations). The next time they logged onto their workstations the new printers were pushed through a different script to map the printers. This script utilizes WMI to query the local workstation and select all network printers from the Win32_Printer object. Once it retrieves a list of printers this script will loop through the printers and delete them one at a time.

As always, I have provided this script “AS-IS”.

Categories: Scripting Tags: ,

Reset Home Folder Permissions

September 28th, 2010 No comments

This week we had an incident occur at work that required all the home directory permissions reset for all users in Active Directory. You basically have two options to reset the permissions do it manually or write a script. Have you thought about which option you would take? Of course you have, a good Systems Administrator would rather write a script to conduct this mundane task. Below is my PowerShell script to add the user back with rights to their directory. It will not overwrite permissions as it uses the default behavior of Windows Server 2003 and Active Directory, which is to have home directories inherit the parent folders NTFS rights.

This script also requires the Active Directory Management pack from Quest Software (free download).

# Load Quest Active Directory Snap-in
add-pssnapin quest.activeroles.admanagement
 
# Get list of users that have home folders on the SAN. Creates an array of objects
$users = get-qaduser -size 1000 | select logonName,homeDirectory | where {$_.homeDirectory -like '\\path\to\users\*'}
 
# Loop through $users array
foreach ($x in $users) {
 
    # Check to see if directory exists. If not write error message to console.
    if (test-path $x.homeDirectory) {
 
        # Build ACL and grant user modify rights to their respective folder. Also propagates the access rule to subfolder and files.
        $acl = get-acl $x.homeDirectory
        $inherit = [System.Security.AccessControl.InheritanceFlags]"ContainerInherit","ObjectInherit"
        $prop = [system.security.accesscontrol.PropagationFlags]"InheritOnly"
        $ar = new-object system.security.accesscontrol.filesystemaccessrule($x.LogonName,"Modify", $inherit, $prop, "Allow")
 
        $acl.SetAccessRule($ar)
 
        # Set ACL on directory
        set-acl $x.homeDirectory $acl
    }
    else {
        write-host $x.homeDirectory "does not exist."
    }    
}
 
write-host "All folder permissions have been changed. Any errors have been listed above."

I hope this script will help someone else accomplish this task.

Create Computer Accounts in Active Directory from text file

September 19th, 2010 4 comments

At work we have a computer deployment coming up where we will need to add computers to the domain. The way our Active Directory structure is based is that all objects (computers, users, printers, and distribution groups) are separated into operational departments. This makes joining computers to the domain and auto-creating the accounts a pain because you constantly have to put the janitor hat on and move the accounts to the proper OU. This script is written in Powershell and requires the Quest Powershell Commands for Active Directory which you can download from here for free.

This script will first check to see if the computer accounts in the text file are located anywhere in the domain, if so it will throw and error and exit. If everything checks out Ok it will create the computer accounts in the specified OU. You will need to run this from an account that has Domain Admin rights or the “Add computers to the domain right”. There are three pieces of information you are prompted for and they are:

  • Path to text-file – needs to be the full path (ie. c:\scripts\computers.txt)
  • Desired OU that you want to create the accounts: input in the format of domain.suffix/path/to/ou
  • Location: Optional, this will fill in the location meta-data for this object. Convenient for indicating the physical location where the computer is located.

As always this script is provided as-is and I am not responsible for any damages or injuries that may result from using this script.

Add Computers to AD success Add Computer to AD error AD Computers in OU

# Creates Active Directory Computers Accounts in the
# specified OU. Reads computer names from a text file
# with one computer name per line. Requires an account
# with Domain Admin  credentials. 
#
# Created by Dustin Berube on 9/18/2010.
# Requires the Quest ActiveRoles Management tools for AD
 
# Load Quest Powershell Snap-in
add-pssnapin quest.activeroles.admanagement
 
# Create pause function to hold the display on screen
function Pause ($Message="Press any key to continue...")
{
    Write-Host -NoNewLine $Message
    $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
    Write-Host ""
}
 
# Obtain import file, OU, and Computer location
$textFile = read-host "Path to text file cotaining computer names"
$ou = read-host "Please enter the OU (Format of domain.suffix/ou/ou)"
$location = read-host "Please Enter the Location"
 
# Load the contents of the text file to an array
$computer = gc $textFile
 
# first check to see if computer accounts already exist with
# the specified name. If not create the account.
$compCheck = get-qadcomputer -Name $computer | select name, dn
$i = 1
 
if ($compCheck -ne $null) {
    write-host "`nERROR: The following Computer Accounts already exist.`n"
    foreach ($x in $compCheck) {
        $obj = new-object psobject
        $obj | add-member noteproperty ComputerAccount $x.name
        $obj | add-member noteproperty DN $x.DN
        write-output $obj;$i++;
    }
    write-host "`nPlease correct the error and run the import script again.`n"
    pause
}    
else {
    write-host "`nSUCCESS: Added the following computer account(s) to this OU`n" $ou "`n"
    foreach ($x in $computer) {
        new-qadcomputer -Name $x -SamAccountName $x -ParentContainer $ou -Location $location
    }
    write-host "`n" # Add blank line before pause
    pause
}

Powershell – Error Querying Win32_Product

September 18th, 2010 No comments

Yesterday while writing a Powershell script to enumerate a specific set of software in our domain I ran into an interesting problem. It appears that after installing Windows Installer 4.5 on a Windows XP Service Pack 3 workstation the Win32_Product class becomes inaccessible. In order to generate this error all you need to do is run a WMI Object query for the Win32_Product class, sample code below.

Get-WmiObject Win32_Product
Error
Number: 0x80041001
Facility: WMI
Description: Generic failure

This error does not exist for Windows Installer 3.1. Another note is that this only becomes an issue if you an installed an application with per-user settings. If you go to this MS knowledge base article you can download the hotfix to resolve the error (email registration required to download hotfix). http://support.microsoft.com/kb/970553

Copy Favorites folder to Home Directory

February 15th, 2010 No comments

This script is designed to copy a user’s favorites folder from their local profile to their home directory. It is useful when you are not implementing roaming profiles and your users migrate to various computers in the office.

Save this script as a .vbs file, you can either incorporate it into an Active Directory Group Policy or execute the script with the cscript command.

As always this script comes with no written or implied warranty. Use at your discretion.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
'Created by Dustin Berube on 1/17/2009

'This script will copy the users favorites to the users folder on the server.

Option Explicit
 
On Error Resume Next
 
Dim objShell, objFSO, objNet, strHomeShare, strUserProfile
 
'Create the shell and file system objects
Set objShell = WScript.CreateObject("WScript.Shell")
set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
Set objNet = WScript.CreateObject("WScript.Network")
 
'Use the Shell Object to retrieve system environment variables
strHomeShare = "\\Server\Share\" & objNet.UserName
strUserProfile = objShell.SpecialFolders("Favorites") 'Local

'Exit if the variables are blank
If strHomeShare = "" Or strUserProfile = "" Then
   objShell.LogEvent 2, "Cannot copy favorites to the server" & vbCRLF & _
   "Error Description: Variables not set"
   Wscript.Quit
End If
 
If objFSO.FolderExists(strHomeShare & "\Favorites") Then
   objFSO.DeleteFolder strHomeShare & "\Favorites"
End If
 
objFSO.CopyFolder strUserProfile,strHomeShare & "\Favorites"
 
If Err Then
   objShell.LogEvent 1, "Cannot copy favorites from " & strUserProfile & _
   " to " & strHomeShare & "\Favorites" & vbCRLF & "Error Description: " & _
   Err.Description
   Err.Clear
Else
   objShell.LogEvent 0, "Favorites successfully copied from " & _
   strUserProfile & " to " & strHomeShare & "\Favorites"   
End If
 
Set objShell = Nothing
Set objFSO = Nothing
Set objNet = Nothing
Categories: Scripting Tags:

VBScript – Delete files Older than X days

February 9th, 2009 No comments

This quick and dirty script will delete all files in a supplied directory older than X number of days. I have used this to clear still images from a surveillance system so it doesn’t fill the entire hard drive.

Warning this script is intended to delete data from a hard drive. Use at your own discretion I am not responsible for any data loss experienced.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
'Created by Dustin Berube 2/9/2009
'Last modified 2/9/2009

Dim fso, f, f1, fc
Set fso = CreateObject("Scripting.FileSystemObject")
Set f = fso.GetFolder("path\to\folder")
Set fc = f.Files
For Each f1 in fc
If DateDiff("d", f1.DateLastModified, Now) > < # of days> Then
f1.Delete
End If
Next
Set fso = Nothing
Set f = Nothing
Set fc = Nothing

Save this as a .vbs file and execute by running cscript filename.vbs

Categories: Scripting Tags: