In order to schedule a PowerShell script to run as a scheduled task in Windows Server 2003 you will need to use the following command syntax. I also set the “Start In” directive to the directory that contains the .ps1 file. The command below will cause the script to run in the background and not generate a window while it is running.
C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe -nologo -command "& {path\to\script.ps1}"
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.
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.