I wrote a little PowerShell script that invokes different MSI files to install software. Sometimes I got the following error from Windows Installer:
Another program is being installed. Please wait until that installation is complete, and then try installing this software again.
How could I prevent this error before I invoke the MSI files? I tried to associate this with the process TrustedInstaller. I thought that the process would come up when the PC is installing something that blocks my installation. But unfortunately, sometimes my installations work fine although the process is running. Is there a definitive indication which could be caught with PS?
You want to see if the _MSIExecute Mutex is set.
Simply checking for a running msiexec.exe won't tell you because a) msiexec could be processing a UI sequence which doesn't block you or b) msiexec could have finished an install and be waiting for 10 minutes to spin down it's service.
try
{
$Mutex = [System.Threading.Mutex]::OpenExisting("Global\_MSIExecute");
$Mutex.Dispose();
Write-Host "An installer is currently running."
}
catch
{
Write-Host "An installer is not currently runnning."
}
In the meantime I found the following approach: Whenever an MSI based installation is currently running a specific regkey is set. This is more reliable than trusting any processes that are active at this time. The regkey is only set when an installation is running.
Test-Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Installer\InProgress"
Related
I'm installing SQL Data Tools via a PowerShell script. I run my script, but the final part where the Data Tools are installed fails (inside of the SQL installer window). If I run the script without that part, and install Data Tools manually it works.
The error is:
VS Shell installation has failed with exit code -2147205120.
The parts before this install .NET and SQL Server Management Studio. I don't think they're relevant to my issue, but I will post that part if requested. Here are the relevant parts. The first try block installs SQL SP1 (removed now for readability), the second installs Data Tools and SNAC_SDK.
try
{
Write-Host "Lauching SQL Server Data Tools install ..."
& "\\mynetworkpath\SSDTBI_x86_ENU.exe" "/ACTION=INSTALL" "/FEATURES=SSDTBI,SNAC_SDK" "/Q" "/IACCEPTSQLSERVERLICENSETERMS"
Write-Host "Installer launched ..."
}
catch
{
Write-Host "SQL Server Data Tools installation failed"
exit
}
I have tried juggling around the arguments for the Data Tools install part, and playing with the -wait verb to make sure SP1 is done for sure, but no luck.
EDIT: Per Matt's suggestion I added /NORESTART to my argument list, but now it doesn't install anything, and doesn't error either...
EDIT: Added updated code with quoted arguments. Still doesn't work, but I think it's closer than it was originally.
I think the comma in the arguments is the culprit here because powershell interprets entities separated by comma as an array.
You can see how parameters get passed with this little hack
& { $args } /ACTION=INSTALL /FEATURES=SSDTBI,SNAC_SDK /Q /IACCEPTSQLSERVERLICENSETERMS
which gives
/ACTION=INSTALL
/FEATURES=SSDTBI
SNAC_SDK
/Q
/IACCEPTSQLSERVERLICENSETERMS
To get rid of this problem you need to quote at least the FEATURES argument. I usually quote everything in those cases, just to be consistent, so
& { $args } "/ACTION=INSTALL" "/FEATURES=SSDTBI,SNAC_SDK" "/Q" "/IACCEPTSQLSERVERLICENSETERMS"
gives you the wanted parameters:
/ACTION=INSTALL
/FEATURES=SSDTBI,SNAC_SDK
/Q
/IACCEPTSQLSERVERLICENSETERMS
Update: Many installers return immediately after they have been called while the install process still runs in the background, which can be a bugger when the rest of the script depends on the install.
There are several methods to make powershell wait for a process exit. One of the shortest is to use Out-Null like this:
& "\\mynetworkpath\SSDTBI_x86_ENU.exe" "/ACTION=INSTALL" "/FEATURES=SSDTBI,SNAC_SDK" "/Q" "/IACCEPTSQLSERVERLICENSETERMS" | Out-Null
You may also want to look at $? or $LASTEXITCODE afterwards to check for errors.
I'm trying to install required software for integration tests. I'm having trouble with my install script though since the installer doesn't have a silent mode. It's an EXE rather than an MSI if that makes a difference.
Here is what I have currently:
- ps: "curl $env:DOWNLOAD_URL -OutFile $env:TMP\\$env:DOWNLOADED_FILENAME"
- ps: "& $env:TMP\\$env:DOWNLOADED_FILENAME"
When I run this in PowerShell on my local machine it launches the installer but I can't see any way to send keys (I need to send something like Alt+N, Alt+A, Alt+N, Alt+I, Alt+F).
The installer is for EnergyPlus building energy simulation software.
Try /S, this works for most cases. If, however, the installer is async, you can do trick like this, to make powershell wait for installer to exit:
start "" /wait "EnergyPlus-8.4.0-09f5359d8a-Windows-i386.exe" /S
I am trying to run a PowerShell script to uninstall owncloud-client from my Windows 10 virtual machine. The code shown below can be found at
https://chocolatey.org/packages/owncloud-client (tools\chocolateyUninstall.ps1)
I would like just to test the code by running it from PowerShell to see if it actually uninstalls the software.
$unfile = "ownCloud\uninstall.exe"
if (Test-Path "${Env:ProgramFiles(x86)}\$unfile") {
$unpath = "${Env:ProgramFiles(x86)}\$unfile"
} else {
$unpath = "${Env:ProgramFiles}\$unfile"
}
Uninstall-ChocolateyPackage 'owncloud-client' 'exe' '/S' "$unpath"
I run script from the directory that contains it by typying:
.\chocolateyUninstall.ps1
As output I get the following error:
Uninstall-ChocolateyPackage is not recognized as the name of cmdlet, function, script file, or operable program.
The Uninstall-ChocolateyPacakge.ps1 package is provided by chocolatey. I checked on my machine and this package is present under:
C:\ProgramData\chocolatey\helpers\functions\Uninstall-ChocolateyPackage.ps1
but still it is not recognized as cmdlet by powershell. How can I solve this problem? thanks
When running the installation/uninstallation scripts, Chocolatey first includes the Chocolatey PowerShell module. This is done in the background, and normally, the end user doesn't need to worry about it.
For what you are trying to do, you will need to first do an Import-Module on the Chocolatey module, to bring it into the current PowerShell session. You can find this here:
old: C:\ProgramData\chocolatey\lib\chocolatey\tools\chocolateyInstall\helpers\chocolateyInstaller.psm1
new: C:\ProgramData\chocolatey\helpers\chocolateyInstaller.psm1
That should allow you to test the script directly.
Alternatively, you could run the install of the package, and then run the uninstall to see if it works as well.
With the latest moderation tools, you don't need to check every package (I mean, unless it makes you feel safer). You can always check the automated tests. There's a status dot to the right of the package title.
You can find the test summary
owncloud-client v2.1.1.5837 - Passed - Package Test Results
https://chocolatey.org/packages/owncloud-client/2.1.1.5837
Tested 10 Feb 2016 12:51:22 +00:00
Tested against win2012r2x64 (Windows Server 2012 R2 x64)
Tested with the latest version of choco, possibly a beta version.
Tested with chocolatey-package-verifier service v0.4.0-15-g979d0cc
Install was successful.
Uninstall was successful.
https://gist.github.com/choco-bot/45f343e23cc12e101130#file-_summary-md
or explore the uninstall log directly.
https://gist.github.com/choco-bot/45f343e23cc12e101130#file-uninstall-txt
I'm a nub scripter and am trying to write a really simple script to taskkill 2 programs and then uninstall 1 of them.
I wrote it in Powershell and stuck it in SCCM for deployment...however every time I deploy it, it's not running the last line to uninstall the program.
Here's the code:
# Closing Outlook instance
#
taskkill /IM outlook.exe /F
#
# Closing Linkpoint instance
#
taskkill /IM LinkPointAssist.exe /F
#
# Uninstalling Linkpoint via uninstall string if in Program Files
#
MsiExec.exe /X {DECDCD14-DEF6-49ED-9440-CC5E562FDC41} /qn
#
# Uninstalling Linkpoint via WmiObject if installed manually in AppData
Get-WmiObject -class win32_product -Filter "Name like '%Linkpoint%'" | ForEach-Object { $_.Uninstall()}
#
Exit
Can someone help? SCCM says the script completes with no error and I know it's able to execute it since the taskkills work...but it's not uninstalling the program.
Thanks in advance for any input.
So, SCCM is running this script, and nothing in the script is going to throw an error.
If you want to throw an error which SCCM can return to know how the deployment went, you need to add an extra step.
$result = Get-WmiObject -class win32_product -Filter "Name like '%Linkpoint%'" | ForEach-Object { $_.Uninstall()}
if ($result.ReturnValue -ne 0){
[System.Environment]::Exit(1603)
}else
{
[System.Environment]::Exit(0)
}
I see a lot of these kinds of questions come through on SO and SF: Someone struggling with unexpected behavior of an application, script, or ConfigMgr and very little information about the assumptions I can make about their environment. At that stage, it would typically be days of interaction to narrow the problem to a point where a solution is possible.
I'm hoping this answer can serve as a reference for future such questions. The first question to OP should be "Which of these 9 principles are you violating?" You could think of it as a sort of Joel Test for ConfigMgr application packaging.
Nine Steps to Better ConfigMgr Application Packages
I have found that installing and uninstalling applications reliably using ConfigMgr requires carefully sticking to a bunch of principles. I learned these principles the hard way. If you're struggling to figure out why an application is not working right under ConfigMgr, odds are that you will answer "no" to one of the following questions.
1. Are you testing the entire lifecycle?
In order to have any hope of reliably managing an application you need to test the entire lifecycle of an application. This is the sequence I test:
Detect: make sure the detection script result is negative
Install: install the application using your installation script
Detect: make sure the detection script result is positive when run
Uninstall: uninstall using your uninstallation script
I run this sequence repeatedly making tweaks to each step until the whole sequence is working.
2. Are you testing independently of ConfigMgr first?
Using ConfigMgr to test your application's lifecycle is slow and has its own ways of failing that can mask problems with your application package. The goal, then, is to be able to test an application's installation, detection, and uninstallation separate from but equivalent to the ConfigMgr client. In order to achieve that goal you end up with three separate scripts for each application:
Install-Application.bat - the entry point for your installation script
Detect-Application.ps1 - the script that detects whether the application is install
Uninstall-Application.bat - the entry point for your uninstallation script
Each of these three scripts can be invoked directly by either you or the ConfigMgr client. For applications installed as system you need to use psexec -s to invoke scripts in the same context as ConfigMgr (caveat).
3. Are you aware of context?
Installers can behave rather differently depending on the context they are invoked in. You need to consider whether an application is installed for a user or the system. If it is installed for the system, when you test independently of ConfigMgr, use psexec -s to invoke your script.
4. Are you aware of user interaction?
An installer can also behave rather differently depending on whether a user can interact with it. To test a script as system with user interaction, use psexec -i -s.
5. Did you match ConfigMgr to the tested context and user interaction?
Once you have the full lifecycle working, make sure you select the correct corresponding options for context (installed for user vs. system) and interaction (user can interact with application, or not). If you don't do this, the ConfigMgr client will be installing the application different from the way you tested, so you really can't expect success.
6. Are you aware of the possibility of application detection context mismatch?
The context that detection scripts run in depends on whether the application is deployed to users or systems. This means that in some cases the installation and detection contexts won't matched. Keep this in mind when you write your detection scripts.
7. Have you structured your scripts so that exit codes work?
ConfigMgr needs to see exit codes from your installation and uninstallation scripts in order to do the right thing. Installers signal failure or the need to reboot using exit codes. In order for exit codes to get to the ConfigMgr client you need to ensure that your install and uninstall scripts are structured correctly.
for batch scripts, use exit /b %errorlevel% to pass the exit code of your executable out to the ConfigMgr client
for PowerShell scripts, this is the only way I have seen work reliably
8. Are you using PowerShell scripts for detection?
ConfigMgr has a nice user interface for checking things like the presence of files, registry keys, etc as a proxy for whether an application is installed. The problem with that scheme is that there is no way to test application detection separately from and equivalent to the ConfigMgr client. If you want to test the application lifecycle independent of the ConfigMgr client (trust me, you want that), all your detection must occur using PowerShell scripts.
9. Have you structured your PowerShell detection scripts correctly?
The rules ConfigMgr uses to interpret the output of a PowerShell detection script are arcane. Thankfully, they are documented.
I am trying to install a msi from a network share remotely.
$app = [WMICLASS]"\\$pcname\ROOT\CIMV2:Win32_Product"
$app.Install($AppPath)
I am getting an err 1619. From some sources say that WMI cannot install remotely with first coping it to the local computer and running it. Some sources use this command to exactly.
That way works great, but I want to install via share so when the developer updates this msi, it will update the installed instances automagiclly. If I install them locally, the update would not be detected (not sure of this).
So I have tried using methods along these lines:
Invoke-Command -ComputerName $pcname{ msiexec /quiet /i "\\appsvr\apps\theapp.msi" }
Those commands seem to go off into the blackhole, those that command works when run locally.
Anyone have a method for doing this that works?
In your last scenario, you're credentials are likely getting lost. This is known as the "double-hop authentication" (or maybe it's "second-hop") problem. You're using creds from ServerA, to run something on ServerB, but it in the end has to connect to ServerC.
There's a fix if you have PowerShell v2 installed everywhere and are willing to accept the implications:
http://blogs.msdn.com/powershell/archive/2008/06/05/credssp-for-second-hop-remoting-part-i-domain-account.aspx