Powershell Script for Verifying software is installed - powershell-4.0

I have been working with a powershell script to verify that a specific version of software is installed and at least a specific version. This is what I have and it works.
`$software = "Bitdefender Endpoint Security Tools";
$version = "7.8.1.244"
$installed = (Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Where { $_.DisplayVersion -eq $version }) -ne $null
If(-Not $installed) {
Write-Host "'$software' NOT is installed.";
} else {
Write-Host "'$software' is installed."
}
`
I am trying to set it to use something like -ge to verify that the version is greater than or equal to the above version. When I switch it to -ge instead of -eq it basically says everything is installed.
Is there a way around this?
I have tried
`$software = "Bitdefender Endpoint Security Tools";
$version = "7.8.1.244"
$installed = (Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Where { $_.DisplayVersion -ge $version }) -ne $null
If(-Not $installed) {
Write-Host "'$software' NOT is installed.";
} else {
Write-Host "'$software' is installed."
}
`

You could break down the version yourself by splitting the current version into it's counterparts:
Major release;
Minor release;
Bugfix release;
Build number.
Then for each release you can compare what is actually installed vs what your known latest version is:
Installed version is equal to last known (and company supported) version;
Installed version is lower than last known (and company supported) version;
Installed version is higher than last known (and company supported) version.

Related

Querying via powershell both 32bit and 64bit registry

I am running a script that queries windows and its registry.
I'm trying to add a code where it can query both 64bit and 32bit versions of the OS.
So if it's a 32bit then it should look at HKLM_SOFTWARE_TEAMVIEWER
and if it's 64bit it should query at HKLM_SOFTWARE_WOW6432Node_Teamviewer
So, how should this part look to query both locations depending on OS type?
$TVID = (Get-ItemProperty "HKLM:\SOFTWARE\TeamViewer").ClientID
This is the script:
Param(
[string]$ServerShare
)
$dom = $env:userdomain
$usr = $env:username
$Fullname = ([adsi]"WinNT://$dom/$usr,user").fullname
$TVID = (Get-ItemProperty "HKLM:\SOFTWARE\TeamViewer").ClientID
if (!$TVID) { $TVID = (Get-ItemProperty "HKLM:\SOFTWARE\TeamViewer\Version9").ClientID }
Apart from first detecting what bitness the computer uses, there is a simpler way I think by testing any of the two possible registry paths like:
# get the existing registry path (if any)
$regPath = 'HKLM:\SOFTWARE\TeamViewer', 'HKLM:\SOFTWARE\WOW6432Node\TeamViewer' | Where-Object { Test-Path -Path $_ }
if ($regPath) {
# we found the path, get the ClientID value
$TVID = (Get-ItemProperty -Path $regPath).ClientID
}
else {
Write-Warning "TeamViewer registry path not found"
}
You can check WMI under Win32_Processor and look at the process AddressWidth property to check your OS CPU AddressWidth.
#determine process version
[boolean]$is64bit = [boolean]((Get-WmiObject -Class "Win32_Processor" |
Where-Object {$_.DeviceID -eq 'CPU0'} | Select -ExpandProperty AddressWidth) -eq 64)
if ($is64bit){
#look here for 64 bit reg keys
Write-Output "x64 bit os detected"
}
else{
#look here for 32 bit reg keys
Write-Output " 32 bit os detected"
}
And run on my system
x64 bit OS Detected
Now all you need to do is merge your registry fetch code into the proper spots and you're on your way...
The easiest way to check OS bittness is to use .net.
[Environment]::Is64BitOperatingSystem

Remove accounts if lastusetime is older then value

Iam trying to create a task that will executed later with tasksch on the local machine, that will run everyday.
The task is, if a user has not logged in to the computer, it shall be removed from the computer.
The Thing is there is something wrong with my code and i dont know what
For now iam trying that the script shall remove testuser 1,2,3 and on testuser 4 is shall say Account is not old by using lastusetime.
System-info
OS Name: Microsoft Windows 10 Enterprise
OS Version: 10.0.17763 N/A Build 17763
Account-Info
#{Sid=S-1-5-21-3824012622-276487612-2647460976-1105; LocalPath=C:\Users\testuser4; LastUseTime=2019-05-13 19:27:57}
#{Sid=S-1-5-21-3824012622-276487612-2647460976-1109; LocalPath=C:\Users\testuser3; LastUseTime=2019-05-10 14:54:07}
#{Sid=S-1-5-21-3824012622-276487612-2647460976-1108; LocalPath=C:\Users\testuser2; LastUseTime=2019-05-10 14:54:07}
#{Sid=S-1-5-21-3824012622-276487612-2647460976-1107; LocalPath=C:\Users\testuser1; LastUseTime=2019-05-10 13:49:16}
# Start PS-Code
$DeleteIfLastUseTimetIsOlderThen = (get-date).AddDays(-5).tostring("yyyy-MM-dd hh:mm:ss”)
$GetLocalAccounts = Get-WmiObject -ComputerName localhost -Filter "Special=False" -Class Win32_UserProfile |
Select-Object Sid, LocalPath, #{Label='LastUseTime';Expression={$_.ConvertToDateTime($_.LastUseTime)} }
foreach ($UserAccount in $GetLocalAccounts)
{
if ($GetLocalAccounts.LastUseTime -Ge $DeleteIfLastUseTimetIsOlderThen )
{ Write-host "Account is old, Remove me"}
Else
{ Write-host "Account is not old"}
}
# End PS-Code
The thing is that it doesn't matter if I change the value "$DeleteIfLastUseTimetIsOlderThen " to 1,2,3,4 or 55, everything seems to be old.
The issue here is twofold. One is that you want to use a less than comparison when looking for an older date since a date in the past is less than a date in the future. Second, you want to compare each date in your collection ($GetLocalAccounts) with a specific fixed date ($DeleteIfLastUseTimeIsOlderThan). To do this with your code structure, you will need to check against the current object ($UserAccount) in your for loop.
# Start PS-Code
$DeleteIfLastUseTimetIsOlderThan = (get-date).AddDays(-5).tostring("yyyy-MM-dd hh:mm:ss”)
$GetLocalAccounts = Get-WmiObject -ComputerName localhost -Filter "Special=False" -Class Win32_UserProfile |
Select-Object Sid, LocalPath, #{Label='LastUseTime';Expression={$_.ConvertToDateTime($_.LastUseTime)} }
foreach ($UserAccount in $GetLocalAccounts)
{
if ($UserAccount.LastUseTime -le $DeleteIfLastUseTimetIsOlderThan )
{ Write-host "Account is old, Remove me"}
Else
{ Write-host "Account is not old"}
}
# End PS-Code

Running command on freeSSHD server with WinSCP fails with "Your shell is probably incompatible with the application (BASH is recommended)"

I am using below script to Verify checksum of a remote file against a local file. The server I installed on my machine is freeSSHd.
When I tried to execute the below script using PowerShell ISE I get an error message saying:
Your shell is probably incompatible with the application (BASH is recommended)
I've granted shell access in the FreeSSHd Server User properties:
Script:
param (
# Use Generate URL function to obtain a value for -sessionUrl parameter.
$sessionUrl = "sftp://user:mypassword;fingerprint=ssh-rsa-xx-xx-xx#example.com/",
[Parameter(Mandatory = $True)]
$localPath,
[Parameter(Mandatory = $True)]
$remotePath,
[Switch]
$pause = $False
)
try
{
Write-Host $localPath -foregroundcolor Gray
# Calculate local file checksum
$localChecksum = ((CertUtil -hashfile $localPath SHA1)[1] -replace " ","")
# Write-Host "Local Checksum:"
Write-Host $localChecksum
# Load WinSCP .NET assembly
#Add-Type -Path (Join-Path $PSScriptRoot "WinSCPnet.dll")
[Reflection.Assembly]::LoadFrom("\\c:\Program Files (x86)\WinSCP\WinSCPnet.dll") | Out-Null
# Setup session options
$sessionOptions = New-Object WinSCP.SessionOptions
$sessionOptions.ParseUrl($sessionUrl)
$session = New-Object WinSCP.Session
try
{
# Connect
$session.Open($sessionOptions)
Write-Host $remotePath -foregroundcolor Gray
# Calculate remote file checksum
$sha1Command = "bash sha1sum -b $remotePath | awk '{print `$1}'"
$result = $session.ExecuteCommand($sha1Command)
$result.Check()
$remoteChecksum = $result.Output;
#$remoteChecksum =
[System.BitConverter]::ToString($session.CalculateFileChecksum("sha-1", $remotePath))
# Write-Host "Remote Checksum:"
Write-Host $remoteChecksum
}
finally
{
# Disconnect, clean up
$session.Dispose()
}
# Compare cheksums
if ($localChecksum -eq $remoteChecksum)
{
Write-Host
Write-Host "Match" -foregroundcolor "green"
$result = 0
}
else
{
Write-Host
Write-Host "Does NOT match" -foregroundcolor "red"
$result = 1
}
}
catch [Exception]
{
Write-Host $_.Exception.Message
$result = 1
}
# Pause if -pause switch was used
if ($pause)
{
Write-Host "Press any key to exit..."
[System.Console]::ReadKey() | Out-Null
}
exit $result
FreeSSHd server does not support any "bash". Its "shell" is Windows cmd.exe.
Your code cannot work. Windows cmd.exe is not compatible with WinSCP.
Moreover FreeSSHd is pretty buggy, do not use it.
You should use another Windows SSH server.
You can use Windows build of OpenSSH. It would allow you to execute a PowerShell script on the server to calculate the checksum.
If you install Windows Subsystem for Linux, you may even get the sha1sum (but I'm not sure).
You can use Cygwin, if you need to simulate *nix environment on Windows.
You can use Bitvise SSH Server for personal use for free. Its SFTP server supports checksum calculation on its own, so you would be able to use WinSCP Session.CalculateFileChecksum method directly.
There are lot of other options.

How to get list of packages of a particular Visual Studio solution with nuget.exe command line

I would like to get a list of packages of my Visual Studio solution after I ran the nuget restore command.
How can I do it from command line or Powershell (oustide Visual Studio)?
You could run following PowerShell script to list all installed packages in your solution. Please modify the $SOLUTIONROOT as your solution path.
#This will be the root folder of all your solutions - we will search all children of this folder
$SOLUTIONROOT = "D:\Visual Studio 2015 Project\SO Case Sample\PackageSource"
Function ListAllPackages ($BaseDirectory)
{
Write-Host "Starting Package List - This may take a few minutes ..."
$PACKAGECONFIGS = Get-ChildItem -Recurse -Force $BaseDirectory -ErrorAction SilentlyContinue |
Where-Object { ($_.PSIsContainer -eq $false) -and ( $_.Name -eq "packages.config")}
ForEach($PACKAGECONFIG in $PACKAGECONFIGS)
{
$path = $PACKAGECONFIG.FullName
$xml = [xml]$packages = Get-Content $path
foreach($package in $packages.packages.package)
{
Write-Host $package.id
}
}
}
ListAllPackages $SOLUTIONROOT
Write-Host "Press any key to continue ..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

How can you find unused NuGet packages in solution?

How can you find the unused NuGet packages in a solution?
I've got a number of solutions where there are a lot of installed packages, and a large number of them are flagged as having updates.
However, I'm concerned there may be breaking changes, so I first want to clean up by removing any unused packages.
ReSharper 2016.1 has a feature to remove unused NuGet.
It can be run on a solution and on each project in a solution and it does the following things:
Analyze your code and collecting references to assemblies.
Build NuGet usage graph based on usages of assemblies.
Packages without content files, unused itself and without used dependencies are assumed as unused and suggested to remove.
Unfortunately, this doesn't work for project.json projects (RSRP-454515) and ASP.NET core projects (RSRP-459076)
Visual Studio 2019 (version 16.9) has the remove-unused-packages function built-in, we will need to enable it manually now.
Go to Tools > Options > Text Editor > C# > Advanced > (Under the Analysis section) Tick Show "Removed Unused References" command
Visual Studio version 16.10 has the remove unused reference feature available. Right-click on the project > Remove Unused References.
You can use the Visual Studio Extension ResolveUR - Resolve Unused References.
Resolve unused references including nuget references in Visual Studio 2012/2013/2015 projects via menu item at solution and project nodes Solution Explorer Tool Window
It's not an easy task, so I suggest to make a backup and/or commit before, just in order to rollback if something went wrong.
You can accomplish this using ReSharper 2019.1.1.
Right click on the project > Refactor > Remove Unused References.
If your project is small, you can also use: project > Optimize Used References . . .
A window will pop up. Select all references and remove them all. Then go back and re-add the ones that give you a compiler error.
Right-click on the Dotnet core project in visual studio 2019 you will see an option for Remove unused references.
Below is a little PowerShell script that finds redundant NuGet packages for .NET Core / .NET 5+ projects. For each project file it removes every reference once and checks if it compiles. This will take a lot of time. After this you get a summary of each reference that might be excluded. In the end it is up to you do decide what should be removed. Most likely you will not be able to remove everything it suggest (due dependencies), but it should give you a good starting point.
Save the script below as a ps1-file and replace the string C:\MySolutionDirectory in line 89 with the directory you want to scan on and then run the ps1-file. Do an backup first in case something goes wrong.
function Get-PackageReferences {
param($FileName, $IncludeReferences, $IncludeChildReferences)
$xml = [xml] (Get-Content $FileName)
$references = #()
if($IncludeReferences) {
$packageReferences = $xml | Select-Xml -XPath "Project/ItemGroup/PackageReference"
foreach($node in $packageReferences)
{
if($node.Node.Include)
{
if($node.Node.Version)
{
$references += [PSCustomObject]#{
File = (Split-Path $FileName -Leaf);
Name = $node.Node.Include;
Version = $node.Node.Version;
}
}
}
}
}
if($IncludeChildReferences)
{
$projectReferences = $xml | Select-Xml -XPath "Project/ItemGroup/ProjectReference"
foreach($node in $projectReferences)
{
if($node.Node.Include)
{
$childPath = Join-Path -Path (Split-Path $FileName -Parent) -ChildPath $node.Node.Include
$childPackageReferences = Get-PackageReferences $childPath $true $true
$references += $childPackageReferences
}
}
}
return $references
}
function Get-ProjectReferences {
param($FileName, $IncludeReferences, $IncludeChildReferences)
$xml = [xml] (Get-Content $FileName)
$references = #()
if($IncludeReferences) {
$projectReferences = $xml | Select-Xml -XPath "Project/ItemGroup/ProjectReference"
foreach($node in $projectReferences)
{
if($node.Node.Include)
{
$references += [PSCustomObject]#{
File = (Split-Path $FileName -Leaf);
Name = $node.Node.Include;
}
}
}
}
if($IncludeChildReferences)
{
$projectReferences = $xml | Select-Xml -XPath "Project/ItemGroup/ProjectReference"
foreach($node in $projectReferences)
{
if($node.Node.Include)
{
$childPath = Join-Path -Path (Split-Path $FileName -Parent) -ChildPath $node.Node.Include
$childProjectReferences = Get-ProjectReferences $childPath $true $true
$references += $childProjectReferences
}
}
}
return $references
}
$files = Get-ChildItem -Path C:\MySolutionDirectory -Filter *.csproj -Recurse
Write-Output "Number of projects: $($files.Length)"
$stopWatch = [System.Diagnostics.Stopwatch]::startNew()
$obseletes = #()
foreach($file in $files) {
Write-Output ""
Write-Output "Testing project: $($file.Name)"
$rawFileContent = [System.IO.File]::ReadAllBytes($file.FullName)
$childPackageReferences = Get-PackageReferences $file.FullName $false $true
$childProjectReferences = Get-ProjectReferences $file.FullName $false $true
$xml = [xml] (Get-Content $file.FullName)
$packageReferences = $xml | Select-Xml -XPath "Project/ItemGroup/PackageReference"
$projectReferences = $xml | Select-Xml -XPath "Project/ItemGroup/ProjectReference"
$nodes = #($packageReferences) + #($projectReferences)
foreach($node in $nodes)
{
$previousNode = $node.Node.PreviousSibling
$parentNode = $node.Node.ParentNode
$parentNode.RemoveChild($node.Node) > $null
if($node.Node.Include)
{
$xml.Save($file.FullName)
if($node.Node.Version)
{
$existingChildInclude = $childPackageReferences | Where-Object { $_.Name -eq $node.Node.Include -and $_.Version -eq $node.Node.Version } | Select-Object -First 1
if($existingChildInclude)
{
Write-Output "$($file.Name) references package $($node.Node.Include) ($($node.Node.Version)) that is also referenced in child project $($existingChildInclude.File)."
continue
}
else
{
Write-Host -NoNewline "Building $($file.Name) without package $($node.Node.Include) ($($node.Node.Version))... "
}
}
else
{
$existingChildInclude = $childProjectReferences | Where-Object { $_.Name -eq $node.Node.Include } | Select-Object -First 1
if($existingChildInclude)
{
Write-Output "$($file.Name) references project $($node.Node.Include) that is also referenced in child project $($existingChildInclude.File)."
continue
}
else
{
Write-Host -NoNewline "Building $($file.Name) without project $($node.Node.Include)... "
}
}
}
else
{
continue
}
dotnet build $file.FullName > $null
if($LastExitCode -eq 0)
{
Write-Output "Building succeeded."
if($node.Node.Version)
{
$obseletes += [PSCustomObject]#{
File = $file;
Type = 'Package';
Name = $node.Node.Include;
Version = $node.Node.Version;
}
}
else
{
$obseletes += [PSCustomObject]#{
File = $file;
Type = 'Project';
Name = $node.Node.Include;
}
}
}
else
{
Write-Output "Building failed."
}
if($null -eq $previousNode)
{
$parentNode.PrependChild($node.Node) > $null
}
else
{
$parentNode.InsertAfter($node.Node, $previousNode.Node) > $null
}
# $xml.OuterXml
$xml.Save($file.FullName)
}
[System.IO.File]::WriteAllBytes($file.FullName, $rawFileContent)
dotnet build $file.FullName > $null
if($LastExitCode -ne 0)
{
Write-Error "Failed to build $($file.FullName) after project file restore. Was project broken before?"
return
}
}
Write-Output ""
Write-Output "-------------------------------------------------------------------------"
Write-Output "Analyse completed in $($stopWatch.Elapsed.TotalSeconds) seconds"
Write-Output "$($obseletes.Length) reference(s) could potentially be removed."
$previousFile = $null
foreach($obselete in $obseletes)
{
if($previousFile -ne $obselete.File)
{
Write-Output ""
Write-Output "Project: $($obselete.File.Name)"
}
if($obselete.Type -eq 'Package')
{
Write-Output "Package reference: $($obselete.Name) ($($obselete.Version))"
}
else
{
Write-Output "Project refence: $($obselete.Name)"
}
$previousFile = $obselete.File
}
You find more information here: https://devblog.pekspro.com/posts/finding-redundant-project-references
In Visual Studio 2019 starting from the latest versions and Visual Studio 2022 you can remove unused packages as reported in previous comments, but only for SDK style projects.
If you try on old projects, like .Net Framework, you won't see this option.
As workaround, to verify, you can create two simply console apps: one using .Net Core or later, and one .Net Framework 4.7 or 4.8.
Please refer to: Remove Unused References
This is manual labor, but it works.
Use ReSharper or similar code analysis tool to identify any unused references in your projects and uninstall the nuget in the corresponding projects.
Sometimes uninstalled nugets still linger in the Installed packages and Updates lists in the Manage NuGet Packages dialog. Close Visual Studio then delete the packages folder, then reopen the solution and restore your nugets.
I don't think there is a default way to find this out. The primary reason being the variety of things these packages can do from referencing an assembly to injecting source code to your project. You may want to check the Nuget.Extensions though. The following thread on codeplex talks about an audit report of nuget packages.
http://nuget.codeplex.com/discussions/429694
(NuGet has been moved from Codeplex to GitHub. Archive of the above link:)
https://web.archive.org/web/20171212202557/http://nuget.codeplex.com:80/discussions/429694
In JetBrains Rider IDE
Right-click solution or project
"Refactor This"
"Remove Unused References"
Next...
https://www.jetbrains.com/help/rider/Refactorings__Remove_Unused_References.html

Resources