Version of jar file by reading its manifest using powershell - powershell

I am running a powershell script to idenfity the versions. For DLL's and EXE's using the following function to get the version . I have a few other files with the extension .Jar. Is there a way I can use powershell to open the jar and get the version of it from their manifest.
Please let me know.
#{n='Version';e={$_.versioninfo.Fileversion}}

Looks like you have to extract from the jar file first. I downloaded java and tested myself using a jar file I also downloaded
& "C:\Program Files\Java\jdk1.8.0_191\bin\jar.exe" xvf junit-4.10.jar META-INF/MANIFEST.MF
get-content .\META-INF\MANIFEST.MF
RESULTS
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.2
Created-By: 1.6.0_26-b03-384-10M3425 (Apple Inc.)
That being said, please read here, Do we want single, complete answers? where Implementation-Version is mentioned, so make sure you know where the version is to be and if you can depend on this.

This works as a PowerShell script on Server 2016/PS 5.1 and Win 10/PS 7.1 without installing anything extra. It reads the MANIFEST.MF file in the zip archive and writes to standard output. This is option 4 found here: https://stackoverflow.com/a/37561878/101151
Be sure to pass the absolute path to [io.compression.zipfile]::OpenRead. It seems to bind to the first directory it was run in and re-use that for relative paths.
# Read the MANIFEST.MF from a Java .JAR (really a .zip) file and output to standard output
param(
[Parameter(Mandatory=$true)][string]$jarname
)
# The following code is based on an answer at https://stackoverflow.com/a/37561878/101151
Add-Type -assembly "system.io.compression.filesystem"
$zip = [io.compression.zipfile]::OpenRead((Get-ChildItem $jarname).FullName)
$file = $zip.Entries | where-object { $_.Name -eq "MANIFEST.MF"}
$stream = $file.Open()
$reader = New-Object IO.StreamReader($stream)
$text = $reader.ReadToEnd()
$text
$reader.Close()
$stream.Close()
$zip.Dispose()

Related

PowerShell: Error when reading files that are open in other programs

Hello PowerShell Experts,
The script snippet below works when adding files to Zip file. However, if the file to be added is open in another program then it fails with exception, "The process cannot access the file[..]". I tried using [IO.FileShare]::ReadWrite but no success yet.
Any suggestion as to how to open the files for reading and writing to zip regardless whether the file is open in another program or not?
Script Source
# write entries with relative paths as names
foreach ($fname in $FullFilenames) {
$rname = $(Resolve-Path -Path $fname -Relative) -replace '\.\\',''
Write-Output $rname
$zentry = $zip.CreateEntry($rname)
$zentryWriter = New-Object -TypeName System.IO.BinaryWriter $zentry.Open()
$zentryWriter.Write([System.IO.File]::ReadAllBytes($fname)) #FAILS HERE
$zentryWriter.Flush()
$zentryWriter.Close()
}
Since we're missing some important part of your code, I'll just assume what might work in this case, and following assumptions based on your comments.
First you would open the file with FileShare.ReadWrite:
$handle = [System.IO.File]::Open($fname, 'Open', 'Read', 'ReadWrite')
Then you should be able to use the .CopyTo(Stream) method from FileStream:
$zentry = $zip.CreateEntry($rname)
$zstream = $zentry.Open()
$handle.CopyTo($zstream)
$zstream.Flush()
$zstream.Dispose()
$handle.Dispose()

Powershell - Download the latest FTP files from Ftp server [duplicate]

I am working on a PowerShell script, which will pull files from an FTP site. The files are uploaded to the FTP site every hour so I need to download the most recent one. The code I currently have downloads all the files from today instead of just one file. How do I make it download only the most recent file?
Here is the code that I am currently using
$ftpPath = 'ftp://***.***.*.*'
$ftpUser = '******'
$ftpPass = '******'
$localPath = 'C:\Temp'
$Date = get-date -Format "ddMMyyyy"
$Files = 'File1', 'File2'
function Get-FtpDir ($url, $credentials)
{
$request = [Net.FtpWebRequest]::Create($url)
if ($credentials) { $request.Credentials = $credentials }
$request.Method = [System.Net.WebRequestMethods+FTP]::ListDirectory
(New-Object IO.StreamReader $request.GetResponse().GetResponseStream()) -split "`r`n"
}
$webclient = New-Object System.Net.WebClient
$webclient.Credentials = New-Object System.Net.NetworkCredential($ftpUser,$ftpPass)
$webclient.BaseAddress = $ftpPath
Foreach ( $item in $Files )
{
Get-FTPDir $ftpPath $webclient.Credentials |
? { $_ -Like $item+$Date+'*' } |
% {
$webClient.DownloadFile($_, (Join-Path $localPath $_))
}
}
It's not easy with the FtpWebRequest. For your task, you need to know file timestamps.
Unfortunately, there's no really reliable and efficient way to retrieve timestamps using features offered by FtpWebRequest/.NET framework/PowerShell as they do not support an FTP MLSD command. The MLSD command provides listing of remote directory in a standardized machine-readable format. The command and the format is standardized by RFC 3659.
Alternatives which you can use, that are supported by .NET framework:
ListDirectoryDetails method (an FTP LIST command) to retrieve details of all files in a directory and then you deal with FTP server specific format of the details (*nix format similar to ls *nix command is the most common, drawback is that the format may change over time, as for newer files "May 8 17:48" format is used and for older files "Oct 18 2009" format is used)
GetDateTimestamp method (an FTP MDTM command) to individually retrieve timestamps for each file. Advantage is that the response is standardized by RFC 3659 to YYYYMMDDHHMMSS[.sss]. Disadvantage is that you have to send a separate request for each file, what can be quite inefficient.
Some references:
C# class to parse WebRequestMethods.Ftp.ListDirectoryDetails FTP response
Parsing FtpWebRequest ListDirectoryDetails line
Retrieving creation date of file (FTP)
Alternatively, use a 3rd party FTP library that supports the MLSD command, and/or supports parsing of the proprietary listing format.
For example WinSCP .NET assembly supports both.
An example code:
# Load WinSCP .NET assembly
Add-Type -Path "WinSCPnet.dll"
# Setup session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property #{
Protocol = [WinSCP.Protocol]::Ftp
HostName = "example.com"
UserName = "user"
Password = "mypassword"
}
$session = New-Object WinSCP.Session
# Connect
$session.Open($sessionOptions)
# Get list of files in the directory
$directoryInfo = $session.ListDirectory($remotePath)
# Select the most recent file
$latest =
$directoryInfo.Files |
Where-Object { -Not $_.IsDirectory } |
Sort-Object LastWriteTime -Descending |
Select-Object -First 1
# Any file at all?
if ($latest -eq $Null)
{
Write-Host "No file found"
exit 1
}
# Download the selected file
$sourcePath = [WinSCP.RemotePath]::EscapeFileMask($remotePath + $latest.Name)
$session.GetFiles($sourcePath, $localPath).Check()
For a full code, see Downloading the most recent file (PowerShell).
(I'm the author of WinSCP)
I tried this, but i get an error:
Error: Exception calling "ListDirectory" with "1" argument(s): "Error listing directory '/path/'.
Could not retrieve directory listing
Can't open data connection for transfer of "/path/"
I read a lot about this problem on the internet, but could not find a solution which seemed fairly simple, and I am not a network setup wizard. So I choose a different approach. In our case the filename of the file which I want to automate the download for, has the date specified in it: backup_2018_08_03_020003_1048387.bak
So we can get the file by using mget *2018_08_03* in a command line ftp session.
Our backup procedure is run every morning at 01.00 AM, so we have a backup each day that we can fetch.
Of course it would have been prettier and nicer to have a script that fetched the latest backup file based on the backup file timestamps, just in case that something went wrong with the latest backup or the backup file naming format changes. The script is just a script to fetch the backup for internal development purposes so its not a big deal if it breaks. I will look into this later and check whether i can make a cleaner solution.
I made a batch script which just asks for todays backup file with the ordinary ftp command prompt scripting.
It is important to get the formatting of todays date right. It must match the formatting of the date in the filename correctly.
If you want to use the script you should replace the variables with your own information. You should also have write access to the directory where you run it from.
This is the script that I made:
#Echo Off
Set _FTPServerName=xxx.xxx.xx.xxx
Set _UserName=Username
Set _Password=Password
Set _LocalFolder=C:\Temp
Set _RemoteFolder="/path/"
Set _Filename=*%date:~-4,4%_%date:~-7,2%_%date:~-10,2%*
Set _ScriptFile=ftptempscript
:: Create script
>"%_ScriptFile%" Echo open %_FTPServerName%
>>"%_ScriptFile%" Echo %_UserName%
>>"%_ScriptFile%" Echo %_Password%
>>"%_ScriptFile%" Echo lcd %_LocalFolder%
>>"%_ScriptFile%" Echo cd %_RemoteFolder%
>>"%_ScriptFile%" Echo binary
>>"%_ScriptFile%" Echo mget -i %_Filename%
>>"%_ScriptFile%" Echo quit
:: Run script
ftp -s:"%_ScriptFile%"
del "%_ScriptFile%"

TFS 2013 - Update MSBuild Parameters from pre-build PowerShell script

I have recently upgraded from TFS 2012 to TFS 2013 and am trying to use the new template (TfvcTemplate.12.xaml). I need to set the version numbers of my .NET applications and WiX installers as part of this process.
In my TFS 2012 process I customised the build template using TFS Community Build Extensions to do the following:
Generate a version number. The Major and Minor version numbers are static, the release number is the number of days since 2014-11-25, the build number is the number of times the build definition has run today.
Update all AssemblyInfo.cs files with the new version number
Update the MsBuildArguments argument to pass the version as a parameter. This is so that I can set the version number in my WiX installers.
Before I resort to customising the build template again I would like to try to achieve the above using a Pre-build PowerShell script.
Items 1 and 2 were easy in PowerShell but I am stuck with the third requirement. Is it possible for the Pre-build PowerShell script to update the MSBuildArguments?
I think there is a simpler way to do this. This is what we did.
Created an include file called Version.wsi. The file contains these 4 lines:
<?xml version="1.0" encoding="utf-8"?>
<Include>
<?define CurrVersion="1.0.0.0" ?>
</Include>
In our wxs file, right after the line
<Wix xmlns:util="http://schemas.microsoft.com/wix/UtilExtension" xmlns="http://schemas.microsoft.com/wix/2006/wi" >
add the following:
<?include Version.wxi ?>
In your wxs file use the variable $(var.CurrVersion) where you currently specify your version.
Now all you need to include in your powershell script is some code to modify the wxi file with the correct version number. This is how I do it:
function UpdateVersion($newVersion)
{
$wxiFile = gci "$Somedir\Version.wxi"
#clear the read-only bit just in case
Set-ItemProperty $wxiFile -name IsReadOnly -value $false -Force
$newContent = $content -replace "1.0.0", $prodVersion
Set-Content -Path $wxiFile -Value $newContent
}

Nuget Powershell: how to add native dependencies? how to add files to a project inside a folder?

I'm creating a Nuget package that has native dependencies. I put them inside the package without problems by specifying additional file entries in the .nuspec file.
However, I also want to copy these to the output folder of the project that is going to use my package, so that the dependencies can be found at runtime.
My idea is to add the native dependencies to the project and set their BuildAction to CopyToOutputDirectory. This I have also managed with the PowerShell script below:
param($installPath, $toolsPath, $package, $project)
Function add_file($file)
{
$do_add = 1
foreach($item in $project.DTE.ActiveSolutionProjects[0].ProjectItems)
{
if ($item -eq $file)
{ $do_add = 0 }
}
if ($do_add -eq 1)
{
$added = $project.DTE.ItemOperations.AddExistingItem($file)
$added.Properties.Item("CopyToOutputDirectory").Value = 2
$added.Properties.Item("BuildAction").Value = 0
}
}
add_file(<dependency1>)
add_file(<dependency2>)
...
add_file(<dependencyN>)
So far so good.
But, now my project becomes completely polluted with these dependencies.
Is there a way to add files to a project using PowerShell and put them inside a folder?
Or is there another way to achieve what I want: adding native dependencies to a NuGet package and outputting them to the bin-folder of the project using my Nu-package?
The SqlServerCompact package did something similar, copying the relevant dlls to the bin folder in the post build event. Here the relevant code:
File:install.ps1
param($installPath, $toolsPath, $package, $project)
. (Join-Path $toolsPath "GetSqlCEPostBuildCmd.ps1")
# Get the current Post Build Event cmd
$currentPostBuildCmd = $project.Properties.Item("PostBuildEvent").Value
# Append our post build command if it's not already there
if (!$currentPostBuildCmd.Contains($SqlCEPostBuildCmd)) {
$project.Properties.Item("PostBuildEvent").Value += $SqlCEPostBuildCmd
}
File:GetSqlCEPostBuildCmd.ps1
$solutionDir = [System.IO.Path]::GetDirectoryName($dte.Solution.FullName) + "\"
$path = $installPath.Replace($solutionDir, "`$(SolutionDir)")
$NativeAssembliesDir = Join-Path $path "NativeBinaries"
$x86 = $(Join-Path $NativeAssembliesDir "x86\*.*")
$x64 = $(Join-Path $NativeAssembliesDir "amd64\*.*")
$SqlCEPostBuildCmd = "
if not exist `"`$(TargetDir)x86`" md `"`$(TargetDir)x86`"
xcopy /s /y `"$x86`" `"`$(TargetDir)x86`"
if not exist `"`$(TargetDir)amd64`" md `"`$(TargetDir)amd64`"
xcopy /s /y `"$x64`" `"`$(TargetDir)amd64`""
I'd suggest you open the 4.0.8852.1 version of the SqlServerCompact Nuget package with NuGet Package Explorer (Microsoft Store, GitHub) and use it as a template. It worked for me.

PowerShell - Download files with WebDAV

I want to use PowerShell with WebDAV (https) to download multiple files from a folder. The name from the download files is unknown. So my plan is to download all files from this folder and create a cleaning job at the server.
At the moment I´m searching for a good PowerShell with WebDAV example. Does anybody know a good example?
I don't try it but do you just test WebClient class?
PS > $source = "http://www.unsite.fr/untruc.zip"
PS > $destination = "c:\temp\untruc.zip"
PS >
PS >$wc = New-Object System.Net.WebClient
PS >$wc.DownloadFile($source, $destination)
----Edited------
Do you try to dig into ADODB.stream com object as you cansee in : "PowerShell : Upload file to WebDav Server"
Take a look at: http://amarchuk.blogspot.com/2011/10/heres-c-webdav-client-that-works-with.html
You can store it as cs file, then call add-type to add it to powershell and from there on client.GetListItems to get names and then download all files recursively.