There is a script named Get-Stuff.ps1 that is headed it with a PSScriptInfo block. The script is published to a NuGet repository. It is then installed to the expected location, C:\Users\lit\Documents\WindowsPowerShell\Scripts\Get-Stuff.ps1. Get-InstalledScript reports that it is installed. However, it is not found to be an executable. The C:\Users\lit\Documents\WindowsPowerShell\Scripts\ directory is not in $Env:PSModulePath.
What step did I miss to make this command executable after installation?
PS C:\> (Get-ChildItem -Recurse -File -Path 'C:\' -Filter 'Get-Stuff*' -ErrorAction SilentlyContinue).FullName
C:\src\Modules\scripts\Get-Stuff.ps1
PS C:\> Test-ScriptFileInfo -Path 'C:\src\Modules\scripts\Get-Stuff.ps1'
Version Name Author Description
------- ---- ------ -----------
1.0.0.1 Get-Stuff lit Get-Stuff produces .csv files of record counts from tables.
PS C:\> Publish-Script -Path 'C:\src\Modules\scripts\Get-Stuff.ps1' -NuGetApiKey 'yanon' -Repository 'yrepo'
PS C:\> Find-Script -Name Get-Stuff
Version Name Repository Description
------- ---- ---------- -----------
1.0.0.1 Get-Stuff yrepo Get-Stuff produces .csv files of record counts from tables.
PS C:\> Find-Script -Name Get-Stuff | Install-Script
PS C:\> (Get-ChildItem -Recurse -File -Path 'C:\' -Filter 'Get-Stuff*' -ErrorAction SilentlyContinue).FullName
C:\src\Modules\scripts\Get-Stuff.ps1
C:\Users\lit\Documents\WindowsPowerShell\Scripts\Get-Stuff.ps1
C:\Users\lit\Documents\WindowsPowerShell\Scripts\InstalledScriptInfos\Get-Stuff_InstalledScriptInfo.xml
PS C:\> Get-InstalledScript -Name Get-Stuff
Version Name Repository Description
------- ---- ---------- -----------
1.0.0.1 Get-Stuff yrepo Get-Stuff produces .csv files of record counts from tables.
PS C:\> Get-Command Get-Stuff
Get-Command : The term 'Get-Stuff' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of
the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ Get-Command Get-Stuff
+ ~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Get-Stuff:String) [Get-Command], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException,Microsoft.PowerShell.Commands.GetCommandCommand
PS C:\> $PSVersionTable.PSVersion.ToString()
5.1.17763.1490
It is $env:PATH that matters with respect to by-file-name-only invocations of *.ps1 files (script files), not $env:PSModulePath, which only applies to modules.
Unfortunately, earlier versions of the PowerShellGet module did not offer to add the directories targeted by the Install-Script cmdlet to $env:PATH persistently, but as of at least v2.2.4 they do (a prompt is presented), the next time you call Install-Script to perform an actual installation.
Try updating your PowerShellGet version with either Update-Module PowerShellGet or, if that fails, Install-Module -Force PowerShellGet (which in Windows PowerShell requires elevation, unless you specify -Scope CurrentUser).
If you want to make these $env:PATH additions yourself, run the following code:
Note:
Modifying $env:PATH persistently, via the registry, is only supported on Windows (on Unix, mechanisms for defining persistent environment variables differ across platforms).
However, on Unix too the in-session $env:PATH variable is updated.
& {
Write-Verbose -vb "Adding Install-Script install directories to `$env:PATH..."
$isWin = $env:OS -eq 'Windows_NT'
$isAdmin = if ($isWin) { [bool] (net session 2>$null) } else { 0 -eq (id -u) }
$ErrorActionPreference = 'Stop'
# Determine the locations: current-user, all-user.
$scriptDirs = (Join-Path (Split-Path ($PROFILE, "$HOME/.local/share/powershell/Modules")[$env:OS -ne 'Windows_NT']) Scripts),
(Join-Path (Split-Path ("$env:ProgramFiles\$(if ($PSVersionTable.PSEdition -ne 'Core') { 'Windows' })PowerShell\Modules", '/usr/local/share/powershell/Modules')[$env:OS -ne 'Windows_NT']) Scripts)
if (-not $isWin) {
# Note: There's no unified mechanism across macOS and Linux.
Write-Warning "On Unix, this script only supports modifying the *current session*'s `$env:PATH variable."
} elseif (-not $isAdmin) {
Write-Warning "Since this session isn't elevated, only the *current-user* location will be added *persistently*."
}
$pathVarSep = [IO.Path]::PathSeparator
$i = 0
foreach ($dir in $scriptDirs) {
# Always update the in-session variable.
Write-Verbose -vb "-- Adding $dir..."
if ($env:PATH -split $pathVarSep -notcontains $dir) {
$env:PATH = ($env:PATH -replace "$pathVarSep`$") + $pathVarSep + $dir
}
else {
Write-Verbose -vb "Already present in-session: $dir"
}
# On Windows, also try to update the *persistent* definitions
if ($isWin) {
$scope = ('User', 'Machine')[$i++ -eq 1]
if ($scope -eq 'Machine' -and -not $isAdmin) { break } # skip due to lack of permissions
# Note: We query the registry directly, so as to preserve unexpanded REG_EXPAND_SZ values.
$currVal = Get-ItemPropertyValue ('registry::HKEY_CURRENT_USER\Environment', 'registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment')[$scope -eq 'Machine'] Path
if ($currVal -split $pathVarSep -notcontains $dir) {
[Environment]::SetEnvironmentVariable('Path', (($currVal -replace "$pathVarSep`$") + $pathVarSep + $dir), $scope)
} else {
Write-Verbose -vb "Already present persistently in the $scope scope: $dir"
}
}
}
Write-Verbose -vb 'Done.'
}
Related
Ive been banging my head with a powershell script that i've tried a few differnt methods with and was wondering if someone can help?
Unsure at this point if im just doing something silly, thanks in advance
Aim:
To copy a vbs file from user's homedrives to a different location, the location of the vbs file changes depending on which user needs account admin doing hence why this needs to be variable. It gets the location from a text file which includes the exact path to go to and a destination which has already been created to copy the files to.
Where I have the issue currently:
$location = Get-Content C:\Users\Administrator\Desktop\here\drive4.txt | Out-String
$dest = "C:\Users\Administrator\Desktop\here"
Get-ChildItem -Path $location |
Copy-Item -Destination $dest -Recurse -Container -filter "peruser.vbs"
write-host $location
Read-Host -Prompt "Press Enter to continue or CTRL+C to quit"
The Issue
Please see the below, I have put write host to show the location powershell is trying to reach, as a side note I am able to reach this location fine through file explorer
Screenshot of error
Error Recieved
Get-ChildItem : Illegal characters in path.
At C:\Users\Administrator\Desktop\MapNetworkDrives2.ps1:17 char:1
+ Get-ChildItem -Path $location | Copy-Item -Destination $dest -Recurse -Container ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (\\WIN-7V7GI0R7C...
:String) [Get-ChildItem], ArgumentException
+ FullyQualifiedErrorId : ItemExistsArgumentError,Microsoft.PowerShell.Commands.GetChildItemCommand
Get-ChildItem : Cannot find path '\\WIN-7V7GI0R7CFK\homedrives\Onetest$
' because it does not exist.
At C:\Users\Administrator\Desktop\MapNetworkDrives2.ps1:17 char:1
+ Get-ChildItem -Path $location | Copy-Item -Destination $dest -Recurse -Container ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (\\WIN-7V7GI0R7C...
:String) [Get-ChildItem], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
Unless I have misunderstood you - you are just trying to copy a file to various locations based on a list. If so you just need to loop through your list. Does this work for you?
$location = Get-Content "C:\Users\Administrator\Desktop\here\drive4.txt"
$dest = "C:\Users\Administrator\Desktop\here"
foreach ($loc in $location){
$vbs = (gci $loc -Filter "peruser.vbs").FullName
Copy-Item $vbs $dest -Force
}
You are not showing what is in the text file, forcing us to guess, which is not really a good thing relative to trying to help you. So, I am going to assume it's just a list of drive letters or path UNC's, which is really moot since you can pull those dynamically, thus no need for the file.
I don't understand why you are doing this...
Get-Content 'C:\Users\Administrator\Desktop\here\drive4.txt' |
Out-String
If it is just a text file for reading, why are you piping that anywhere?
You don't need double quotes for this. Single quotes for simple string, double for variable expansion or other specific formatted requirements
$dest = 'C:\Users\Adminstrator\Desktop\here'
Just pass the read directly
Get-Content 'C:\Users\Administrator\Desktop\here\drive4.txt' |
ForEach {
"Processing location $($PSItem.FullName)"
Copy-Item -Path $PSItem.FullName -Destination $dest -Filter 'peruser.vbs' -Recurse -WhatIf
}
Point of note:
You don't need Write-Host to output to the screen, as that is the PowerShell default, as I'll show in my example to follow. Really, except for writing screen text with color, you'd never need to use Write-Host/echo at all, well, there are a few other specific times to use it.
Also of note, regarding Write-Host from the inventor of Monad/PowerShell Jeffery Snover
http://www.jsnover.com/blog/2013/12/07/write-host-considered-harmful
https://twitter.com/jsnover/status/727902887183966208
https://learn.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Utility/Write-Information?view=powershell-5.1
You also, do not necessarily need both Get-ChildItem and Copy-Item, since both will read the folder tree recursively. As I'll show below. I am using splatting to tighten up the code block for readability.
So, if I demo this just using a drive and folder on my system. And step through a script build out to make sure I am getting what I expect at each step before moving to the next.
Get-PSDrive -PSProvider FileSystem |
Format-Table -AutoSize
<#
# Results
Name Used (GB) Free (GB) Provider Root CurrentLocation
---- --------- --------- -------- ---- ---------------
C 357.48 118.83 FileSystem C:\ Windows\system32
D 114.10 362.71 FileSystem D:\ Scripts
E 1194.00 668.89 FileSystem E:\
F 3537.07 188.83 FileSystem F:\
G FileSystem G:\
#>
# Validate if there is any content in the destination
Try
{
Get-PSDrive -PSProvider FileSystem |
Where Name -eq 'D' |
ForEach {
"Processing location $($PSItem.Root) and the contents are as listed."
(Get-ChildItem -Path 'D:\Temp\here' -Recurse).FullName
}
}
Catch {Write-Warning -Message 'No content in the destination folder'}
<#
# Results
Processing location D:\ and the contents are as listed.
WARNING: No content in the destination folder
#>
# Show what is on the drive for the source files
Get-PSDrive -PSProvider FileSystem |
Where Name -eq 'D' |
ForEach{
"Processing the location $($PSItem.Root)"
(Get-ChildItem -Path "$($PSItem.Root)\Temp\book1.csv" -Recurse).FullName
}
<#
# Results
Processing the location D:\
D:\Temp\Source\book1.csv
D:\Temp\book1.csv
#>
<#
# Show what will happen if a Copy files from the source to the destination occurs
Using splatting for readability
#>
Get-PSDrive -PSProvider FileSystem |
Where Name -eq 'D' |
ForEach{
"Processing the location $($PSItem.Root)"
$CopyItemSplat = #{
Path = "$($PSItem.Root)\Temp\book1.csv"
Destination = "$($PSItem.Root)\Temp\here"
Recurse = $true
WhatIf = $true
}
}
Copy-Item #CopyItemSplat
<#
# Results
Processing the location D:\
What if: Performing the operation "Copy File" on target "Item: D:\Temp\book1.csv Destination: D:\Temp\here\book1.csv".
If the results are as expected, execute the action
Using splatting for readability
#>
Get-PSDrive -PSProvider FileSystem |
Where Name -eq 'D' |
ForEach{
"Processing the location $($PSItem.Root)"
$CopyItemSplat = #{
Path = "$($PSItem.Root)\Temp\book1.csv"
Destination = "$($PSItem.Root)\Temp\here"
Recurse = $true
}
}
Copy-Item #CopyItemSplat
<#
# Results
Processing the location D:\
#>
# Validate if there is any content in the destination
Try
{
Get-PSDrive -PSProvider FileSystem |
Where Name -eq 'D' |
ForEach {
"Processing location $($PSItem.Root) and the contents are as listed."
(Get-ChildItem -Path 'D:\Temp\here' -Recurse).FullName
}
}
Catch {Write-Warning -Message 'No content in the destination folder'}
<#
# Results
Processing location D:\ and the contents are as listed.
D:\Temp\here\book1.csv
#>
I backed up printers from a Windows 10 system to XML files. I'm trying to add them using the Set-Printconfiguration CMDLET, but it seems to be not accepting variables?
I've looked everywhere but I cannot find anything saying my syntax is wrong.
#get list of printers in backup folder
$printerNames = (Get-ChildItem -Path c:\temp\printers\*.xml -Recurse | select name).name
foreach ($printer in $printerNames)
{
Set-PrintConfiguration -PrinterName $printer -PrintTicketXml c:\temp\printers\$printer
}
Here is the code I used to get the printer XML files:
$TARGETDIR = "c:\temp\printers"
if(!(Test-Path -Path $TARGETDIR )){
New-Item -ItemType directory -Path $TARGETDIR
}
# Get all the printers:
$PN = (get-printer | select name).name
# Foreach loop to create XML file for each printer configuration
Foreach ($P in $PN){
$GPC = get-printconfiguration -PrinterName $P
mkdir c:\temp\printers\$P
$GPC.PrintTicketXML | out-file C:\Temp\printers\$P.xml
# $p|select *|out-file -Path c:\temp\$p.xml -NoTypeInformation
}
edit: here is the error I'm getting:
Set-PrintConfiguration : The specified printer was not found.
At U:\PowerShell\Scripts\backup\newRestorePrinters.ps1:15 char:9
+ Set-PrintConfiguration -PrinterName $printer -PrintTicketXml ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (MSFT_PrinterConfiguration:ROOT/StandardCi...erConfiguration) [Set-PrintConfiguration], CimException
+ FullyQualifiedErrorId : HRESULT 0x80070709,Set-PrintConfiguration
edit
I added more variables to get the list of printers w/out the .XML on the end of the names. It still gives me the same error output. It looks like it's not passing my variables to the set-printconfiguration command?
New restore script code:
$printerShortNameList = (Get-ChildItem -Path c:\temp\printers\*.xml -Recurse | select name).name
foreach ($shortName in $printerShortNameList)
{
$shortName.Replace('.xml', "x")
}
#get list of printers in backup folder
$printerNames = (Get-ChildItem -Path c:\temp\printers\*.xml -Recurse | select name).name
foreach ($printer in $printerNames)
{
Set-PrintConfiguration -PrinterName $shortName -PrintTicketXml c:\temp\printers\$printer
}
What was the error message? Shouldn't you take the '.xml' off the end of $printer for the printer name? I think you have to use add-printer first. I don't believe Set-PrintConfiguration creates printers.
On the bottom when you make the xml files, why do you create the c:\temp\printers\$p directory?
Set-PrintConfiguration:
You need administrator credentials to use Set-PrintConfiguration.
This identical code has been used in 3 servers, and only one of them does it silently fail to move the items (it still REMOVES them, but they do not appear in the share).
Azure-MapShare.ps1
param (
[string]$DriveLetter,
[string]$StorageLocation,
[string]$StorageKey,
[string]$StorageUser
)
if (!(Test-Path "${DriveLetter}:"))
{
cmd.exe /c "net use ${DriveLetter}: ${StorageLocation} /u:${StorageUser} ""${StorageKey}"""
}
Get-Exclusion-Days.ps1
param (
[datetime]$startDate,
[int]$daysBack
)
$date = $startDate
$endDate = (Get-Date).AddDays(-$daysBack)
$allDays =
do {
"*"+$date.ToString("yyyyMMdd")+"*"
$date = $date.AddDays(-1)
} until ($date -lt $endDate)
return $allDays
Migrate-Files.ps1
param(
[string]$Source,
[string]$Filter,
[string]$Destination,
[switch]$Remove=$False
)
#Test if source path exist
if((Test-Path -Path $Source.trim()) -ne $True) {
throw 'Source did not exist'
}
#Test if destination path exist
if ((Test-Path -Path $Destination.trim()) -ne $True) {
throw 'Destination did not exist'
}
#Test if no files in source
if((Get-ChildItem -Path $Source).Length -eq 0) {
throw 'No files at source'
}
if($Remove)
{
#Move-Item removes the source files
Move-Item -Path $Source -Filter $Filter -Destination $Destination -Force
} else {
#Copy-Item keeps a local copy
Copy-Item -Path $Source -Filter $Filter -Destination $Destination -Force
}
return $True
The job step is type "PowerShell" on all 3 servers and contains this identical code:
#Create mapping if missing
D:\Scripts\Azure-MapShare.ps1 -DriveLetter 'M' -StorageKey "[AzureStorageKey]" -StorageLocation "[AzureStorageAccountLocation]\backup" -StorageUser "[AzureStorageUser]"
#Copy files to Archive
D:\Scripts\Migrate-Files.ps1 -Source "D:\Databases\Backup\*.bak" -Destination "D:\Databases\BackupArchive"
#Get date range to exclude
$exclusion = D:\Scripts\Get-Exclusion-Days.ps1 -startDate Get-Date -DaysBack 7
#Remove items that are not included in exclusion range
Remove-Item -Path "D:\Databases\BackupArchive\*.bak" -exclude $exclusion
#Move files to storage account. They will be destroyed
D:\Scripts\Migrate-Files.ps1 -Source "D:\Databases\Backup\*.bak" -Destination "M:\" -Remove
#Remove remote backups that are not from todays backup
Remove-Item -Path "M:\*.bak" -exclude $exclusion
If I run the job step using SQL then the files get removed but do not appear in the storage account. If I run this code block manually, they get moved.
When I start up PowerShell on the server, I get an error message: "Attempting to perform the InitializeDefaultDrives operation on the 'FileSystem' provider failed." However, this does not really impact the rest of the operations (copying the backup files to BackupArchive folder, for instance).
I should mention that copy-item also fails to copy across to the share, but succeeds in copying to the /BackupArchive folder
Note sure if this will help you but you could try to use the New-PSDrive cmdlet instead of net use to map your shares:
param (
[string]$DriveLetter,
[string]$StorageLocation,
[string]$StorageKey,
[string]$StorageUser
)
if (!(Test-Path $DriveLetter))
{
$securedKey = $StorageKey | ConvertTo-SecureString -AsPlainText -Force
$credentials = New-Object System.Management.Automation.PSCredential ($StorageUser, $securedKey)
New-PSDrive -Name $DriveLetter -PSProvider FileSystem -Root $StorageLocation -Credential $credentials -Persist
}
Apparently I tricked myself on this one. During testing I must have run the net use command in an elevated command prompt. This apparently hid the mapped drive from non-elevated OS features such as the Windows Explorer and attempts to view its existence via non-elevated command prompt sessions. I suppose it also was automatically reconnecting during reboots because that did not fix it.
The solution was as easy as running the net use m: /delete command from an elevated command prompt.
Is this possible?
I ask because I have a script which works on my PC but not on the client machine, and it will be a waste of time trying to debug if it wont work simply because the script uses the wrong version.
Thanks
The script I am trying to run (from the top of a logon script):
try {
. "\\dc1\netlogon\PSSubs\Logging_Functions.ps1"
}
catch { [System.Windows.Forms.MessageBox]::Show($Error[0]) }
try {
Log-Start -LogPath "\\DC1\NETLOGON\PSSubs" -LogName "Test_Log.log" -ScriptVersion "1.0"
}
catch { [System.Windows.Forms.MessageBox]::Show($Error[0]) }
Where Logging_Functions.ps is from here, and I have posted the code for the first function I try to call (Log-Start) nelow.
Function Log-Start{
<#
.SYNOPSIS
Creates log file
.DESCRIPTION
Creates log file with path and name that is passed. Checks if log file exists, and if it does deletes it and creates a new one.
Once created, writes initial logging data
.PARAMETER LogPath
Mandatory. Path of where log is to be created. Example: C:\Windows\Temp
.PARAMETER LogName
Mandatory. Name of log file to be created. Example: Test_Script.log
.PARAMETER ScriptVersion
Mandatory. Version of the running script which will be written in the log. Example: 1.5
.INPUTS
Parameters above
.OUTPUTS
Log file created
.NOTES
Version: 1.0
Author: Luca Sturlese
Creation Date: 10/05/12
Purpose/Change: Initial function development
Version: 1.1
Author: Luca Sturlese
Creation Date: 19/05/12
Purpose/Change: Added debug mode support
.EXAMPLE
Log-Start -LogPath "C:\Windows\Temp" -LogName "Test_Script.log" -ScriptVersion "1.5"
#>
[CmdletBinding()]
Param ([Parameter(Mandatory=$true)][string]$LogPath, [Parameter(Mandatory=$true)][string]$LogName, [Parameter(Mandatory=$true)][string]$ScriptVersion)
Process{
$sFullPath = $LogPath + "\" + $LogName
#Check if file exists and delete if it does
If((Test-Path -Path $sFullPath)){
Remove-Item -Path $sFullPath -Force
}
#Create file and start logging
New-Item -Path $sFullPath -ItemType File
# This version displays an annoying erro
# New-Item -Path $LogPath -Value $LogName -ItemType File
Add-Content -Path $sFullPath -Value "***************************************************************************************************"
Add-Content -Path $sFullPath -Value "Started processing at [$([DateTime]::Now)]."
Add-Content -Path $sFullPath -Value "***************************************************************************************************"
Add-Content -Path $sFullPath -Value ""
Add-Content -Path $sFullPath -Value "Running script version [$ScriptVersion]."
Add-Content -Path $sFullPath -Value ""
Add-Content -Path $sFullPath -Value "***************************************************************************************************"
Add-Content -Path $sFullPath -Value ""
#Write to screen for debug mode
Write-Debug "***************************************************************************************************"
Write-Debug "Started processing at [$([DateTime]::Now)]."
Write-Debug "***************************************************************************************************"
Write-Debug ""
Write-Debug "Running script version [$ScriptVersion]."
Write-Debug ""
Write-Debug "***************************************************************************************************"
Write-Debug ""
}
}
The canonical way for a script to specify which version it requires is to uses #Requires:
#Requires -Version <N>[.<n>]
#Requires –PSSnapin <PSSnapin-Name> [-Version <N>[.<n>]]
#Requires -Modules { <Module-Name> | <Hashtable> }
#Requires –ShellId <ShellId>
#Requires -RunAsAdministrator
See help about_requires for more info.
So placing #Requires in your script will make sure it will only run if the minimum required version is installed.
To answer the question in the OP title: if the script was written using #Requires, simply search the script for the #Requires keyword and parse for the -Version argument. If #Requires wasn't used, then see the comments to the OP.
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?
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
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
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
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
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.
$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