Powershell to Loop through each user profile to get Version number of software and then create uninstall string and run the command - powershell

Hoping someone can give me an idea on how to proceed with the remaining script.
The script is to get Version number of Installed Chrome from that build Build a string for the uninstall as shown below.
I'm stuck on the second part, fine on getting the version number.
What would the logic be next to then iterate through each user profile to run the setup.exe from C:\Users[username]\appdata\Local\Google\Chrome\Application\90.0.4430.72\Installer. The error I am getting is unrecognized cmdlet on the { & $unin}
Thank you
#UserHives - Find all the user profiles in the registry
$UserHives = Get-ChildItem Registry::HKEY_USERS\ |Where-Object {$_.Name -match '^HKEY_USERS\\S-1-5-21-[\d\-]+$'}
$UserProfile = $Env:USERPROFILE
#
foreach($user in $UserHives)
{
#1.Get Version Of chrome
#1. PATH TO SEARCH FOR
$Path = Join-Path $user.PSPath "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Google Chrome"
If (Test-Path $Path){
$GetVersion = Get-ItemProperty -Path $Path | Select-Object -Property Version
$VersionInstalled = $GetVersion.Version
#create uninstallstring
$UninString = "\Google\Chrome\Application\$VersionInstalled\Installer\setup.exe --uninstall --Channel --chrome --force-uninstall"
$unin = $UserProfile + "" + $UninString
If($VersionInstalled){ & $unin}
}
}

Quote from the docs:
The call operator does not parse strings. This means that you cannot
use command parameters within a string when you use the call operator.
Pass the arguments separately:
$uninArgs = "--uninstall", "--Channel", "--chrome", "--force-uninstall"
$uninExe = "$UserProfile\Google\Chrome\Application\$VersionInstalled\Installer\setup.exe"
if ($VersionInstalled) {
& $uninExe $uninArgs
}

Related

Powershell Detection Method - File path exists, and if so check filesize

I've got into a bit of a rut with this and I'm hoping someone can help me nail it:
I've been tasked with dropping a custom settings file into the roaming profile of the logged on user of all workstations.
The file would need to deployed if one of the 2 conditions are correct:
The file is not there.
The size of the file is smaller than that which is being deployed.
The deployment method is good, but the detection method is giving me a headache.
Andy Dawson's blog got me most of the way there, it's the file size (length) bit that's not working for me.
So, my first script went like this:
Part 1: Get logged on user
Function CurrentUser {
$LoggedInUser = get-wmiobject win32_computersystem | select username
$LoggedInUser = [string]$LoggedInUser
$LoggedInUser = $LoggedInUser.split(“=”)
$LoggedInUser = $LoggedInUser[1]
$LoggedInUser = $LoggedInUser.split(“}”)
$LoggedInUser = $LoggedInUser[0]
$LoggedInUser = $LoggedInUser.split(“\”)
$LoggedInUser = $LoggedInUser[1]
Return $LoggedInUser
}
Part 2: Assign User Path and Targetfile variables
$user = CurrentUser
$path = C:\Users\"+$user+"\AppData\Roaming\folder\folder\settings.cfg"
$targetfile = Get-Item $path
Part 3: Detect path exists and check filesize
if (( Test-Path $targetfile) -and ((Get-Item $targetfile).length -ge 26831))
{
Write-Host "installed"
}
else
{
Write-Host "NOT installed"
}
This works if condition 1 is satisfied, but if not the detection method would fail because $path variable and therefore $targetfile could not be populated.
I was using the $targetfile variable because other methods of getting .length seemed to be returning the character count (therefore string length) rather than the intended file size value.
Back to the drawing board. It seems I need to only commence with the rest of the script, assigning the is Condition 1 is NOT satisfied, so...
...My second (current) script goes like this:
Part 1: Get logged on user
UNCHANGED THIS BIT'S FINE, BECAUSE IS STOLE IT :)
Part 2: Assign User and Userpath variables (simplified as this one will always be found)
$user = CurrentUser
$Userpath = "C:\Users\"+$user
Part 3: If path is NOT there state exists and check filesize
if (-not (Test-Path "$Userpath\AppData\Roaming\folder\folder\settings.cfg"))
{
Write-Host "NOT installed"
}
elseif.....
...and this is where the rut sets in! I want the second check to be along the lines of ((Get-Item $targetfile).length -ge 26831)) as before but I just can't seem to get the syntax/logic right here.
Any help greatly appreciated!!!
You'll want to test whether the file doesn't exist OR is to small:
if(-not(Test-Path $targetFile) -or (Get-Item $targetFile).Length -lt $newFileSize){
# File either doesn't exist or is incomplete - go ahead and copy the new config file to $targetFile
Copy-Item .\path\to\reference\config.cfg -Destination $targetFile -Force
}

Output of Get-content as variable?

I am attempting to run a foreach loop on a get-content and convertfrom-json cmd. Now im aware this potentially has issues being multiple value results in the variable, im wondering how i can continue to pass this info to the rest of the script.
$testconv = Get-device * |select ID
$testid = $testconv.id
$conv = foreach ($id in $testid)
{
get-content "\\HDC-PRTG-03\System Information Database\Services\Device$id.Services" | Convertfrom-json
}
$rpccheck =$conv.message
$snmpcheck = $conv.message
$svcname = $conv.data.displayname
$svcstate=$conv.data.properties.state
if($RPCon = $rpccheck |select-string -pattern RPC -AllMatches){
write-host RPC Not enabled
}else{
write-host No RPC Enabled - Moving to Services List
Now when i run that with out the $conv= making it a variable it returns
kind : Services
recievetime : 29-01-2018 14:43:32
error : 106
Message : SNMP Channels Not Available.
Which is what i expect. However when i define it a variable with $conv= it just starts to say it cannot find the file paths which i find an odd error to throw but hey ho.
Do any of you smart guys have any pointers for how i can keep these fromjson objects in memory so i can continue to run foreach loops against them. The ultiumate function of this script is to query a local .services file for what services are running on the device and then create sensors to monitor them within our PRTG installation. Therefore i need to be able to ref the deviceID and apply things to it.
I suspect i may be using too many foreach loops in the whole script but frankly i am 100% out of my depth
any guidance hugely hugely appreciated
Sam
If i understand correctly you should have json files for all device ID's. If a file with the name of a particular device is missing you will get the 'File not found' error.
As for the code, you can try this:
$testconv = Get-Device * | select ID
$testid = $testconv.id
$oldErrorAction = $ErrorActionPreference
$ErrorActionPreference = 'Stop'
foreach ($id in $testid) {
try {
$conv = Get-Content -Path "\\HDC-PRTG-03\System Information Database\Services\Device$id.Services" -Raw | ConvertFrom-Json
$rpccheck = $conv.message # These look the same to me...
$snmpcheck = $conv.message # These look the same to me...
$svcname = $conv.data.displayname
$svcstate = $conv.data.properties.state
$Matches = ($rpccheck | Select-String -Pattern "RPC*" -AllMatches)
if ($Matches.Matches.Count) {
Write-Host "RPC Not enabled"
}
else {
Write-Host "No RPC Enabled - Moving to Services List "
}
}
catch {
Write-Warning $_.Exception.Message
}
}
$ErrorActionPreference = $oldErrorAction
Instead of the try{}..catch{} you could also first test if a file with that name is present using Test-Path directly before doing the Get-Content.

Locate MSTest.exe using powershell

I'm in the process of automating my .Net solution build to be completely in PowerShell. I want to locate MSTest.exe using PowerShell.
I used the following script to locate MSBuild.exe and I hope that I can have something similar to locate MSTest.exe
$msBuildQueryResult = reg.exe query "HKLM\SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0" /v MSBuildToolsPath
$msBuildQueryResult = $msBuildQueryResult[2]
$msBuildQueryResult = $msBuildQueryResult.Split(" ")
$msBuildLocation = $msBuildQueryResult[12] + "MSBuild.exe"
Any directions ?
The following works with Visual Studio 2010 and higher[1]:
# Get the tools folder location:
# Option A: Target the *highest version installed*:
$vsToolsDir = (
Get-Item env:VS*COMNTOOLS | Sort-Object {[int]($_.Name -replace '[^\d]')}
)[-1].Value
# Option B: Target a *specific version*; e.g., Visual Studio 2010,
# internally known as version 10.0.
# (See https://en.wikipedia.org/wiki/Microsoft_Visual_Studio#History)
$vsToolsDir = $env:VS100COMNTOOLS
# Now locate msbuild.exe in the "IDE" sibling folder.
$msTestExe = Convert-Path -EA Stop (Join-Path $vsToolsDir '..\IDE\MSTest.exe')
The approach is based on this answer and is generalized and adapted to PowerShell.
It is based on system environment variables VS*COMNTOOLS, created by Visual Studio setup, where * represents the VS version number (e.g., 100 for VS 2010).
Re option A: Sort-Object is used to ensure that the most recent Visual Studio installation is targeted, should multiple ones be installed side by side:
The script block used for sorting first extracts only the embedded version number from the variable name ($_.Name -replace '[^\d]'; e.g., 100 from VS100COMNTOOLS) and converts the result to an integer ([int]); [-1] then extracts the last element from the sorted array - i.e., the variable object whose names has the highest embedded version number - and accesses its value (.Value).
The IDE subfolder, in which MSTest.exe is located is a sibling folder of the tools folder that VS*COMNTOOLS points to.
If MSTest.exe is NOT in the expected location, Convert-Path will throw a non-terminating error by default; adding -EA Stop (short for: -ErrorAction Stop) ensures that the script is aborted instead.
[1]
- I've tried up to Visual Studio 2015; do let me know whether or not it works on higher versions.
- Potentially also works with VS 2008.
Perhaps you are wanting something like this?
$regPath = "HKLM:\SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0"
$regValueName = "MSBuildToolsPath"
$msBuildFilename = "MSBUild.exe"
if ( Test-Path $regPath ) {
$toolsPath = (Get-ItemProperty $regPath).$regValueName
if ( $toolsPath ) {
$msBuild = Join-Path $toolsPath $msBuildFilename
if ( -not (Test-Path $msBuild -PathType Leaf) ) {
Write-Error "File not found - '$msBuild'"
}
}
}
# Full path and filename of MSBuild.exe in $msBuild variable
My way of getting mstest path.
GetMSTestPath function is main function which you call and then if first GetMsTestPathFromVswhere function will find something it returns path if not your will be making a long search for mstest.exe. Usually, it takes approximately 10 sec. I know that this is not the best but at least it is something when you struggle to find mstest.exe. Hope it will be helpful for somebody. :)))
function GetMSTestPath
{
function GetTime()
{
$time_now = Get-Date -format "HH:mm:ss"
return $time_now;
}
function GetMsTestPathFromVswhere {
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
$path = & $vswhere -latest -prerelease -products * -requires Microsoft.Component.MSBuild -property installationPath
#write-host $path
if ($path) {
$tool = join-path $path 'Common7\IDE\MSTest.exe'
if (test-path $tool) {
return $tool
}
return ""
}
}
function SeachForMsTestPath
{
write-host $(GetTime)
$path = Get-ChildItem C:\ -Filter MSTest.exe -Recurse -ErrorAction Ignore | ? { $_.VersionInfo.FileDescription -eq 'Test Execution Command Line Tool' } | Select -First 1
write-host $(GetTime)
return $path
}
$msTestExePath = GetMsTestPathFromVswhere
if ([string]::IsNullOrEmpty($msTestExePath))
{
$msTestExePath = SeachForMsTestPath;
if ([string]::IsNullOrEmpty($msTestExePath))
{
Write-host "MsTest path is not found. Exiting with error"
Exit -1
}
}
return $msTestExePath;
}
Thanks #Bill_Stewart , I used your comments to write this working function:
function Get-MSTest-Location {
$msTests = #()
$searchResults = Get-ChildItem C:\* -Filter MSTest.exe -Recurse -ErrorAction Ignore
foreach($searchResult in $searchResults) {
try{
if(($searchResult.VersionInfo -ne $null) -and ($searchResult.VersionInfo.FileDescription -eq "Test Execution Command Line Tool"))
{ $msTests = $msTests + $searchResult.FullName }
}
catch{}
}
if($msTests.Length -eq 0)
{return "MSTest not found."}
return $msTests[0]
}

Powershell select filenames that match

List all filenames that match a pattern but can't seem to get it to list only the files I need I am eventually going to replace the filter with user input
$src = $env:ININ_TRACE_ROOT
$cmp = $env:COMPUTERNAME
$dst = $env:USERPROFILE + "\Desktop\" + $cmp
$lDate = Read-Host "Which Date?"
$s2 = $src + "\$ldate\"
$filter = "ip"
Get-ChildItem -Path $s2 | Where-Object { $_.Name -match $filter } | Select Name
Tried the above problem is it returns
accserver.zip
acdserver.zip
adminserver.zip
adminserver_1.zip
caasbillingserver.zip
caasproxyserver.zip
CallLog.zip
clientservices.zip
ClientStatsWkgQDataLog.zip
compressormanager.zip
datamanager.zip
dsserver.zip
fbmc.zip
hostserver.zip
httppluginhost.zip
i3runcrreport.zip
i3runcrreport_1.zip
i3runcrreport_2.zip
i3runcrreport_3.zip
imapconnector.zip
ininfaxserver.zip
interactionclient.zip
interactionrecoveryu.zip
ip.ininlog_journal
ip.zip
ipdbserver.ininlog_journal
ipdbserver.zip
ipserver.ininlog_journal
ipserver.zip
ip_1.zip
ip_10.zip
ip_11.zip
ip_12.zip
ip_13.zip
ip_14.zip
ip_2.zip
ip_3.zip
ip_4.zip
ip_5.zip
ip_6.zip
ip_7.zip
ip_8.zip
ip_9.zip
iwpserver.zip
LineGroupStatsDataLog.zip
mail account monitor.zip
mrcpsubsystem.zip
notifier.zip
notifierserver.zip
notifier_1.zip
notifier_2.zip
notifier_3.zip
optimizer server.zip
OutOfProcCustomDLL.zip
postofficeserver.zip
processautomationserver.zip
promptserver.zip
provisionserver.zip
QueuePeriodAgentStatsDataLog.zip
QueuePeriodWorkgroupStatsDataLog.zip
queuestatprovider.zip
recorder server.zip
RecoSubsystem.zip
remocoserver.zip
rstrapmonitor.zip
sessionmanager.zip
SIPEngine-mrcp.ininlog_journal
SIPEngine-mrcp.zip
SIPEngine.ininlog_journal
SIPEngine.zip
smsserver.zip
smtpconnector.zip
SNMPAgent.zip
statalertserver.zip
statserveragent.zip
statserveragent_1.zip
statserveragent_2.zip
statserverworkgroup.zip
statserverworkgroup_1.zip
statserverworkgroup_2.zip
surveyservice.zip
switchover.zip
switchoverfilemonitor.zip
tracker server.zip
tracker server_1.zip
transactionserver.zip
transactionserver_1.zip
transactionserver_2.zip
transactionserver_3.zip
transactionserver_4.zip
tsserver.zip
tsserver_1.zip
tsserver_2.zip
tsserver_3.zip
voicexml host server.zip
Problem is I need it to only return
ip.zip
ip_1.zip
ip_10.zip
ip_11.zip
ip_12.zip
ip_13.zip
ip_14.zip
ip_2.zip
ip_3.zip
ip_4.zip
ip_5.zip
ip_6.zip
ip_7.zip
ip_8.zip
ip_9.zip
Any ideas on how to achieve this
Updated using this now returns the list but is there a better way to do it?
$filter = "^ip[^server][^db][^ininlog_journal]"
Also this works but missing the non ip.zip
$filter = "^ip_[0-9]"
Since -match uses a regular expression, you should be able to write something like this:
get-childitem $s2 | where-object { $_.Name -match '^ip' }
(i.e., match when the Name property starts with ip).
See the about_Regular_Expressions help topic for more information.

How to find out what version of webdeploy/msdeploy is currently installed?

I'm looking for something like a Powershell script to check if msdeploy is installed and if it is, what version
I've considered checking "c:\Program Files\IIS" and checking for MSDeploy installations there, but is this always guaranteed to be the install location?
I need this to work on any given server machine
When msdeploy is installed (no matter where in the file system), it will add its install path to the registry at;
HKLM\Software\Microsoft\IIS Extensions\MSDeploy\<version>\InstallPath
and its version information to;
HKLM\Software\Microsoft\IIS Extensions\MSDeploy\<version>\Version
...where <version> is currently 1, 2 or 3 depending on the WebDeploy version you have installed.
Depends on what you consider "version". By the folder name "c:\Program Files\IIS\Microsoft Web Deploy V3", the version is 3, but if you run msdeploy.exe, the version is 7.X
This is what I did in my PowerShell script:
$WebDeployInstalled = Get-WmiObject Win32_Product | ? {$_.Name -like '*Microsoft Web Deploy*'}
if ($WebDeployInstalled -eq $null)
{
$msg = "Microsoft Web Deploy is not found on this machine."
Write-host -BackgroundColor Red -ForegroundColor White $msg
return
}
else
{
$MSDeployPath = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\IIS Extensions\MSDeploy\*" | Select-Object InstallPath
$MSDeployPath = $MSDeployPath.InstallPath
}
HTH
You can use the following PowerShell snippet:
$installPath = $env:msdeployinstallpath
if(!$installPath){
$keysToCheck = #('hklm:\SOFTWARE\Microsoft\IIS Extensions\MSDeploy\3','hklm:\SOFTWARE\Microsoft\IIS Extensions\MSDeploy\2','hklm:\SOFTWARE\Microsoft\IIS Extensions\MSDeploy\1')
foreach($keyToCheck in $keysToCheck) {
if(Test-Path $keyToCheck){
$installPath = (Get-itemproperty $keyToCheck -Name InstallPath -ErrorAction SilentlyContinue | select -ExpandProperty InstallPath -ErrorAction SilentlyContinue)
}
if($installPath) {
break;
}
}
}
If you wrap it into script block then you can call it in remote session.