I'm not sure if this is a typographical error or a logical error, but I will reformat your code a bit so the problem is more evident...
$servers = Get-Content -Path "C:\Temp\reviewfileversion\servers.txt"
$versioupdated = "16.11.32106.195"
foreach ($server in $servers) {
$version = Invoke-Command -ComputerName $server -ScriptBlock {
Get-ChildItem "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\devenv.exe"
| ForEach-Object { $_.VersionInfo.productversion }
If ($version -eq $versioupdated) {
Write-Host "updated"
}
else {
Write-Host "no updated"
}
}
}
Now it's clear that the -ScriptBlock
parameter encompasses not just the Get-ChildItem ... | ForEach-Object ...
pipeline but also the If...else...
block that follows.
Local session variables in a remote [ScriptBlock]
The pipeline is yielding the VersionInfo.ProductVersion
property of the devenv.exe
file, which will be assigned to the local variable $version
, but you can't then use that same variable in remote code...
If ($version -eq $versioupdated) {
$versioupdated
is also only defined locally, so that comparison becomes effectively...
If ($null -eq $null) {
...which is always $true
.
The shortest path to making your code work is to simply move one closing brace such that the remote code only obtains the ProductVersion
property and the local code performs the actual comparison...
$servers = Get-Content -Path "C:\Temp\reviewfileversion\servers.txt"
$versioupdated = "16.11.32106.195"
foreach ($server in $servers) {
$version = Invoke-Command -ComputerName $server -ScriptBlock {
Get-ChildItem "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\devenv.exe"
| ForEach-Object { $_.VersionInfo.productversion }
}
If ($version -eq $versioupdated) {
Write-Host "updated"
}
else {
Write-Host "no updated"
}
}
If you really did want to perform the comparison remotely you could define $versioupdated
inside the [ScriptBlock]
so it is a remote variable...
$servers = Get-Content -Path "C:\Temp\reviewfileversion\servers.txt"
foreach ($server in $servers) {
Invoke-Command -ComputerName $server -ScriptBlock {
$versioupdated = "16.11.32106.195"
# Get-ChildItem is unnecessary when retrieving a single file
$file = Get-Item "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\devenv.exe"
If ($file.VersionInfo.ProductVersion -eq $versioupdated) {
Write-Host "updated"
}
else {
Write-Host "no updated"
}
}
}
...or as above but just compare against the string literal instead...
If ($file.VersionInfo.ProductVersion -eq "16.11.32106.195") {
Write-Host "updated"
}
else {
Write-Host "no updated"
}
...or define it as a local variable and pass it as parameter to the [ScriptBlock]
using -ArgumentList
...
$servers = Get-Content -Path "C:\Temp\reviewfileversion\servers.txt"
$versioupdated = "16.11.32106.195"
foreach ($server in $servers) {
Invoke-Command -ComputerName $server -ArgumentList $versioupdated -ScriptBlock {
param($requiredVersion)
# Get-ChildItem is unnecessary when retrieving a single file
$file = Get-Item "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\devenv.exe"
If ($file.VersionInfo.ProductVersion -eq $requiredVersion) {
Write-Host "updated"
}
else {
Write-Host "no updated"
}
}
}
...or specify the Using:
scope to identify the variable as coming from the local session...
$servers = Get-Content -Path "C:\Temp\reviewfileversion\servers.txt"
$versioupdated = "16.11.32106.195"
foreach ($server in $servers) {
Invoke-Command -ComputerName $server -ScriptBlock {
# Get-ChildItem is unnecessary when retrieving a single file
$file = Get-Item "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\devenv.exe"
If ($file.VersionInfo.ProductVersion -eq $Using:versioupdated) {
Write-Host "updated"
}
else {
Write-Host "no updated"
}
}
}
Comparing version strings
You also mentioned that you want to...
... compare a file's version to a specified version and tell me which one is higher.
Comparing [String]
instances with the -eq
operator, of course, will only tell you if the [String]
s are identical. You probably won't bump into it with the [FileVersionInfo]
class, but [String]
comparisons will give you undesirable results for cases like this...
PS> '1.2.3.4' -eq '01.02.03.04'
False
...or this...
PS> '1.0.0.0', '2.0.0.0', '10.0.0.0' | Sort-Object
1.0.0.0
10.0.0.0
2.0.0.0
Instead, convert your version [String]
s to instances of the [Version]
class, which knows how to compare each component of the version...
PS> [Version] '1.2.3.4' -eq [Version] '01.02.03.04'
True
...as well as determine ordering...
PS> '1.0.0.0', '2.0.0.0', '10.0.0.0' | Sort-Object -Property { [Version] $_ }
1.0.0.0
2.0.0.0
10.0.0.0
You can incorporate [Version]
comparisons into your code like this...
$servers = Get-Content -Path "C:\Temp\reviewfileversion\servers.txt"
[Version] $versioupdated = "16.11.32106.195"
foreach ($server in $servers) {
Invoke-Command -ComputerName $server -ScriptBlock {
# Get-ChildItem is unnecessary when retrieving a single file
$file = Get-Item "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\devenv.exe"
[Version] $fileProductVersion = $file.VersionInfo.ProductVersion
If ($fileProductVersion -eq $Using:versioupdated) {
Write-Host "same"
}
elseif ($fileProductVersion -gt $Using:versioupdated) {
Write-Host "newer"
}
else {
Write-Host "older"
}
}
}