I was looking for some assistance with some code I've been working on, which has been designed to check your current OS architecture, and to run the relevant uninstaller for TeamViewer depending on the values returned...
Please forgive my basic Powershell knowledge, but I've knocked together the below, and I'm getting the following error:
Start-Process : This command cannot be run due to the error: The system cannot find the file specified.
It's almost like if it can't find the initial uninstaller, then the code stops.
if ((gwmi win32_operatingsystem | select osarchitecture).osarchitecture -eq "64-bit")
{
#64 bit TeamViewer Uninstall
Start-Process -FilePath "C:\Program Files\TeamViewer\uninstall.exe"
$StartTVUninstaller = New-Object -ComObject wscript.shell;
Sleep 2
$StartTVUninstaller.SendKeys('~')
Sleep 10
$StartTVUninstaller.SendKeys('%{F4}')
sleep 2
Stop-Process -name Un_A
}
else
{
#32 bit TeamViewer Uninstall
Start-Process -Filepath "-file C:\Program Files (x86)\TeamViewer\uninstall.exe"
$StartTVUninstaller_32 = New-Object -ComObject wscript.shell;
Sleep 2
$StartTVUninstaller_32.SendKeys('~')
Sleep 10
$StartTVUninstaller_32.SendKeys('%{F4}')
sleep 2
Stop-Process -name Un_A
}
Ignore the 'SendKeys' elements for now, this is more for when the Uninstaller has launched and will attempt to make the uninstallation process seemless.
The reason this is being done this way, is due to TeamViewer being deployed en masse using the executable, and not a custom packaged MSI.
Hopefully someone can point me in the right direction.
Related
I am new to scripting in general and am trying to tackle the task of writing a PowerShell script to automate accepting RSA keys from PuTTY across some 15,000 servers in my organization. I have the servers saved in a .bat file and when running that it will auto login through PuTTY. The issue is when it logs in A RSA security window will pop up requiring me to hit "y" I have that part and closing PuTTY so the next instance will be loaded, the only issue is I cant get the process to loop. I am looking for some guidance on the issue.
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
#Variables
$batFile = Start-Process -FilePath "C:\Users\UID\OneDrive - CompanyA\PS Scripts\puttyRSA.bat";
New-Object -ComObject wscript.shell;
#opens the "puttyRSA.bat" file
$batFile
#Loops everything
do{
# Will click "Y"
$wshell = New-Object -ComObject wscript.shell;
$wshell.AppActivate('title of the application window')
Start-Sleep -Seconds 3
$wshell.SendKeys('y')
#Waits and closes putty
Start-Sleep -Seconds 3
Stop-Process -name putty
}
While (-FilePath puttyRSA.bat=running)here
Assuming you want to keep running until $batFile finishes, your while clause isn't valid PowerShell. You'll have to make two changes here.
First, you'll need to kick off $batFile with Start-Process so you can get the PID to wait on:
# -PassThru is required because by default Start-Process doesn't return an object
$processId = ( Start-Process -FilePath $batFile -PassThru ).Id
Then, for your while clause:
} while ( Get-Process -Id $processId 2>$null )
This will keep your loop running until the process belonging to $batFile ends. The 2>$null redirects the error stream to $null, so it won't display an error when the process can no longer be found.
You can read more on output streams and redirection on my answer here.
I'm trying to make a silent install of an AMD driver with Powershell, but for some reason, I always get the AMD installation screen.
My arguments seem to be ok because I do not have to click anywhere and the installation completes by itself.Is there any way to install it without any windows popping up? I can install 7zip silently the same way without any problem.
Set-ExecutionPolicy Unrestricted
$Logpath = 'C:\powershell.log'
function Install_app
{
$exe_to_execute = 'C:\Setup.exe'
$argument = '/unattended_install:"..\Packages\Drivers\Display\W76A_INF;..\Packages\Drivers\amdkmpfd\W764a;..\Packages\Apps\ACP64;..\Packages\Apps\AppEx;..\Packages\Apps\CCC2;..\Packages\Apps\CIM;..\Packages\Apps\VC12RTx64\" /autoaccept_all /force_hide_first_run /force_close_when_done /on_reboot_message:no'
$process = Start-Process -FilePath $exe_to_execute -ArgumentList $argument -Wait -PassThru -NoNewWindow
# Loop until process exits
do {start-sleep -Milliseconds 500}
until ($process.HasExited)
# Log results
$(Get-Date).ToString() + " Exit code " + $process.ExitCode | Out-File $Logpath -Append
}
Install_app
My script is in fact actually working as it is. The problem is that it will only hide all setup windows if run under the system account.
I have a .ps1 script for installing a piece of software with Wait-Process that was created with ISE on a W7 machine that when I try to run it on W10, it errors out. Here is the script up until failure:
#Runs EnterpriseRx installer configured for PROD:
.\"EnterpriseRx.exe" /q /installType=0 /facilityID=999 /targetEnv=PROD
/encryptFacility=0 /S /D=C:\McKesson\EnterpriseRx Production
#15 second notification letting user know install is running:
$wshell = New-Object -ComObject Wscript.Shell
$wshell.Popup("This process typically takes about 1 minute. You will be
notified when install is complete.",15,"EnterpriseRx - PROD is
installing...",0x1)
#Wait for application to finish installing:
Wait-Process -name "EnterpriseRx.exe"
The error returned is this:
Wait-Process : Cannot find a process with the name "EnterpriseRx.exe".
Verify the process name and call the cmdlet again.
At C:\temp\EnterpriseRx Install TEST\EnterpriseRx Production - Desktop.ps1:9
char:1
+ Wait-Process -name "EnterpriseRx.exe"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (EnterpriseRx.exe:String) [Wait-
Process], ProcessCommandException
+ FullyQualifiedErrorId :
NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.WaitProcessCommand
I've tried changing the name to match what is showing in Task Manager, but with no success; I get the same error message. Note: This process is a run-on-command.exe, I don't need to verify if it's running, I know it is running, I just need to know what it's running as.
Any ideas or suggestions?
While your installation is in progress, use another PowerShell window to run the following to find out what PowerShell sees for the process.
Get-Process | Where-Object {$_.path -match "EnterpriseRx.exe"}
It most likely sees the process name as simply "EnterpriseRx" without the .exe on the end.
An other attempt would be, starting the Process by Start-Process, as this Cmdlet will give you your Process-Object back. You can utilize this to wait:
#Runs EnterpriseRx installer configured for PROD:
$Process = Start-Process .\"EnterpriseRx.exe" -ArgumentList /q, /installType=0, /facilityID=999, /targetEnv=PROD,
/encryptFacility=0, /S, /D=C:\McKesson\EnterpriseRx, Production -PassThru
#15 second notification letting user know install is running:
$wshell = New-Object -ComObject Wscript.Shell
$wshell.Popup("This process typically takes about 1 minute. You will be
notified when install is complete.",15,"EnterpriseRx - PROD is
installing...",0x1)
#Wait for application to finish installing:
$Process | Wait-Process
This should work fine in PowerShell older than 3. I need to run two processes: wuapp.exe and desk.cpl with ScreenSaver's tab. The problem I have is that once I start wuapp.exe the process name shows up in Task Manager as explorer.exe - the current code works for wuapp.exe but not on every machine. The other thing is when I kill rundll32 other apps will close also. What do you suggest?
$wshell = New-Object -ComObject Wscript.Shell
Start-Process wuapp.exe
(New-Object -comObject Shell.Application).Windows() | foreach-object {$_.quit()}
Start-Process rundll32 desk.cpl,InstallScreenSaver
Stop-Process -ProcessName rundll32* -Force
I'm not entirely sure what you mean by wuapp.exe showing up as explorer.exe, but keeping track of the rundll32 process is fairly straightforward.
Use Start-Process with the PassThru parameter to have it return the process it creates:
$ScreenSaverCpl = Start-Process rundll32 desk.cpl,InstallScreenSaver -PassThru
# Call Stop-Process when no longer needed:
Stop-Process $ScreenSaverCpl
I would like to install a set of applications: .NET 4, IIS 7 PowerShell snap-ins, ASP.NET MVC 3, etc. How do I get the applications to install and return a value that determines if the installation was successful or not?
These answers all seem either overly complicated or not complete enough. Running an installer in the PowerShell console has a few problems. An MSI is run in the Windows subsystem, so you can't just invoke them (Invoke-Expression or &). Some people claim to get those commands to work by piping to Out-Null or Out-Host, but I have not observed that to work.
The method that works for me is Start-Process with the silent installation parameters to msiexec.
$list =
#(
"/I `"$msi`"", # Install this MSI
"/QN", # Quietly, without a UI
"/L*V `"$ENV:TEMP\$name.log`"" # Verbose output to this log
)
Start-Process -FilePath "msiexec" -ArgumentList $list -Wait
You can get the exit code from the Start-Process command and inspect it for pass/fail values. (and here is the exit code reference)
$p = Start-Process -FilePath "msiexec" -ArgumentList $list -Wait -PassThru
if($p.ExitCode -ne 0)
{
throw "Installation process returned error code: $($p.ExitCode)"
}
Depends. MSIs can be installed using WMI. For exes and other methods, you can use Start-Process and check the Process ExitCode.
msi's can also be installed using msiexec.exe, msu's can be installed using wusa.exe, both have a /quiet switch, /norestart and /forcerestart switches and a /log option for logging (specify the file name).
You can read more about the options if you call them with /?
Note: wusa fails silently when they fail, so you have to check the log file or eventlog to determine success.
I have implemented exactly what you are looking for at my current project. We need to automate deployment and instillation of n number of apps across multiple environments and datacenters. These scripts are slightly modified from the original version for simplicity sake since my complete code is reaching 1000 lines but the core functionality is intact. I hope this does what you are asking for.
This PS function pulls all the apps from the registry (what add/remove programs reads from) and then search's for the supplied app name and display version. In my code (PSM1) I run this function before I install to whether or not it is their and then afterword’s to verify that it got installed…. All this can be wrapped in one master function to manager flow control.
function Confirm-AppInstall{
param($AppName,$AppVersion)
$Apps = Get-ItemProperty Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*|?{$_.DisplayName -ne $Null}|?{$_.DisplayName -ne ""}
$Apps += Get-ItemProperty Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*|?{$_.DisplayName -ne $Null}|?{$_.DisplayName -ne ""}
$Installed = $Apps|?{$_.DisplayName -eq ""}|?{$_.DisplayVersion -eq ""}|select -First 1
if($Installed -ne $null){return $true}else{return $false}
}
This PS function will load a txt file that has the install commands prepopulated (one command per line). and run each line indivaduly and wait for the install to complete before moving on to the next.
function Install-Application{
param($InstallList = "C:\Install_Apps_CMDS.txt")
$list = gc -Path $InstallList
foreach ($Command in $list){
Write-Output ("[{0}]{1}" -f (Get-Date -Format G),$call)
#Make install process wait for exit before continuing.
$p = [diagnostics.process]::Start("powershell.exe","-NoProfile -NoLogo -Command $Command")
$p.WaitForExit()
Start-Sleep -Seconds 2
#Searches for the installer exe or msi that was directly opened by powershell and gets the process id.
$ProcessID = (gwmi -Query ("select ProcessId from Win32_Process WHERE ParentProcessID = {0} AND Name = '{1}'" -f $p.Id,$ParentProcessFile)|select ProcessId).ProcessId
#waits for the exe or msi to finish installing
while ( (Get-Process -Id $ProcessID -ea 0) -ne $null){
Start-Sleep -Seconds 2
$ElapsedTime = [int](New-TimeSpan -Start $P.StartTime -End (Get-Date)|select TotalSeconds).TotalSeconds
#install times out after 1000 seconds so it dosent just sit their forever this can be changed
if(2000 -lt $ElapsedTime){
Write-Output ('[{0}] The application "{1}" timed out during instilation and was forcfully exited after {2} seconds.' -f (Get-Date -Format G),$App.Name,(([int]$App.InstallTimeOut) * 60))
break
}
}
#clean up any old or hung install proccess that should not be running at this point.
Stop-Process -Name $ParentProcessName -ea 0 -Force
Stop-Process -Name msiexec -ea 0 -Force
}
}
The TXT file should be formatted as such... you will need to do you research on how to each app needs to be installed. a good resource is appdeploy.com
C:\Install.exe /q
C:\install.msi /qn TRANSFORMS='C:\transform.mst'
C:\install2.msi /qn /norestart
C:\install3.exe /quiet
Let me know if there are any errors I had to modify my existing code to remove the proprietary values and make this a little more simplistic. I am pulling my values from a custom XML answer sheet. But this code should work as I have supplied it.
If you would like for me to discuss more about my implementation let me know and i can make a more detailed explanation and also add more of the supporting functions that I have implemented.