using DotNetZip from Powershell, ZipFile.Save fails on network drives?

Nov 2, 2010 at 11:14 AM

I'm writing a PowerShell script which zips up log files. Everything seems to work OK until the call to Save, at which point I get this error:

Exception calling "Save" with "1" argument(s): "Request for the permission of type 'System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed."
At U:\scriptdev\logarchiver\logarchiver.ps1:27 char:15
+     $zipFile.Save <<<< ($zipFileName)
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

The script works fine if I copy it to a folder on C: and run it from there. From what I can gather on Google, this is some sort of trust issue, but it seems like the utilities for setting trust ("gacutil" and "caspol") are unavailable/deprecated since .NET Framework 4? Any ideas how to solve this?

Here's the script in question:

# Log Archiver
# Checks to see if we have a month's worth of log files, then zips them up

# Load DotNetZip Library
$dotNetZip = Resolve-Path "Ionic.Zip.dll"
[System.Reflection.Assembly]::LoadFrom($dotNetZip) | Out-Null

# Get all log files in current folder, sorted by last write time
$logFiles = Get-ChildItem | Where {$_.extension -eq ".log"} | Sort-Object LastWriteTime
# Find date of earliest log file
$earliestLog = $logFiles[0].LastWriteTime
# Find current path
$currentPath = Resolve-Path $logFiles[0].Name | Split-Path
$monthAfterEarliest = $earliestLog.AddMonths(1)
$currentDate = Get-Date "8/11/2010" # date is there for testing purposes, remove for live usage
# Compare
if ($currentDate -gt $monthAfterEarliest) {
	# logs need archiving
	$zipFileName = $currentPath + "\logarchive-" + $currentDate.ToString("yyyy-MM-dd") + ".zip"
	$zipFile = New-Object Ionic.Zip.ZipFile
	foreach ($logFile in $logFiles) {
		$fileName = Resolve-Path $logFile.Name
		$zipFile.AddFile($fileName,"") | Out-Null
	}
	$zipFile.Save($zipFileName)
	$zipFile.Dispose()
	# zipping complete, delete log files
	foreach ($logFile in $logFiles) {
		$fileName = Resolve-Path $logFile.Name
		Remove-Item $fileName
	}
}

Coordinator
Nov 7, 2010 at 2:42 PM

As you pointed out, this is not an issue related to DotNetZip.

This is a security issue, related to running powershell scripts from networked drives, if i understand correctly. 

I think you would get a similar security exception if you ran a simple PS script from u:\ that simply created a file on c:\ , with no use of DotNetZip at all.  The error occurs when calling System.IO.File.Create() (or Open()), and it would occur when running the ps1 script from u:\, regardless of whether you used a third party library. 

The solution is to adjust the security for powershell scripts, or run the script locally.  I'm not an expert on powershell security, but I think this blog post may be relevant.

Nov 19, 2010 at 9:58 AM

Thanks for the reply. I tried changing the Powershell security temporarily (I ran it from a batch file with -ExecutionPolicy Bypass) which resulted in a different error:

out-lineoutput : Exception getting "formatValueList": "Microsoft.PowerShell.Commands.Internal.Format.FreeFormatEntry.formatValueList"
    + CategoryInfo          : NotSpecified: (:) [out-lineoutput], GetValueInvocationException
    + FullyQualifiedErrorId : CatchFromBaseAdapterGetValue,Microsoft.PowerShell.Commands.OutLineOutputCommand

Googling this gives only one result: http://social.technet.microsoft.com/Forums/en/winserverpowershell/thread/dd5dcae2-1ccc-4be2-b986-61c069102ffb which curiously enough also relates to DotNetZip.

However, for the moment I've been able to arrange things so the script can be run from a local location on a server.

Coordinator
Nov 19, 2010 at 11:59 AM

Wow, that error message is astoundingly opaque.

I don't know what to make of it.