60

I would like to be able to get the file version and assembly version of all DLL files within a directory and all of its subdirectories. I'm new to programming, and I can't figure out how to make this loop work.

I have this PowerShell code to get the assembly version (taken from a forum):

$strPath = 'c:\ADMLibrary.dll'
$Assembly = [Reflection.Assembly]::Loadfile($strPath)

$AssemblyName = $Assembly.GetName()
$Assemblyversion = $AssemblyName.version

And this as well:

$file = Get-ChildItem -recurse | %{ $_.VersionInfo }

How can I make a loop out of this so that I can return the assembly version of all files within a directory?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Tim Sloyan
  • 601
  • 1
  • 5
  • 3

6 Answers6

78

Here is a pretty one liner:

Get-ChildItem -Filter *.dll -Recurse | Select-Object -ExpandProperty VersionInfo

In short for PowerShell version 2:

ls -fi *.dll -r | % { $_.versioninfo }

In short for PowerShell version 3 as suggested by tamasf:

ls *.dll -r | % versioninfo
Community
  • 1
  • 1
knut
  • 4,699
  • 4
  • 33
  • 43
  • 8
    In short: ls *.dll -r | % versioninfo – tamasf Jan 09 '13 at 08:56
  • 14
    This will only yield the FileVersion but not the AssemblyVersion – bitbonk Feb 05 '15 at 11:44
  • 1
    For managed dll's, to get the real/updated version info, .NET is really the only way to go. http://elegantcode.com/2009/12/22/powershell-load-assembly-without-locking-file/ Look at the "update" down below, the rest is over-complicating it :p – Christopher Wirt Jul 16 '15 at 17:24
47

As an ugly one-liner:

Get-ChildItem -Filter *.dll -Recurse |
    ForEach-Object {
        try {
            $_ | Add-Member NoteProperty FileVersion ($_.VersionInfo.FileVersion)
            $_ | Add-Member NoteProperty AssemblyVersion (
                [Reflection.AssemblyName]::GetAssemblyName($_.FullName).Version
            )
        } catch {}
        $_
    } |
    Select-Object Name,FileVersion,AssemblyVersion

If you only want the current directory, then obviously leave out the -Recurse parameter. If you want all files instead of just DLLs, then remove the -Filter parameter and its argument. The code is (hopefully) pretty straightforward.

I'd suggest you spin off the nasty parts within the try block into separate functions since that will make error handling less awkward here.

Sample output:

Name                                    FileVersion     AssemblyVersion
----                                    -----------     ---------------
Properties.Resources.Designer.cs.dll    0.0.0.0         0.0.0.0
My Project.Resources.Designer.vb.dll    0.0.0.0         0.0.0.0
WindowsFormsControlLibrary1.dll         1.0.0.0         1.0.0.0
WindowsFormsControlLibrary1.dll         1.0.0.0         1.0.0.0
WindowsFormsControlLibrary1.dll         1.0.0.0         1.0.0.0
Joey
  • 344,408
  • 85
  • 689
  • 683
  • This works, but unfortunately it loads the files and never releases them ... Run it and then try to delete one of those files. – Karel Frajták Oct 15 '14 at 15:23
  • 2
    That is indeed a drawback. You can circumvent this by spawning a new PowerShell instance: `powershell -NoProfile -OutputFormat XML -EncodedCommand $encodedCommand |%{$_}` with `$encodedCommand` being the Base64-encoded variant of the above snippet (see `powershell /?` for a sample how to obtain it). This will yield the same objects that would otherwise be produced, but the shell loading the files is no longer alive now. – Joey Oct 16 '14 at 09:14
  • I am trying to load the assemblies into new AppDomain and unload it later, but it does not work - the assembly loader looks for assemblies in PowerShell directory (C:/windows/system32/WindowsPowerShell/v1.0) even though I set the base directory when creating the new domain... – Karel Frajták Oct 17 '14 at 12:13
  • @Karel, what exactly would be wrong with just spawning a new process? – Joey Oct 17 '14 at 16:45
  • 1
    I didn't say that! I just tried it and it locked those files. And then tried different approach and that didn't work. Yes, spawning new process is the solution here. – Karel Frajták Oct 17 '14 at 21:04
  • The AppDomain approach should work too, but it's somewhat difficult to pull off, I guess. – Joey Oct 17 '14 at 21:30
  • 5
    You can use `AssemblyName.GetAssemblyName` to get the AssemblyName (and hence the AssemblyVersion) without loading the assembly – lesscode Nov 03 '14 at 22:49
  • @Wayne: Oh, that's way nicer. Thanks. – Joey Nov 04 '14 at 11:15
  • This actually works for C++/CLI assemblies that don't have Version resources – Eugenio Miró Aug 01 '16 at 19:29
8

Let Select-Object create the properties

Get-ChildItem -Filter *.dll -Recurse | Select-Object Name,@{n='FileVersion';e={$_.VersionInfo.FileVersion}},@{n='AssemblyVersion';e={[Reflection.AssemblyName]::GetAssemblyName($_.FullName).Version}}

And Sample output is similar

Name                                           FileVersion AssemblyVersion
----                                           ----------- ---------------
CI.EntityFramework.Initialization.dll          1.0.0.0     1.0.0.0
Castle.Core.dll                                3.3.0.43    3.3.0.0
Castle.Windsor.dll                             3.3.0.51    3.3.0.0
Mutare.VitalLink.dll                           1.0.0.0     1.0.0.0
Newtonsoft.Json.dll                            9.0.1.19813 9.0.0.0
Jim W
  • 421
  • 5
  • 6
3

Here's a pretty one-liner:

Get-ChildItem -Filter *.dll -Recurse | ForEach-Object `
{
    return [PSCustomObject]@{
        Name = $_.Name
        FileVersion = $_.VersionInfo.FileVersion
        AssemblyVersion = ([Reflection.AssemblyName]::GetAssemblyName($_.FullName).Version)
    }
}

Sample output:

Name            FileVersion AssemblyVersion
----            ----------- ---------------
Minimatch.dll   1.1.0.0     1.1.0.0
VstsTaskSdk.dll 1.0.0.0     1.0.0.0
Dmitry Serbin
  • 81
  • 1
  • 4
3

Based on Joey's answer, but exploiting some handy behaviour for implicit exception handling. First add an extension property:

Update-TypeData -TypeName System.IO.FileInfo -MemberType ScriptProperty -MemberName AssemblyVersion -Value { [Reflection.AssemblyName]::GetAssemblyName($this.FullName).Version }

That can optionally be placed into your profile for reuse. Then the actual selection is just e.g.

Get-ChildItem -Filter *.dll -Recurse | Select-Object Name,AssemblyVersion

As a side-note, the main reason I'm posting this as an additional answer is for the benefit of PowerShell noobs like myself: it took me a long time to figure out that $_ in Joey's answer needs to be turned into $this in the definition given to Update-TypeData.

Peter Taylor
  • 4,918
  • 1
  • 34
  • 59
0
$j = 'C:\Program Files\MySQL\Connector ODBC 8.0\' # this is the path of foler where you want check your dlls 
$files = get-childitem $j -recurse -include *.dll # this is the command thatwill check all the dlls in that folder 

foreach ($i in $files) {
   $verison = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($i).FileVersion
   Write-Host  "$i ----> $verison "
} # loop is used where it will travel throuhg all the files of the specified folder and check the verion and will print it 
Dhrumil Pathak
  • 101
  • 3
  • 11
  • 2
    please add description or comment on your answer – Maria Nov 16 '18 at 16:56
  • Not familiar with PHP, but wouldn't `\'` escape the quote, meaning you haven't ended the String? – Zoe Nov 16 '18 at 18:48
  • 1
    Welcome to StackOverflow! Your answer need more explanation about how the code works to be a good answer. – Tân Nov 17 '18 at 07:47