2

Here's my script (createdistro.ps1)

Add-Type -assembly "system.io.compression.filesystem"

$source = "bin\Debug\"
$destination = "gwtester_signed.zip"

If(Test-path $destination) {Remove-item $destination}
[io.compression.zipfile]::CreateFromDirectory($source, $destination)

Notice the error message I get from running the script:

PS C:\dev\DEV7\Test\gwtester> .\createdistro.ps1
Exception calling "CreateFromDirectory" with "2" argument(s): "The file 'C:\Users\bbren\gwtester_signed.zip' already
exists."
At C:\dev\DEV7\Test\gwtester\createdistro.ps1:7 char:1
+ [io.compression.zipfile]::CreateFromDirectory($source, $destination)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : IOException

As you can see, the script attempts to write to C:\Users\bbren\gwtester_signed.zip, but the current working directory is C:\dev\etc\.

The documentation for ZipFile.CreateFromDirectory states that "A relative path is interpreted as relative to the current working directory."

What is wrong?

codeape
  • 97,830
  • 24
  • 159
  • 188

3 Answers3

2

I don't recommend $PSScriptRoot.

Try this:

$destination = Join-Path (Get-Location) 'gwtester_signed.zip'

But depending on your psversion, how about Expand-Archive?

Max
  • 77
  • 5
  • OK. How would you do it if the destination file path was passed from the command line? To support both relative and absolute paths? – codeape Mar 09 '16 at 13:37
  • I ended up using Compress-Archive. But I would still like to understand how Powershell handles absolute and relative paths. I'm baffled as to why CreateFromDirectory uses the user's home directory, instead of the current working dir. – codeape Mar 09 '16 at 13:38
  • Why not `$PSScriptRoot`? I understand it as a variable containing the directory of the running script. – G42 Mar 09 '16 at 13:43
  • @gmsoulman your understanding is correct. I assume the user may not always want zip files to land in the script's folder. – Max Mar 09 '16 at 13:51
  • 2
    @codeape afaik providing a relative path to .net objects in ps will be resolved relative to $env:userprofile. to support relative paths, you can use $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Path). that will convert itself to a absolute path if required,. – Max Mar 09 '16 at 14:00
1

Change $destination = "gwtester_signed.zip" to $destination = "$PSScriptRoot\gwtester_signed.zip"

G42
  • 9,791
  • 2
  • 19
  • 34
0

I've actually added this to my prompt function to keep the .NET and Powershell view of what the current working directory is in sync. There's probably a load of reasons this is a BadIdea™ - but it works for me :

[System.Environment]::CurrentDirectory = $PWD

Of course, you could just call that before you want to run a .NET method that cares about it too.

Edit: Ah yes, this question points out why this might end up being a bad idea : Why don't .NET objects in PowerShell use the current directory?

Edit2: and in light of the above, I've now changed my prompt function to do this :

if($PWD.Provider.Name -eq 'Filesystem'){
    [System.Environment]::CurrentDirectory = $PWD
}

So that the attempt to update the .NET view of current directory only happens when the current Powershell provider is the Filesystem one.

Community
  • 1
  • 1
GodEater
  • 3,445
  • 2
  • 27
  • 30