0

In MSBuild, there's the GetDirectoryNameOfFileAbove property function.

How do I achieve the same with PowerShell?

Should better have compact syntax, because that's what you have to paste into every entry-point script to find its includes.


The idea of this question:

  • There's a large solution in source code control. Some of its parts are relatively autonomous.
  • It has a location for shared scripts and reusable functions, at a known folder under the root.
  • There're numerous entry-point scripts (files which you explicitly execute) scattered around the project, all of them including the shared scripts.
  • What's the convenient way for locating the shared scripts from the entry-point-script?

Relative paths turn out to work bad because they look like "../../../../../../scripts/smth", are hard to write and maintain.

Registering modules is not a good option because (a) you're getting this from SCC, not by installing (b) you usually have different versions in different disc locations, all at the same time and (c) this is an excess dependency on the environment when technically just local info is enough.


MSBuild way for doing this (since v4) is as follows: drop a marker file (say, root.here or whatever), get an absolute path to that folder with GetDirectoryNameOfFileAbove, et voila! You got the local root to build paths from.

Maybe it's not the right way to go with powershell, so I'd be grateful for such directions as well.

hypersw
  • 475
  • 3
  • 9

2 Answers2

1

You can access the current folder thus: $invoker= Split-Path -Parent $MyInvocation.MyCommand.Path

So the parent of that one is : $parent=Split-Path -Parent $MyInvocation.MyCommand.Path|Split-Path -Parent

James Woolfenden
  • 6,498
  • 33
  • 53
  • This isn't a good answer because: (1) $MyInvocation.MyCommand.Path is often NULL, and (2) getting a parent once is simple, but you have to look for an ancestor folder with a marker file — it's still an open question whether there's a neat way for such recursion. – hypersw Feb 04 '13 at 13:37
  • Its not often null, its works when a script is run. Also here http://stackoverflow.com/questions/5466329/whats-the-best-way-to-determine-the-location-of-the-current-powershell-script – James Woolfenden Feb 04 '13 at 13:54
  • Sometimes "not often" is not good enough ;-) For instance, when calling powershell.exe with -Command which dotsources the script and then calls a function in it. `MyCommand.Path` does not work in this case. – hypersw Feb 04 '13 at 14:08
  • `Definition` is an interesting recipe, but it should be in the `$script:MyInvocation.MyCommand.Definition` form I think, to work inside a function. Wish there were something simple and reliable (like `$(MSBuildThisFileDirectory)` which was added in v4 over community feedback). – hypersw Feb 04 '13 at 14:11
0

A quick and dirty solution looks like this:

function GetDirectoryNameOfFileAbove($markerfile)
{
    $result = ""
    $path = $MyInvocation.ScriptName
    while(($path -ne "") -and ($path -ne $null) -and ($result -eq "")) 
    { 
        if(Test-Path $(Join-Path $path $markerfile)) {$result=$path}
        $path = Split-Path $path 
    }
    if($result -eq "") {throw "Could not find marker file $markerfile in parent folders."}
    return $result
}

It could be compacted into a single line for planting into scripts, but it's still too C#-ish, and I think it might be shortened down with some PS pipes/LINQ style magic.

UPD: edited the script, it was found that $MyInvocation.MyCommand.Path is often NULL when script is called from cmdline with dotsourcing (with any context level), so the current hypothesis is ScriptName.

hypersw
  • 475
  • 3
  • 9