Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Write file in Windows Programs folder

by Anonymous Monk
on Jan 24, 2018 at 21:40 UTC ( #1207869=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I do not know Windows quite well, but I cannot write a folder/file in the C:/Programs (x86) folder where normally programs are installed. I guess it has with restrictions to do. The following code works fine with all other $TargetDir folders, exept the "Programs (x86)" where it ends without dying because it creates another folder with the same name.

use strict; use warnings; use File::Copy::Recursive qw(dircopy); my $SourceDir="C:/test"; my $TargetDir="C:/Programs (x86)"; dircopy($SourceDir,$TargetDir) or die("$!\n");

Furthermore, I guess the "Programs (x86)" is called differently depending on the locale. Is there is a way to get it programmatically?

PS: I am trying to create an "updater" for a program. This need to download the newest .exe version from server and replace the existing one.

Replies are listed 'Best First'.
Re: Write file in Windows Programs folder
by stevieb (Canon) on Jan 24, 2018 at 22:26 UTC
    "Is there is a way to get it programmatically?"

    Yep, all of the important directory locations are housed within the system environment variables. In Windows, you can use the set command-line command to see them all, and once you know which one refers to what, here's how you can get at them in Perl (note that the %ENV hash is not limited to Windows):

    use warnings; use strict; my $prog_files_64 = $ENV{ProgramFiles}; my $prog_files_32 = $ENV{'ProgramFiles(x86)'}; print "64-bit: $prog_files_64\n"; print "32-bit: $prog_files_32\n";

    Output:

    64-bit: C:\Program Files 32-bit: C:\Program Files (x86)
Re: Write file in Windows Programs folder
by soonix (Abbot) on Jan 24, 2018 at 22:36 UTC
    • The "real" name of that folder is C:\Program Files (x86), the national language variant is a Junction Point
    • On my system, the name is available to Perl via %ENV, more specifically in $ENV{ProgramFiles(x86)} (no spaces in that name, contains folder name including drive letter and all)
    • Depending on system configuration, not even an Admin User can simply write there → UAC
      Before you panic about UAC, you may want to verify that this isn't a simple case of trying to run from a non-admin account. Right-click on the command prompt icon, RunAs Administrator, and launch your Perl script from there. If it works as an admin user, you can probably code a test for that and tell the user what to do if it fails. (I do most of my Perl in Linux, so I'm probably not the best person to help you with that part).

      If open my $fh, '>', $path or die "Can't open $path: $!\n"; still fails on your programs dir when run as an admin, then you can panic.

        No solution worked. I can not write/copy in the Programs folder. I packed the script in an exe in order to run it as Administrator (do not know how to run a script as Administrator), but nothing is written in the Programs folder.

        However, there are some programs installed in the same folder doing automatic updates, which I guess means automatic replace some files in the installation folder. I am a bit scared of looking into the "writing rights" matter. Just seems to complicated for me.

Re: Write file in Windows Programs folder
by salva (Abbot) on Jan 25, 2018 at 07:54 UTC
    Just in case you are hand coding an installer for a Perl application, let me point you to Win32::Packer.

      Hi, the most correct way to get the "ProgramFiles" Folder would be

      to use Win32::GetFolderPath(FOLDER), where FOLDER is the constant CSIDL_PROGRAM_FILES.

      And yes, it is true that Administrator rights are necessary to write to this Folder, so you have to start your perl program "as Administrator".

      A warning: If you try to write an Installation program using perl, don't do this!

      Use some kind of open source Software like NSIS or WIX to create an Installation package.

        Use some kind of open source Software like NSIS or WIX to create an Installation package

        That's actually what Win32::Packer does. It builds an MSI installer for the Perl application using WIX.

      I'll give definitively a try! I'll need to package scripts in exe/msi in the next future, and I am trying several ways.

Re: Write file in Windows Programs folder
by GrandFather (Sage) on Jan 25, 2018 at 23:29 UTC

    The behavior is by design to help ensure Windows install, update and uninstall processes are robust. Windows takes a pretty full on approach to application management where Mac is fairly hands off (and *nix does whatever it does). There are pros and cons both ways with the Mac approach needing more user management to clean stuff up (if they care) and the Windows approach needing (a lot) more developer care to get the installer right. A lot of the impetus for locking down the conventional application folders on Windows is to make it harder for viruses and other such nasty software.

    Installing and managing software on Windows is pretty heavy going. My module Win32::MSI::HighLevel helps with creating an installer, but it only partially insulates you from the machinery. Tools like WiX are another way of doing the same thing. Win32::MSI::HighLevel is about due for a big clean up of the documentation and better examples so this node may be the nudge I need to do some work!

    Premature optimization is the root of all job security
Re: Write file in Windows Programs folder
by IB2017 (Pilgrim) on Jan 26, 2018 at 08:57 UTC

    Add the following:

    use Win32::RunAsAdmin qw(force);

    This works for me on Windows 10. The user get prompted from indows if the script should be run as Administrator. Copying/Writing should now be allowed. It works for me with your code (without this module it doesn't work for me either). Solution found here.

    This is a working example using Temp folder to download and unzip the original zip file. It downloads the (zip) file to be updated in your program installation folder, it enzip it in your Temo folder and copy it to the final destination.

    #!/usr/bin/perl use strict; use warnings; use Win32::RunAsAdmin qw(force); use LWP::Simple; use Archive::Extract; my $url = 'URL'; my $WindowsProgramfilesDir = $ENV{'PROGRAMFILES(X86)'}; my $WindowsTempDir = $ENV{'TEMP'}; my $InstallationDir = $WindowsProgramfilesDir . "/INSTALLATION_FOLDER" +; my $ZipFile = $WindowsTempDir . '/update.zip'; getstore($url, $ZipFile); my $tempDir=$WindowsTempDir . '/unzippedFolder'; my $x = Archive::Extract->new( archive => $ZipFile ); $x->extract( to => $tempDir ) or die $x->error; use File::Copy::Recursive qw(dircopy); dircopy($tempDir,$InstallationDir) or die("$!\n");

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1207869]
Approved by marto
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (6)
As of 2020-04-03 17:34 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    The most amusing oxymoron is:
















    Results (30 votes). Check out past polls.

    Notices?