http://www.perlmonks.org?node_id=491533
Category: Win32 Stuff
Author/Contact Info grinder on perlmonks
Description:

I need to transfer files from one Windows machine to another. I've always needed to one way or another, over the years, and have always hacked up fragile workarounds, usuall involving batch files, "RunAs" commands, shares using hard-coded drive letters and so on.

All the pieces are already bundled with the Perl distribution, it was just a question of putting them together. This code, then, lays down an approach to the problem in a Perl-only manner.

# copy files to a remote share requiring authentication
#
# This program demonstrates how to find a free drive letter
# on the local machine, setting up the shared connection,
# copying the file over and then tearing down the connection
# afterwards. I hope this helps someone else save the two hours
# it took me to gather all the loose ends together.
#
# copyright (c) David Landgren 2005
#
# This program is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.

use strict;
use warnings;

use Win32::NetResource qw/GetUNCName AddConnection CancelConnection/;
use Win32API::File qw/ CopyFile fileLastError /;

use constant SHARE_NAME => '\\\\remote_svr\\sharename'; # must use bac
+kslashes
use constant USER_NAME  => 'myusername';
use constant PASSWORD   => 'mysekretpassword';

my $drive;
for my $letter ('g' .. 'z' ) {
    my $mapped;
    $drive = "$letter:";
    GetUNCName( $mapped, $drive );
    last if not $mapped;
}

my $share = {
    RemoteName => SHARE_NAME,
    LocalName  => $drive,
};

print "connecting $share->{RemoteName} to $share->{LocalName}\n";
if( not AddConnection( $share, PASSWORD, USER_NAME, 0 )) {
    die "connection error:\n", win32err();
}

for my $file( @ARGV ) {
    print "copying $file\n";
    CopyFile( $file, "$share->{LocalName}$file", 0 )
        or print "\tfailed: " . fileLastError() . "\n";
}

if( not CancelConnection( $share->{LocalName}, 0, 1 )) {
    print "disconnection error:\n", win32err();
}

sub win32err {
    my $err;
    # Win32::GetError($err); -- bug spotted by puploki
    Win32::NetResource::GetError($err);
    Win32::FormatMessage($err);
}
Replies are listed 'Best First'.
Re: Copying files to an authenticated Win32 share
by puploki (Hermit) on Sep 13, 2005 at 13:07 UTC
    Very neat, I always like pure Perl ways of doing stuff. A couple of thoughts:
    • If you don't have a Windows domain (i.e. have a set of disparate boxes in workgroups) then you would need to specify a valid account on the remote machine in the form "remotemachinename\\username".
    • When I ran your code on my machine, I got the following error:
      connecting \\server\share to g: Undefined subroutine &Win32::GetError called at 491533.pl line 54.
      But that could just be me missing something...
    • I'm also a bit twitchy about leaving a password in clear text lying around, but that's just me :)
Re: Copying files to an authenticated Win32 share
by SheridanCat (Pilgrim) on Sep 13, 2005 at 16:32 UTC
    Since you can map UNC pathnames "anonymously", there's really no reason to find a free drive letter. I use the following in a library I wrote:
    sub connect{ my ( $paths, $user, $password, $verbose ) = @_; # Make $paths an array reference, even if it isn't already if ( ref $paths ne "ARRAY") { if( ! ref $paths ){ push my @paths, $paths; $paths = \@paths; }else{ die "You must pass a scalar or array in as first argument +to connect()\n"; } } if( $^O eq 'MSWin32' ){ require Win32::NetResource qw( :DEFAULT GetSharedResources Get +Error AddConnection CancelConnection ); foreach my $path ( @$paths ){ # In case we don't have the leading backslashes, # add them. unless( $path =~ m|^\\{4}| ){ $path =~ s/^\\+//; $path = "\\\\" . $path; } my %resources = ( Scope => RESOURCE_GLOBALNET, Type => RESOURCETYPE_DISK, DisplayType => RESOURCEDISPLAYTYPE_SHARE, RemoteName => $path ); AddConnection( \%resources, $password, $user, 1 ); if( $verbose ){ my $err; GetError( $err ); warn Win32::FormatMessage( $err ); } } }else{ die "Unsupported Operating System: $^O\n"; } }