Start application with specific name from powershell - powershell

I have application with the following name: "x64.Staging.1.0.0.99.ClientBootstrapper". I need install this app every week. From powershell i use this command
"./x64.Staging.1.0.0.99.ClientBootstrapper"
but every week version the version number changes and I have to change the my script. How I can update my script so that the script will automatically detect the latest version of the application and run it ?
I tried using the following:
$version=“x64.Staging.{0-9}.ClientBootstrapper.exe
./x64.Staging.$version.ClientBootstrapper.exe /qn
but this doesn't seem to work.

You could potentially do the following:
$exe = Get-ChildItem -Path "x64.Staging.[0-9]*.ClientBootstrapper.exe" -File | Sort-Object {
[version]($_.Name -replace 'x64\.Staging\.([0-9\.]+)\.ClientBootstrapper\.exe','$1' -replace '^\d+$','$0.0')
} -Descending |
Select-Object -First 1 | Resolve-Path -Relative
& $exe '/qn'
Explanation:
The strategy is to sort by the version string in the middle of the filename. -replace removes all characters in the file name except the version. ([0-9\.]+) matches one or more digits and dots. $1 is the capture group that represents the version string. Since a version object requires at least a major and minor number (3.2 for example), a .0 is appended to a lone, single digit that may show up in the version string.
Resolve-Path is just to return the relative path. It is not necessary as you could remove the command and then modify Select-Object -First 1 -Expand FullName

Related

Scripts executed by a WinRar self-extracting archive not behaving as expected

I have a self-extracting WinRar archive set up to run a powershell script upon completion. The script will launch, but specific commands do not give expected results.
In particular, I have the following command to find the installation path of an installed game (Risk of Rain 2).
Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | % { Get-ItemProperty $_.PsPath } | Where-Object {$_.DisplayName -like 'Risk of Rain 2'} | Select InstallLocation -ExpandProperty InstallLocation
When running the script by itself, I get the install path as expected.
F:\SteamLibrary\steamapps\common\Risk of Rain 2
When the script is launched (either before or after extraction), the command seems to run, but outputs nothing.
In testing, I removed everything but the following:
Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | % { Get-ItemProperty $_.PsPath }
This still works, outputting a list of installed applications. When I add the pipe to the "Where-Object" portion, it starts to fail.
My only guess is that WinRar is starting the scripts with some other parameters set.
I tried having Winrar start a .bat that will then run the .ps1 file, but had the same result. Same goes for running the archive as an administrator.
Is something funky with my powershell script, or am I just missing something with how Winrar handles things?
Thanks!
So according to your comment the archive uses underscore in place of spaces. So looking at your code we see this originally
Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | % { Get-ItemProperty $.PsPath } | Where-Object {$.DisplayName -like 'Risk of Rain 2'} | Select InstallLocation -ExpandProperty InstallLocation
Your error occurs when we try to include the Where-object. So I believe the solution to your problem should be to modify your code as such:
Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | % { Get-ItemProperty $_.PsPath } | Where-Object {$_.DisplayName -like 'Risk_of_Rain_2'} | Select InstallLocation -ExpandProperty InstallLocation
Essentially we changed the -like from 'Risk of Rain 2' to 'Risk_of_Rain_2'
I believe this should solve the problem as it is called by the WinRar it probably still uses the underscore name. Since you are checking for a like name that only indicates that it can include any number and type of characters after or before the words in the like string. The like string itself is exact.
So...WinRAR gives options for the SFX module used. I was using the default Zip.SFX module when I should have been using Zip64.SFX.
The powershell session it opened previously was 32-bit, which gives a different result when reading the installed programs from the registry.
If you have anything 32/64 bit specific in the commands being run after an extraction, make sure the right module is selected in the Advanced SFX options.
Thank you all for the help!
Advanced SFX options

Check file names and delete files with lower number in suffix

I have a following task on PowerShell:
I need to check files on remote machines:
For instance:
Get-ChildItem \\ServerName\data\
In this folder I have following files:
standard_file.0.tst
standard_file.1.tst
standard_file.2.tst
standard_file.3.tst
So, i need to delete files with lower number prefix (based on file name).
In the end, into the folder should be only one file with biggest prefix.
For instance:
standard_file.3.tst
I broke up my mind - and have no any ideas how to perform this.
Could you please push me to the right direction?
Thanks in advance.
You could use a regex to get the number and cast it to an int. Then sort the filenames by the number using the Sort-Object cmdlet so the file with the highest number will be the last. Then you select all objects using Select-Object and skip the last one and finally remove it using Remove-Item:
Get-ChildItem '\ServerName\data\' |
Sort-Object { [int][regex]::Match($_, '.*?(\d+)\.[^.]+$').Groups[1].Value } |
Select-Object -SkipLast 1 |
Remove-Item
Regex:
.*?(\d+)\.[^.]+$
This will gather all the files in the path that have numerical suffixes in their names. The way that is done is by using a regex to match all of the digits on the end of the basename. Sorting on the result of that match in descending order will put the wanted file on the top of the list. We then remove the remaining files by skipping that first result.
$path = "c:\temp"
Get-ChildItem $path | Where-Object{$_.BaseName -match "\.\d+$"} |
Sort-Object -Property {$_.BaseName -match "\.(\d+)$";[int]$Matches[1]} -Descending |
Select-Object -Skip 1 |
Remove-Item -Confirm:$false -WhatIf
Remove -WhatIf when you are sure that it will remove the files you want.

How to get a version number from an output

R&D has asked us to deploy a new outlook plugin to all the systems in the company... however, there is a catch. If you have any other plugins that are outdated from our company it will break them.. As such we need to determine if an endpoint has the plugin installed and what version it is. If its installed and less than version "X" then we need to update it. Another issue is that not everyone uses the plugins so we cant just push it to everyone and call it a day.
As such we found a query that will call WMI and spit out the output which we then write to a file. Running
"wmic product where "Vendor like '%Microsoft%'" get Name, Version > C:\temp\test.txt"
gives us output:
Name Version
First Plug-in for Microsoft Outlook 1.1.9.0
Second Plug-in for Microsoft Outlook 2.0.2.0
Third Plug-in for Microsoft Outlook 1.2.5.0
etc.
What we want to do is to parse each one of those and write the version to a file so we can then see if we need to deploy the new plugin or not.
Ex:
First.txt contains 1.1.9.0
Second.txt contain 2.0.2.0
etc.
If for example Test.txt has no "First" in it don't make a file at all. We pretty much have to use batch file to do this but should be able to also do this with PowerShell (although that will take some tweaking as our deployment system isn't very powerful).
As such I was wondering if someone can point me in the right direction regarding how to do this on a Windows system.
Note: This answer answers the question as stated and may be of interest from a regex-matching perspective, but for a fundamentally better approach see rojo's comment on the question.
The following Powershell pipeline writes to individual files, named for the product (with extension .txt) and containing the version number, as requested:
Get-Content C:\temp\test.txt | Select-Object -Skip 1 | ForEach-Object `
{
if ($_ -match '^(.*[^ ]) +([^ ]+) *$') {
$fname = $matches[1] + '.txt'
$ver = $matches[2]
$ver > $fname
}
}
Note that the output files are written to the current directory.
Get-Content C:\temp\test.txt sends the contents of the file line by line through the pipeline.
Select-Object -Skip 1 skips the header line.
$_ -match '^(.*[^ ]) +([^ ]+) *$' matches the line at hand ($_) against a regular expression that uses capture groups ((...)) to capture the product name and the version number substrings, accessible through the elements of special match-info variable $matches.
$fname = $matches[1] + '.txt' appends .txt to the 1st capture group - the product name - and stores it in variable $fname.
$ver = $matches[2] saves the version number - the 2nd capture group - in variable $ver.
$ver > $fname simply writes the version number to the output file.
Note that PowerShell creates UTF-16 LE-encoded files when you use output redirection (>); to use a different encoding, use, e.g., $ver | Out-File -Encoding utf8.
If you want to call the entire PowerShell command from cmd.exe (a batch file), use the following:
powershell.exe -noprofile -command "Get-Content C:\temp\test.txt | Select-Object -Skip 1 | ForEach-Object { if ($_ -match '^(.*[^ ]) +([^ ]+) *$') { $fname = $matches[1] + '.txt'; $ver = $matches[2]; $ver > $fname } }"
To only use the 2nd whitespace-separated token of the plug-in name as the file name:
In both commands above, replace:
$fname = $matches[1] + '.txt'
with:
$fname = (-split $matches[1])[1] + '.txt'

Files sorting with version number in Powershell

I have this folder in a directory. With different version on them.
CD1,CD2,CD3,CD4,CD5,CD6,CD7,CD8,CD9,CD11,CD12
I'm new to powershell, can anyone help me to get the latest version folder from the above folders? Here CD12 is the latest folder. I can't use last modified time because I copy them at the same time.
$FolderName=(Get-ChildItem C:\Current\CD |Where-Object {$_.name -like "*CD*"}| sort{$_.name.Substring(2,2)}|Select-Object Name -Last 1).Name)
Write-Host "$FolderName"
I tried the above script and it did not help. Can anyone help me?
The next new version is CD13, and the script should get that folder
You can try something like below
$max_version = Get-ChildItem "C:\Current\" | Where-Object {$_.PSIsContainer}
| Foreach-Object {$_.Name} | Foreach-object {$_ -replace "CD", ""}
| measure -maximum | Select-Object -expand Maximum
Write-host ("CD" + $max_version)
Which will result in CD12
You almost have it. When I tried to run your code, I ran into two errors. First, you have an extra ')' at the end of the line causing a syntax error. Second, your 'SubString()' call is failing because you're trying to get the 3rd and 4th characters of a string without a 4th character ("CD1"). You don't need the scriptblock to your Sort command, though. You can just sort on the Name field.
$FolderName = Get-ChildItem C:\7005\Hot-Fix\CD | where Name -like "CD*" | sort Name | Select-Object -Last 1 -ExpandProperty Name
As a side note, this uses the PowerShell 3 syntax for Where-Object and Sort-Object to omit the {}. And it uses the -ExpandProperty parameter to Select-Object, so you don't have to wrap the whole thing in parens to get the Name property.
You could try this:
#requires -v 3
$baseFolder='C:\7005\Hot-Fix\CD'
$folder=dir $baseFolder\CD* -Directory |
? basename -CMatch 'CD\d{1,}' |
sort #{e={'{0:0000}' -f [int]($_ -replace '\D')}} -Descending |
select -First 1
Notice, I'm considering case sensitive matching; also, $folder contains what you're looking for.

Delete Directories based on time modified

I am using Powershell scripts to deploy the codebase on our remote servers.
One Major part of the script copies the current release to the server. Now I just need to keep the last two releases on the remote server and delete all others.
I Need to keep the latest two releases
Eg:
In the remote server, I have
//server001/Application/
Build_1_0_0_19
Build_1_0_0_18
Build_1_0_0_17
Build_1_0_0_16
I need to clear Builds _17 and _16 while deploying _19.
We can sort out the directories according to the time modified and the last two will come on top. Rest all are not required.
Can this be done through Powershell Scripts ?
P.S. The builds are not always in sequential order
You can do something like this:
#requires -version 2
Get-ChildItem //server001/Application/|
Sort-Object CreationTime -Descending|
Select-Object -Skip 2|
Remove-Item -Recurse -Confirm
Just remove the -Confirm switch once you are sure that it does what you want.
Here is a v1 compatible method:
$dirs = #(Get-ChildItem //server001/Application/)
$dirs|
Sort-Object CreationTime -Descending|
Select-Object -Last ($dirs.Count - 2)|
Remove-Item -Recurse -Confirm