Powershell Check versions number of installed program - powershell

i'm trying to get this code to work, but i cant get the version to match - can you help?
$Version = Get-ChildItem hklm:\software\microsoft\windows\currentversion\uninstall | ForEach-Object {Get-ItemProperty $_.pspath} | Where-Object {
$_.PSChildName -Eq '{BFAE8D5B-F918-486F-B74E-90762DF11C5C}'} | Select-Object Version
Write-Host $Version
if ($Version -eq 67436760)
{
Write-Host "Version match"
}
else
{
Write-Host "Not Matched"
}

The problem is that you are trying to compare an object to an integer. Since it's the wrong data type you will always get False returned.
To fix this you simply need add .Version, like this:
if ($Version.Version -eq 67436760)
{
Write-Host "Version match"
}
else
{
Write-Host "Not Matched"
}
That will retrieve the integer inside the object instead of the object itself.
Best regards

you need to capture that version variable better and convert it to an interger. Use:
Write-Host $Version
[int]$Version=$Version.version

Related

How to compare an item property to a string value

I am relatively new to PowerShell and cannot understand why my original attempts failed. I am attempting to validate the bit version of MS Office and perform actions off that. For whatever reason the strings were not comparing properly until I found a solution in the actual question here. Help understanding the difference between the two examples below would be much appreciated.
First attempt:
$getMSBitVersion= Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration" | Select-Object -Property Platform
if( $getMSBitVersion -eq "x64" ){
Write-Host "true"
} else {
Write-Host "false"
}
Working solution:
$getMSBitVersion= (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration" -Name Platform).Platform
if( $getMSBitVersion -eq "x64" ){
Write-Host "true"
} else {
Write-Host "false"
}
My assumption is the first is outputting an object instead of string and thus the comparison cannot be done. If this is the case, is the working solution the only way/best way to do this?
Thank you Mathias and Abraham.
From what I gather, the following are confirmed methods on how to make the desired comparison.
1: This will scope into the object property of "Platform" by using dot notation and return the string value instead of the whole object.
$getMSBitVersion= (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration" -Name Platform).Platform
if( $getMSBitVersion -eq "x64" ){
Write-Host "true"
} else {
Write-Host "false"
}
2: This will take all the properties of the Path and pass through to Select-Object. Select-Object will take and expand the "Property" object and return it as a string.
$getMSBitVersion= Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration" | Select-Object -ExpandProperty Platform
if( $getMSBitVersion -eq "x64" ){
Write-Host "true"
} else {
Write-Host "false"
}
I was unable to get this solution to function correctly, but should, in theory, work.
3: This, in theory, should work, but the two objects are recognized differently and do not compare as intended.
$getMSBitVersion= Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration" | Select-Object -Property Platform
$test= #{Platform="x64"}
if( Compare-Object $getMSBitVersion $test ){
Write-Host "true"
} else {
Write-Host "false"
}

Convert PowerShell object to use it on a condition

$version = Get-Module SharePointPnPPowerShellOnline -ListAvailable | Select-Object Version | Format-Table -HideTableHeaders | Out-String
Write-Output $version
With this I can get my PowerShell version, how can I convert it to use it in an if-else condition as an integer for example?
I think you can better use the version as type [Version]. That way you can compare easily enough and/or make use of its properties Major, Minor, etc indivudually
$version = [Version](Get-Module -Name SharePointPnPPowerShellOnline -ListAvailable).Version
if ($version -ge [Version]'3.23.2007.1') {
# do something
}
else {
# do something else
}
Edit
As JosefZ commented, the above does not check for a returned value of $null (not installed).
Nor does it check for the possibility that the cmdlet can return an array of versions in case there are more versions of the same module installed.
To overcome situations like that, you could do:
$module = 'SharePointPnPPowerShellOnline'
$version = [Version](Get-Module -Name $module -ListAvailable).Version |
Sort-Object | Select-Object -Last 1
if ($version) {
Write-Host "Module is installed. Current version $($version.ToString())"
if ($version -ge [Version]'3.23.2007.1') {
# do something (or not because the wanted version or higher is already installed)
}
else {
# do something else, like installing newer module
}
}
else {
Write-Warning "Module '$module' is not installed"
# do something, like installing the module
}

Cleanup PowerShell Command

I have been trying to re-format this command by making it cleaner but I just can't seem to get around the write-output.
Get-QARSOperation -ParentContainer 'somedomain.com/OU1/OU2' -TargetObjectType 'user' |
Where-Object {$_.Status -eq 'Completed' -and $_.Controls.ID -eq 'OperationReason'} |
ForEach-Object {Get-QARSApprovalTask -Operation $_.ID} |
ForEach-Object {
Write-OutPut ("Target: " + $_.Operation.TargetObjectInfo.DN.Replace("CN=","").Replace("cn=","").Replace("\","").Replace(",","").Replace("OU","").Split('=')[0]);
Write-OutPut ("Operation ID: "+ $_.Operation.ID);
Write-OutPut ("Approver: " + $_.CompletedBy.DN.Replace("CN=","").Replace("\","").Replace(",","").Replace("OU","").Split('=')[0]);
Write-OutPut ("StartedOn: " + $_.Created);
Write-OutPut ("Completed: " + $_.Completed);
Write-OutPut ("Comments: " + $_.CompletionReason);
Write-OutPut ("Operation Type: " + $_.Operation.Type);
Write-OutPut ""
}
Also the format when I export to csv doesn't put the data into columns. What suggestions do you have to make this script look neater?
Thank you!
As suggested in the comments the correct thing to do is use Export-Csv to generate a CSV file. As for creating an object that you want to export and making that easy to read in the code you could do something similar to what you have, and use it to create a custom object that could then be piped to Export-Csv. Also, I think your whole .Replace("CN=","").Replace("cn=","").Replace("\","").Replace(",","").Replace("OU","").Split('=')[0] can be simplified to .Split('=,')[1]. The string's .Split() method accepts multiple characters to split on, and it will split on any of the characters provided. Here's what I would suggest, you will need to update the path at the end, and may have to revert to your longer .Replace bit if mine doesn't work for you.
Get-QARSOperation -ParentContainer 'somedomain.com/OU1/OU2' -TargetObjectType 'user' |
Where-Object {$_.Status -eq 'Completed' -and $_.Controls.ID -eq 'OperationReason'} |
ForEach-Object {Get-QARSApprovalTask -Operation $_.ID} |
ForEach-Object {
[PSCustomObject][Ordered]#{
"Target" = $_.Operation.TargetObjectInfo.DN.Split('=,')[1]
"Operation ID" = $_.Operation.ID
"Approver" = $_.CompletedBy.DN.Split('=,')[1]
"StartedOn" = $_.Created
"Completed" = $_.Completed
"Comments" = $_.CompletionReason
"Operation Type" = $_.Operation.Type
}
} |
Export-Csv C:\Path\To\File.csv -NoTypeInformation
You could use a Select statement, but I think this looks cleaner for you.

Check text file content in PowerShell

The PowerShell command
Get-ADFSRelyingPartyTrust | select Name | out-file C:\listOfNames.txt
generates a file as follows:
Name
----
AustriaRP
BahamasRP
BrazilRP
CanadaRP
[...]
Now, how can I check if BrazilRP has been extracted and C:\listOfNames.txt contains it?
The Get-Content and then Select-String should help. If the string is in the file it will get returned. If not then the command will returned empty value.
Get-Content C:\listOfNames.txt | Select-String "BrazilRP"
If the "BrazilRP" occurs more than once all the occurrences will returned so you know if you got any duplicates. Same holds if the string is a part of a longer expression. For example if you search for "zil" then "BrazilRP" will be returned as well.
Also you can pipe the results out to another file:
Get-Content C:\listOfNames.txt | Select-String "BrazilRP" | Out-File C:\myResults.txt
I found a solution (but thanks to PiotrWolkowski to suggest me the Get-Content function):
$file = Get-Content "C:\listOfNames.txt"
$containsWord = $file | %{$_ -match "BrazilRP"}
if ($containsWord -contains $true) {
Write-Host "There is!"
} else {
Write-Host "There ins't!"
}
If you want to easily see if a file contains your text try this
The [bool] type returns the data as either true or false instead of returning the actual data your searching for
if ([bool]((Get-Content -Path "C:\listOfNames.txt") -like '*BrazilRP*')) {
write-host "found it"
}
else {
write-host "didnt find it"
}

What is the cleanest way to join in one array the result of two or more calls to Get-ChildItem?

I'm facing the problem of moving and copying some items on the file system with PowerShell.
I know by experiments the fact that, even with PowerShell v3, the cmdlet Copy-Item, Move-Item and Delete-Item cannot handle correctly reparse point like junction and symbolic link, and can lead to disasters if used with switch -Recurse.
I want to prevent this evenience. I have to handle two or more folder each run, so I was thinking to something like this.
$Strings = #{ ... }
$ori = Get-ChildItem $OriginPath -Recurse
$dri = Get-ChildItem $DestinationPath -Recurse
$items = ($ori + $dri) | where { $_.Attributes -match 'ReparsePoint' }
if ($items.Length -gt 0)
{
Write-Verbose ($Strings.LogExistingReparsePoint -f $items.Length)
$items | foreach { Write-Verbose " $($_.FullName)" }
throw ($Strings.ErrorExistingReparsePoint -f $items.Length)
}
This doen't work because $ori and $dri can be also single items and not arrays: the op-Addition will fail. Changing to
$items = #(#($ori) + #($dri)) | where { $_.Attributes -match 'ReparsePoint' }
poses another problem because $ori and $dri can also be $null and I can end with an array containing $null. When piping the join resutl to Where-Object, again, I can end with a $null, a single item, or an array.
The only apparently working solution is the more complex code following
$items = $()
if ($ori -ne $null) { $items += #($ori) }
if ($dri -ne $null) { $items += #($dri) }
$items = $items | where { $_.Attributes -match 'ReparsePoint' }
if ($items -ne $null)
{
Write-Verbose ($Strings.LogExistingReparsePoint -f #($items).Length)
$items | foreach { Write-Verbose " $($_.FullName)" }
throw ($Strings.ErrorExistingReparsePoint -f #($items).Length)
}
There is some better approch?
I'm interested for sure if there is a way to handle reparse point with PowerShell cmdlets in the correct way, but I'm much more interested to know how to join and filters two or more "PowerShell collections".
I conclude observing that, at present, this feature of PowerShell, the "polymorphic array", doen't appear such a benefit to me.
Thanks for reading.
Just add a filter to throw out nulls. You're on the right track.
$items = #(#($ori) + #($dri)) | ? { $_ -ne $null }
I've been on Powershell 3 for a while now but from what I can tell this should work in 2.0 as well:
$items = #($ori, $dri) | %{ $_ } | ? { $_.Attributes -match 'ReparsePoint' }
Basically %{ $_ } is a foreach loop that unrolls the inner arrays by iterating over them and passing each inner element ($_) down the pipeline. Nulls will automatically be excluded from the pipeline.