After fighting with this problem for two weeks I have finally found a working solution that allows you to generate log files of an install or un-install an MSI package on a remote machine. In recap, this stems off my first post of how to install an application on a remote machine using powershell. The problem with the Install() method is you cannot pass your standard parameters to the MSI, you can only pass MSI properties. Windows Installer 4.0 includes an MSI Property called “MsiLogging” which is used for this exact purpose; however Windows Installer 4.0 is only available in Windows Vista and Windows Server 2008 so unless you are targeting those exact operating systems, you are out of luck; well until now.
“One Sleazy Hack Deserves Another 5 Others!”
There is no question what we are about to do is pretty sleazy. It is sleazy for several reasons:
You cannot control where the file is written to.
You cannot give the file a specific name.
As long as the hack is in place it will log every MSI that is installed or un-installed so you should remove it when you are finished.
To compensate for these side effects, it will require us to additional sleazy things in PowerShell for clean up! All in all though, it does what we want it to do—generate log files!
Step 1: Hack the Registry
The first step requires hacking the registry to add a value to tell the MSI Installer to log. As long as this registry key is here, all MSI installs and un-installs are logged, so later on we will delete the key when we are finished.
Here is the list of variables that are going to be used throughout these examples so add them to your project and modify them as necessary.
$server = "assaria"
$computer = "deviisvm02", "assaria" #an array of computers
$valueName= "Logging"
$valueData = "voicewarmupx"
$keyPath = "Software\Policies\Microsoft\Windows\Installer"
$hive = [Microsoft.Win32.RegistryHive]::LocalMachine
$box = "assaria"
We have to create a string value in the following registry key on the remote machine: key:HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\Installer
string: Logging
value: “voicewarmupx”
Here is a function that will create a registry value on a remote machine:
function CreateRegistryValue([string]$computer, [string]$valName, [string]$valData)
{
#Get the remote key
$localMachineRegKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($hive,
$computer)
$installerRegKey = $localMachineRegKey.OpenSubKey($keyPath, $TRUE)
# Set registry value
$installerRegKey.SetValue($valName, $valData)
Write-Host "The registry value $valName has been created"
}
Step 2: Run your install
Here are 4 lines of code that will install your MSI package on a remote machine. Now, keep in mind the path I have below is the C drive on the remote machine, not the local machine.
$box=”deviis01” #this is the name of your server
$product= [WMICLASS]"\\$box\ROOT\CIMV2:win32_Product"
Write-Host "Installing software on $box"
$product.Install("c:\Setup\somesoftwarepackage.msi")
Step 3: Rename the Log File
When the install is finished, the log file is created in the Windows\Temp directory. (Note, if you are trying to create a log file on a local machine, it is located in the %temp% directory, not the Windows\Temp directory.) The log file has a name of MSI###.log with some random numbers. You can either just leave this as is, or if your like me and want to try and salvage some dignity in this project, I prefer to rename the file to something more readable. Here is the function you can call that will rename the file:
function RenameLogFile([string]$computer, [string]$fileName)
{
#Set the working location
Set-Location \\$computer\C$\Windows\Temp
# Rename the file
Get-ChildItem .\*.log | Rename-Item -NewName "$fileName.log"
Write-Host "Log file renamed to $fileName.log on $computer"
}
Step 4. Copy the File to a Different Location
It wouldn't be wise to just leave these log files in the Temp directory for obvious reasons, so as soon as our script finishes renaming the log file, we should move it to a different directory for archiving purposes . Below is the function you can use to copy your file to a different specified location on the remote computer:
function CopyLogFile([string]$computer, [string]$version, [string]$folder)
{
#Set the working location
Set-Location \\$computer\C$\Windows\Temp
Move-Item -path .\*.log -destination \\$computer\C$\Setup\$version\$folder\
Write-Host "Log file moved to $folder"
}
You don't have to worry about deleting the file out of Temp as the Move-Item literally moves the file and does not just copy it.
Step 5. Delete the Registry Value
Now that our file has been renamed and moved we need to delete the registry string value so that MSI logging isn't left on. I have seen first hand that this will clog your Temp directory full of logs, especially anytime you do something in Add/Remove programs. So to keep things in order, we will remove the value once we are finished. Here is the function to delete a registry value on a remote machine:
function DeleteRegistryValue([string]$valName, $server)
{
#Get the remote key
$localMachineRegKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($hive, $server)
$installerRegKey = $localMachineRegKey.OpenSubKey($keyPath, $TRUE)
# Delete registry value
$installerRegKey.DeleteValue($valName)
Write-Host "Registry Value $valName has been deleted on $box."
}
With these 5 steps you can do a powerful automated install or un-install with logging on a remote machine using PowerShell!
-Flea#
0 comments:
Post a Comment