PowerShell: Backup documents on Dropbox securely with encryption

Like many other people out there, you’re probably looking for a way to backup your documents regularly, reliably, and securely on some sort of central storage service. Dropbox is a great option for this, since they provide a fair amount of storage for free, and their annual cost for additional storage is pretty fair. Unfortunately, there have been wide reports of privacy concerns around Dropbox’s ability to release information to the government, which are concerns that I also share. That’s alright though, because as we’ll see, we can still use the service to securely backup our files.

Advertisement: Please take a moment to check out Arvixe PersonalClassASP web hosting!

Since we cannot confidently store our files on Dropbox in plain sight, we should ensure that they are encrypted before they’re transferred to the backup service. There are built-in capabilities to encrypt files in Windows, but I prefer the security and performance of the popular, open-source 7-Zip application. 7-Zip is an ideal tool for compressing and encrypting documents, because it is fast, uses secure AES-256 encryption, and offers the option to encrypt the compressed file headers. The last option I mentioned is important to  prevent people from reading the file names inside the archive; by default, 7-Zip only encrypts the document data, and not the document metadata.

7-Zip is only part of the equation, however. We need to schedule these backup jobs to run on a regular schedule so that we are constantly getting up-to-date backups. Additionally, we may desire to add multiple folder paths to add to a single zip file, which isn’t easily done using 7-Zip by itself. This is where Microsoft Windows PowerShell comes into play. We can use PowerShell to make multiple calls to the 7-Zip executable, which is otherwise very command line friendly, and add files from multiple folders to the same aggregate (eg. daily) archive file.

I recently wrote a PowerShell script that will assist with creating automated backups of my information, and wanted to share it with the community. This script not only performs a daily backup of the specified folders (using the -Path parameter), but it also downloads and installs 7-Zip if the system it’s being executed on doesn’t have it installed already.

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
function Backup-FolderToDropbox {
    [CmdletBinding()]
    param (
          [string] $Password
        , [string[]] $Path
        , [string] $BackupFolder
        , [switch] $Force
    )

    Set-PSDebug -Strict;
    # REQUIRES PowerShell version 3.0 CTP2 or later

    # Define source and backup folder
    $BackupName = '{0}Documents.7z' -f (Get-Date -Format 'yyyy-MM-dd');
    Remove-Item -Path "$env:TEMP\$BackupName" -Force:$Force -ErrorAction SilentlyContinue;

    # Create a new System.Net.WebClient object
    $WebClient = New-Object -TypeName System.Net.WebClient;
    # Define URL to download 7-Zip if it's unavailable
    $7ZipUrl = 'http://downloads.sourceforge.net/sevenzip/7z920-x64.msi';
    $7ZipDownloadPath = "$env:TEMP\7z920-x64.msi";
    $7ZipInstalled = $true;

    try {
        # Get path to 7-Zip executable
        $7ZipPath = Resolve-Path `
            -Path ((Get-Item -Path HKLM:\SOFTWARE\7-Zip -ErrorAction SilentlyContinue).GetValue("Path") + '\7z.exe');
        if (!$7ZipPath) {
            $7ZipInstalled = $false;
        }
    }
    catch {
        $7ZipInstalled = $false;
    }

    # Download and install 7-Zip if it's not installed
    if (!$7ZipInstalled) {
        # Download the 7-Zip installer
        $WebClient.DownloadFile($7ZipUrl, $7ZipDownloadPath);

        # Install 7-Zip package
        Start-Process -Wait `
            -FilePath msiexec.exe `
            -ArgumentList ('/package "{0}" /quiet /l*v "{1}"' -f $7ZipDownloadPath, "$env:TEMP\7-Zip Install.log");

        # Remove the downloaded installer file
        Remove-Item -Path $7ZipDownloadPath -Force -ErrorAction SilentlyContinue;
    }

    foreach ($FolderPath in $Path) {
        # Define command line arguments for 7-Zip
        $Arguments = 'a -y -p{0} -t7z -mhe=on -mtc=on "{1}" "{2}"' -f $Password, $BackupName, $FolderPath;
        # For debugging: Write-Host -Object $Arguments;
        Start-Process `
            -RedirectStandardOutput "$env:TEMP\7-Zip Output.log" `
            -WorkingDirectory $env:TEMP `
            -NoNewWindow `
            -Wait `
            -FilePath $7ZipPath.Path `
            -ArgumentList $Arguments;
    };

    # Copy backup file to Dropbox folder
    Copy-Item -Path ('{0}\{1}' -f $env:TEMP, $BackupName) -Destination $BackupFolder -Force:$Force;
}

Clear-Host;
Backup-FolderToDropbox -Password foobar -Path c:\MyDocs -BackupFolder c:\Dropbox\Backups -Force;

Copy Filenames to Clipboard with PowerShell

Have you ever wanted to copy a large amount of data to the Windows clipboard, but haven’t known quite how to do it? How about this scenario: you have a folder full of files, and you want to get a list of the files’ full names / paths. That’s pretty easy to do with a simple Get-ChildItem PowerShell command, but how do you then get the data into say, an e-mail, or paste it into a file? Sometimes it’s just easiest to have the data copied to the Windows clipboard for a more arbitrary usage.

This simple PowerShell script will take a folder path and copy all of the file paths to the Windows clipboard.

Important: The Windows clipboard requires that the application be running in Single-Threaded Apartment (STA) mode, so if you’re using PowerShell v2, please be sure to run PowerShell with the –STA parameter. If you use Multi-Threaded Apartment (MTA), the [Clipboard]::SetText() static method will fail.

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
function Copy-FileNamesToClipboard {
    # The CmdletBinding() attribute
    [CmdletBinding()]

    # Define parameters for the PowerShell v2 advanced function
    param (
        # Define a mandatory parameter called Path, which will be the path to gather files from
        [Parameter(Mandatory = $true)]
        [string] $Path
    )

    process {
        # Load the Presentation Core assembly, which contains the System.Windows.Clipboard class
        [void][Reflection.Assembly]::LoadWithPartialName("PresentationCore");

        # Initialize the text variable to an empty string
        $text = [string]::Empty;

        # Get a list of files in the specified directory
        $FileList = Get-ChildItem -Path $Path;

        # For each file in the directory, add the file path and a new line to $text
        foreach ($File in $FileList) {
            $text += ("{0}`n" -f $File.FullName);
        };

        # Set the Clipboard text to the string we just got
        [System.Windows.Clipboard]::SetText($text);
    };
};

Copy-FileNamesToClipboard -Path c:\Users\Trevor\Documents\;

Internal Server Error with nopCommerce on IIS

If you’re working with the open-source nopCommerce project, you might notice that upon initial setup, you get a message saying the following:

“We’re sorry, an internal error occurred that prevents the request to complete. Our supporting staff has been notified with this error and will address this issue shortly. We profusely apologize for the inconvenience and for any damage this may cause. You might want to try the same action at a later time.”

There’s a good chance that — depending on who your webhost is —your website might be pre-configured to use the .NET 2.0 runtime instead of the .NET 4.0 runtime. If your webhost allows you to change the option, make sure that your website (or virtual directory) is configured to use the .NET 4.0 Integrated pipeline for Internet Information Services (IIS).

Hope this helps!

image