Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Using PowerShell to automate FTP transfers

2,878 views
Skip to first unread message

DavidTM

unread,
Sep 14, 2006, 4:22:02 AM9/14/06
to
I have seen newsgroup messages that discuss how traditional cmd line FTP
scripts can be ported to PowerShell, but these are still using 'cmd'
commands.

I believe that WSH provided no support for FTP.

Is there any new functionality in PowerShell that is provided for automating
FTP transfers?

BR

David

Alex K. Angelopoulos [MVP]

unread,
Sep 14, 2006, 9:01:43 AM9/14/06
to
Inline:

"DavidTM" <Dav...@discussions.microsoft.com> wrote in message
news:0E64185D-1CDC-4052...@microsoft.com...


>I have seen newsgroup messages that discuss how traditional cmd line FTP
> scripts can be ported to PowerShell, but these are still using 'cmd'
> commands.

And that's "OK". :)

There are other ways to do it, but one of the most important things about
scripting environments is that they should allow you to glue in little bits
of functionality without depending on someone rewriting the tools first.

> I believe that WSH provided no support for FTP.

In effect, yeah, although the real story is a bit messy. WSH actually
depended on outside components for heavy lifting, much like PowerShell. In
some areas there were lots of easy-to-use components, in others there
weren't. You could actually use ADO to perform an FTP download from a WSH
script IIRC, for example, but it was pretty clumsy.

> Is there any new functionality in PowerShell that is provided for
> automating
> FTP transfers?

Here's the quick way:
$source = "ftp://ftp.microsoft.com/ResKit/win2000/dureg.zip"
$target = "c:\temp\dureg.zip"
$WebClient = New-Object System.Net.WebClient
$WebClient.DownloadFile($source, $target)

Since it's customary to make these into one-liners as well, here's the way
to make downloading a file into a one-line statement:

(New-Object Net.WebClient).DownloadFile($source, $target)

And here's my script for doing this:

# Copy-WebFile.ps1
Param([string]$Uri, [string]$File, [switch]$Asynchronous)

$webclient = New-Object System.Net.WebClient

if($Asynchronous)
{
$webclient.DownloadFileAsync($Uri, $File)
}
else
{
$webclient.DownloadFile($Uri, $File)
}

DavidTM

unread,
Sep 14, 2006, 9:16:02 AM9/14/06
to
Hi Alex

Thanks very much for your reply. It was very helpful.

BR

David

dreeschkind

unread,
Sep 15, 2006, 11:46:03 AM9/15/06
to
"DavidTM" wrote:

PowerShell has built-in support for loading and using external .NET
assemblies.
I did a quick search on the web for a free .NET based FTP implementation and
some sample code. The implementation by the Indy project was the first that I
found.
I also found some useful sample code for that assembly on codeproject.com.

#http://www.indyproject.org/Sockets/Download/Files/DotNet.de.aspx
#http://www.codeproject.com/dotnet/FTPWinFormClient.asp?df=100&forumid=37923&exp=0&select=971260

I transformed the sample code into PowerShell functions. Basically, these
are very simple wrapper functions for the methods provided by
Indy.Sockets.FTP and are just a prove of concept. They do need some serious
cleanup and some error handling, but I think they are useful to get started.

function Open-FTPConnection($ftphost, $username, $password) {

[void][Reflection.Assembly]::LoadFrom("C:\IndyNet-Daily-20051007\Indy.Sockets.dll")
$ftp = new-object Indy.Sockets.FTP
$ftp.Disconnect()
$ftp.Host = $ftphost
$ftp.Username = $username
$ftp.Password = $password
$ftp.Connect()
$ftp.Passive=$true;
return $ftp
}

function Close-FTPConnection($ftp) {
$ftp.Disconnect();
}

function Draw-DirectoryContents($ftp) {
"Listing directory contents ..";
$ls = new-object System.Collections.Specialized.StringCollection;
$ftp.List($ls, "", $true);
foreach($file in $ls){
$file;
}
Get-FTPCurrentLocation $ftp
"Complete";
}

function Get-FTPCurrentLocation($ftp) {
return $ftp.RetrieveCurrentDir();
}

function Set-ParentLocation($ftp) {
"Changing to Parent Directory ..";
$ftp.ChangeDirUp();
Draw-DirectoryContents;
}

function Download-FTPFile($ftp, $sourceFileName, $targetDir) {
"Downloading {0} into {1}.." -f $sourceFileName, $targetDir;
$ftp.Get($sourceFileName, ($targetDir + $sourceFileName), $true, $false);
"Downloading of {0} into {1} is complete" -f $sourceFileName,
[Environment]::CurrentDirectory;
}

function Upload-FTPFile($ftp, $sourceFileName, $targetDir) {
"Uploading {0} into {1}.." -f $sourceFileName, $targetDir;
$ftp.Put($sourceFileName, ($targetDir + $sourceFileName), $false);
"Uploading of {0} into {1} is complete" -f $sourceFileName, $targetDir;
}

function Process-FTPItem($ftp, [string]$sel) {
[string[]]$fields=[Regex]::Split($sel, " +");
$startField=8; #the file/directory name starts after 8 fields
[string]$name="";

for ($field=$startField; $field -lt $fields.Length; $field++) {
if ($field -eq $startField) {
$temp = ""
} else {
$temp = " "
}
$name += $temp + $fields[$field];
#add aditional space for name split into multiple fields
}

if ($sel[0] -eq 'd') { #directory
"Changing directoy to {0} .." -f $name
$ftp.ChangeDir($name);
Draw-DirectoryContents $ftp #redraw contents after changing directory
} else {
if ($sel[0] -eq '-') { #plain file has '-' as first character
return $name; #return the name of file to download
}
}
}

# with these functions loaded you can do stuff like this:
$f = Open-FTPConnection "localhost" "foo" "bar"
Draw-DirectoryContents $f
Process-FTPItem $f "drw-rw-rw- 1 ftp ftp 0 Jul 02 01:51
test"
$file = Process-FTPItem $f "-rwxrwxrwx 1 ftp ftp 10 Apr 01
10:00 test.dat"
Download-FTPFile $f $file ([Environment]::CurrentDirectory)
Upload-FTPFile $f "C:\myfile.txt" (Get-FTPCurrentLocation $f)
"myfileonftp.txt"
Close-FTPConnection $f


--
greetings
dreeschkind

klu...@xtra.co.nz

unread,
Sep 15, 2006, 1:08:53 PM9/15/06
to
YAY indy!!!.. i love that library (especially coming form a delphi
background)

ftp provider would probably be a very good example provider wouldn't
it?

Karl

Lee Holmes [MSFT]

unread,
Sep 15, 2006, 1:16:26 PM9/15/06
to
Somebody is working on one internally... I'll see if he's comfortable
sharing it when he's done.

--
Lee Holmes [MSFT]
Windows PowerShell Development
Microsoft Corporation
This posting is provided "AS IS" with no warranties, and confers no rights.

<klu...@xtra.co.nz> wrote in message
news:1158340133.6...@h48g2000cwc.googlegroups.com...

dreeschkind

unread,
Sep 15, 2006, 5:55:01 PM9/15/06
to
"Lee Holmes [MSFT]" wrote:

> Somebody is working on one internally... I'll see if he's comfortable
> sharing it when he's done.

Sharing this with the community would be really great!
I'm planning to work on a similar provider and I think I will also face
similar problems, so it might be very helpful to have some more sample code.
How are access rights managed by providers like this? Does New-PSDrive
prompt for username and password in that case? Do I need to run
Remove-PSDrive and New-PSDrive again to 'login' with different credentials?
How are connection timeouts or delays managed? Probably much more questions
to come...
I'm looking forward to this! :)

--
greetings
dreeschkind

Brandon Shell

unread,
Sep 15, 2006, 6:31:17 PM9/15/06
to
Can we provide a Syslog provider to :)
Write-Syslog (Server,Facility,Port,Level,...,msg) = awesome :D

"dreeschkind" <drees...@discussions.microsoft.com> wrote in message
news:F392CB0F-C355-497B...@microsoft.com...

Nick

unread,
Sep 17, 2006, 3:17:01 PM9/17/06
to
I wrote an FTP Provider snapin awhile back; I suspect there's a bug or two
somewhere or other, but it supports copy to/from filesystem, remove, list,
and cache. It also does credentials, although I haven't tested it with
encryption, so I have no idea how well that works.

If you'd like, I can post the code somewhere...

Nick

Alex K. Angelopoulos [MVP]

unread,
Sep 17, 2006, 3:39:38 PM9/17/06
to
Yes. Do, please. :)


"Nick" <Ni...@discussions.microsoft.com> wrote in message
news:154115EE-C0D7-4DE9...@microsoft.com...

Alex K. Angelopoulos [MVP]

unread,
Sep 18, 2006, 10:24:00 AM9/18/06
to
Attachment worked.

This is pretty nifty, Nick. Do you have plans to release it yourself later?
Would you be interested in it becoming part of the PowerShell Community
Extensions project? (hint,hint).

"Nick Howell" <msnews-0....@spamgourmet.com> wrote in message
news:eon3Dcy2...@TK2MSFTNGP02.phx.gbl...
> OK; I'm attaching the files as a zip. (I haven't attached via newsgroup
> before, so I'm not sure if it'll work.)
>
> The files are:
> SnapIn.cs -- just the snapin class
> Howell.PowerShell.Provider.Ftp.dll-Format.ps1xml -- contains formats
> for the types I define (namely, FtpDrive and FtpItem)
> FtpItem.cs -- contains various stuff to deal with FtpDirectory and
> FtpFile; not a whole lot of logic
> FtpDriveInfo.cs -- contains most of the logic, especially w.r.t. the
> connection
> FtpPathData.cs -- a whole bunch of path logic
> ExportProviderCmdlet.cs -- should be named CopyProviderItemCmdlet.cs;
> contains a (hopefully) pretty general abstraction of cross-provider
> copying
> CopyFsToFtp.cs and CopyFtpToFs.cs -- contains internal implementations
> of bi-directional FTP-FS copy support
>
> I think I got all the files. Note that there is at least one bug in it;
> browsing ftp.mozilla.org I got a null-reference exception at one point
> or another. Also, it only works with Unix-style listings, although it
> should be trivial to implement other styles.
>
> If you have any other questions about my implementation, I'll try my
> best to answer them (I wrote this nearly six months ago, and hacked it
> until it worked with later releases of PoSH).
>
> Nick

Nick Howell

unread,
Sep 18, 2006, 11:58:24 AM9/18/06
to
Sure; sounds like a good idea. I'll see if I can't figure out how to get
it in there.

James Truher

unread,
Sep 25, 2006, 9:09:17 PM9/25/06
to
hmmm, I'm attempting to use this now, but the data from the FTP server in
GetChildItemsRemote retuns something that looks like below. Did the data
format change? Any reason why it looks like HTML?

jim

<HTML>
<meta http-equiv="Content-Type" content="text-html; charset=UTF-8">
<HEAD>
<TITLE>FTP root at ftp.gnu.org. </TITLE>
</HEAD>
<BODY>
<H1>FTP root at ftp.gnu.org. </H1>
<HR>
<H4><PRE>
Due to U.S. Export Regulations, all cryptographic software on this
site is subject to the following legal notice:


This site includes publicly available encryption source code
which, together with object code resulting from the compiling of
publicly available source code, may be exported from the United
States under License Exception &quot;TSU&quot; pursuant to 15 C.F.R.
Sectio
n
740.13(e).


This legal notice applies to cryptographic software only. Please see
the Bureau of Industry and Security (www.bxa.doc.gov) for more
information about current U.S. regulations.
</PRE></H4>
<HR>
<PRE>
08/20/04 12:00AM [GMT] 8 <A
HREF="/CRYPTO.README">CRYPTO.README</A>
10/23/03 12:00AM [GMT] 17,864 <A
HREF="/MISSING-FILES">MISSING-FILES</A>
08/13/03 12:00AM [GMT] 4,178 <A
HREF="/MISSING-FILES.README">MISSING-FILES.README</A>
09/18/03 12:00AM [GMT] 17,992 <A
HREF="/MISSING-FILES%7E">MISSING-FILES~</A>
08/16/02 12:00AM [GMT] 2,103 <A HREF="/README">README</A>
08/18/00 12:00AM [GMT] 1,516 <A
HREF="/README.%7E1%7E">README.~1~</A>
10/23/03 12:00AM [GMT] 405,121 <A
HREF="/before-2003-08-01.md5sums.asc">before-2003-08-01.md5sums.asc</A>
09/18/06 03:34PM [GMT] &lt;DIR&gt; <A HREF="/gnu/">gnu</A>
09/23/04 12:00AM [GMT] &lt;DIR&gt; <A
HREF="/gnu+linux-distros/">gnu+linux-distros</A>
02/16/93 12:00AM [GMT] 90 <A HREF="/lpf.README">lpf.README</A>
09/25/06 10:31AM [GMT] 312,781 <A
HREF="/ls-lrRt.txt.gz">ls-lrRt.txt.gz</A>
04/20/05 12:00AM [GMT] &lt;DIR&gt; <A HREF="/mirrors/">mirrors</A>
04/15/04 12:00AM [GMT] 11 <A HREF="/non-gnu">non-gnu</A>
04/03/06 09:47PM [GMT] &lt;DIR&gt; <A HREF="/old-gnu/">old-gnu</A>
08/05/03 12:00AM [GMT] 1 <A HREF="/pub">pub</A>
01/15/04 12:00AM [GMT] &lt;DIR&gt; <A
HREF="/savannah/">savannah</A>
08/02/03 12:00AM [GMT] &lt;DIR&gt; <A
HREF="/third-party/">third-party</A>
08/13/03 12:00AM [GMT] 954 <A HREF="/welcome.msg">welcome.msg</A>
04/10/02 12:00AM [GMT] 849 <A
HREF="/welcome.msg%7E">welcome.msg~</A>
</PRE>
<HR>
</BODY>
</HTML>

--
--
James Truher [MSFT]


Windows PowerShell Development
Microsoft Corporation
This posting is provided "AS IS" with no warranties, and confers no rights.

"Nick Howell" <msnews-0....@spamgourmet.com> wrote in message

Alex K. Angelopoulos [MVP]

unread,
Sep 26, 2006, 7:57:35 AM9/26/06
to
Nick,

Hit me offline if you're having trouble getting into the Codeplex project:
http://www.codeplex.com/Wiki/View.aspx?ProjectName=PowerShellCX

I can go ahead and add the current code if you like as well. ;)

Alex


"Nick Howell" <msnews-0....@spamgourmet.com> wrote in message

news:ulvkctz2...@TK2MSFTNGP02.phx.gbl...

Fred J.

unread,
Sep 26, 2006, 5:47:46 PM9/26/06
to
Alex,
I have been following this thread. I have written functions and
saved the in ps1 files using the name of the function.

You wrote:
(New-Object Net.WebClient).DownloadFile($source, $target)

And here's my script for doing this:
# Copy-WebFile.ps1
Param([string]$Uri, [string]$File, [switch]$Asynchronous)
$webclient = New-Object System.Net.WebClient
if($Asynchronous)
{
$webclient.DownloadFileAsync($Uri, $File)
}
else
{
$webclient.DownloadFile($Uri, $File)

I am not certain how to invoke this script. Is it different than a
function? I do not see the function declaration.
Thank you,
Fred Jacobowitz

Alex K. Angelopoulos [MVP] wrote:

Alex K. Angelopoulos [MVP]

unread,
Sep 28, 2006, 2:11:39 PM9/28/06
to
"Fred J." <swim.in...@gmail.com> wrote in message
news:1159307266....@e3g2000cwe.googlegroups.com...

> I am not certain how to invoke this script. Is it different than a
> function? I do not see the function declaration.
> Thank you,
> Fred Jacobowitz

You can think of the file as providing the "skin" for a PowerShell script.
It can be invoked as pasted if the script file is in your search path.

If you want to have it as a function in your standard configuration script,
you can wrap it up like this:

# Copy-WebFile.ps1
function Copy-WebFile
{

0 new messages