Advanced installer powershell script set property - powershell

I am using advanced installer 10.7.1. I am adding the custom action of 'run windows powershell script'. What this script does is to check if the installer is being run on an azure vm or not. if it is, only then does it allow the user to install. The script runs fine on the vm, I've checked it. but now I need to display an error message on the basis of a script's result. which means I have to set some property in the script, on the basis of which I will display the error message.
can anybody tell me how to set advanced installer's property through a powershell script.

This is limitation of Windows Installer, not of Advanced Installer. PowerShell does not have access to the Session object of the installation, so you cannot set/get properties from a powershell script into an MSI, no matter the tool used to build the MSI.
The only custom actions that can be used to set a property (scheduled as immediate of course), are VBS scripts (inline or attached files) or DLLs written in C++ or C#. In C# is much easier as you have access to a lot of .NET API (but you also have the requirement of the .NET Framework to be on the end user machines).
#ravikanth
It takes only script text and there is no associated action based on the return value. Weird!
This is how Windows Installer works, i.e. the technology against which all MSI packages are built. More specifically, custom actions running into an MSI cannot use the return code to communicate "what ever they want" with the main installation progress. Windows Installer accepts only a strictly defined set of return codes, in the case of PowerShell custom actions in Advanced Installer, the return code is controlled in the background by the installer.
The scenario in which PS scripts are used in installations is that users usually need to them to make certain configurations on the machine, to prepare it for the installation. (like installing/activating Windows components, configuring network credentials, etc...) For very well and powerfully integrated custom code in the installers DLLs should be used as custom actions, as they provide a full cycle of communication (can get and set properties) and also can be debugged nicely into an IDE (by attaching to the installation process).

I don't know how Advanced Installer works but you can always return a value from the script and then use that value in the caller. For example,
#Custom Script action
#Get the VM details
If (AzureVM) {
$true
} else {
$false
}
Once you have the result from the script, use that to switch the path of installation or display messages.

For Future Reference:
Setting a property value from a script (for immediate custom actions)
To set a property simply include a line with the following syntax in your script:
AI_SetMsiProperty YOUR_PROP <VALUE>
Where YOUR_PROP is the property and <VALUE> is the value assigned to it.
NOTE: This only works with script that are set to run immediately.

Related

How to make parameter name suggestions work?

I'm trying to create a powershell module to store some reusable utility functions. I created script module PsUtils.psm1 and script module manifest PsUtils.psd1 (used these docs). My problem is that when I import this module in another script Visual Code does not suggest parameters names. Here's a screenshot:
When I hover cursor over the function I only get this:
PsUtils.psm1
function Get-Filelist {
Param(
[Parameter(Mandatory=$true)]
[string[]]
$DirectoryPath
)
Write-Host "DIR PATH: $DirectoryPath"
}
PsUtils.psd1 (excerpt)
...
FunctionsToExport = '*'
I have Powershell extension installed. Do I need to install anything else to make the suggestions work? What am I missing?
Generally speaking, only auto-loading modules - i.e., those in one of the directories listed in environment variable $env:PSModulePath - are automatically discovered.
As of version v2022.7.2 of the PowerShell extension, the underlying PowerShell editor services make no attempt to infer from the current source-code file what modules in nonstandard directories are being imported via source code in that file, whether via Import-Module or using module
Doing so would be the prerequisite for discovering the commands exported by the modules being imported.
Doing so robustly sounds virtually impossible to do with the static analysis that the editor services are limited to performing, although it could work in simple cases; if I were to guess, such a feature request wouldn't be entertained, but you can always ask.
Workarounds:
Once you have imported a given module from a nonstandard location into the current session - either manually via the PIC (PowerShell Integrated Console) or by running your script (assuming the Import-Module call succeeds), the editor will provide IntelliSense for its exported commands from that point on, so your options are (use one of them):
Run your script in the debugger at least once before you start editing. You can place a breakpoint right after the Import-Module call and abort the run afterwards - the only prerequisite is that the file must be syntactically valid.
Run your Import-Module command manually in the PIC, replacing $PSScriptRoot with your script file's directory path.
Note: It is tempting to place the cursor on the Import-Module line in the script in order to use F8 to run just this statement, but, as of v2022.7.2, this won't work in your case, because $PSScriptRoot is only valid in the context of running an entire script.
GitHub issue #633 suggests adding special support for $PSScriptRoot; while the proposal has been green-lighted, no one has stepped up to implement it since.
(Temporarily) modify the $env:PSModulePath variable to include the path of your script file's directory.
The most convenient way to do that is via the $PROFILE file that is specific to the PowerShell extension, which you can open for editing with psedit $PROFILE from the PIC.
Note: Make sure that profile loading is enabled in the PowerShell extension's settings.
E.g., if your directory path is /path/to/my/module, add the following:
$env:PSModulePath+="$([IO.Path]::PathSeparator)/path/to/my/module"
The caveat is that all scripts / code that is run in the PIC will see this updated $env:PSModulePath value, so at least hypothetically other code could end up mistakenly importing your module instead of one expected to be in the standard locations.
Note that GitHub issue #880 is an (old) proposal to allow specifying $env:PSModulePath entries as part of the PowerShell extension settings instead.
On a somewhat related note:
Even when a module is auto-discovered / has been imported, IntelliSense only covers its exported commands, whereas while you're developing that module you'd also like to see its private commands. Overcoming this limitation is the subject of GitHub issue #104.

How to add a location to windows 7/8 search index using batch or vbscript?

I'm trying to add a location (scope) to my Windows 8 Search Index programmatically, and after some googling, I found this code:
Set objISAdm = CreateObject("Microsoft.ISAdm")
Set objCatalog = objISAdm. GetCatalogByName("MyCatatlog")
Set objScope= objCatalog.AddScope("C:\myfiles",False)
objScope.Alias = "MyCatalogScope"
Unfortunately, a 800A01AD error prompts suggesting object Microsoft.ISAdm cannot be created; with some further digging, it seems the above code doesn't work with the newer version of Windows Search on Windows 8.
Does anyone know how to do that using VB scripts or from command line, presumably something works under windows 7 will work on Windows 8 as well?
Garett, you are a genius! This is the code I learned from the links you provided:
#Code copied from "Powershell Tackles Windows Desktop Search" http://powertoe.wordpress.com/2010/05/17/powershell-tackles-windows-desktop-search/
#Microsoft.Search.Interop.dll is needed, download from http://www.microsoft.com/en-us/download/details.aspx?id=7388
#Load the dll
Add-Type -path "D:\Unattend\UserFiles\Tools\Microsoft.Search.Interop.dll"
#Create an instance of CSearchManagerClass
$sm = New-Object Microsoft.Search.Interop.CSearchManagerClass
#Next we connect to the SystemIndex catalog
$catalog = $sm.GetCatalog("SystemIndex")
#Get the interface to the scope rule manager
$crawlman = $catalog.GetCrawlScopeManager()
#add scope
$crawlman.AddUserScopeRule("file:///D:\*",$true,$false,$null)
$crawlman.SaveAll()
Save the code as AddScope.ps1, and run it from a elevated cmd console:
PowerShell Set-ExecutionPolicy Unrestricted -force
PowerShell D:\Unattend\UserFiles\AddScope.ps1
That's it!
In the code you provided you're attempting to use the Indexing service interface. The indexing service is no longer available in Windows 8. From the documentation:
Indexing Service is no longer supported as of Windows XP and is
unavailable for use as of Windows 8. Instead, use Windows Search for
client side search and Microsoft Search Server Express for server side
search.
As the documentation states, you will want to look into Windows Search.
UPDATE:
I've not done this, but to accomplish what you are seeking the documentation states
Before you can use any of the Crawl Scope Manager (CSM) interfaces,
you must perform the following prerequisite steps:
Create the CrawlSearchManager object and obtain its ISearchManager interface.
Call ISearchManager::GetCatalog for "SystemIndex" to obtain an instance of an ISearchCatalogManager interface.
Call ISearchCatalogManager::GetCrawlScopeManager to obtain an instance of ISearchCrawlScopeManager interface.
After making any changes to the Crawl Scope Manager (CSM), you must
call ISearchCrawlScopeManager::SaveAll. This method takes no
parameters and returns S_OK on success.
Here's one example and another for doing this.
Unfortunately, I don't think this can be done from VBScript, because the COM interfaces provided by the Windows Search API don't implement the IDispatch interface, which allows scripting languages like VBScript to call COM objects via late binding.
Does it have to be from VBScript, or can you do it in .NET? If it has to be from VBScript then one approach would be to write a wrapper in .NET and expose it as a COM object.

Is there a way to access TeamCity system properties in a Powershell script?

I'm trying to set up a new build configuration in TeamCity using the Powershell runner. However, I can't seem to find a way to access the TeamCity System Properties in the build script. I've seen hints that it is possible, but cannot find documentation on how to do it.
I have tried accessing the system properties using Powershell variable syntax, $variable. I have also printed out all variables in memory and see no teamcity variables to use.
Is this possible with the Powershell runner, and if so what is the syntax necessary to get it working?
TeamCity will set up environment variables, such as build.number (you can see a list of these within TeamCity).
In Powershell you can access environment variables using the env "provider", e.g.
$env:PATH
TeamCity variables are accessible by replacing the . with a _, so the build.number variable can be accessed as
$env:build_number
As it says in the TeamCity documentation, the system parameters are passed to the build script runner, but not all build script runners know what to do with them. In the case of the Powershell script runner, when using a script file, they don't propagate down to your scripts.
It's occurred to me to write a psake-optimized build runner that does, but in the meantime you can do one of the following:
explicitly map any of the TeamCity build properties to script parameters using the parameter expansion that's available within the Script Source box. eg .\build.ps1 -someParam:%build.name%
use environment parameters, which can be accessed explicitly within PowerShell using $env:NAME_IN_TEAMCITY syntax, eg $env:TEAMCITY_VERSION, or looped over and pushed into variable scope
access the build properties file that TeamCity makes available during the build. The file is available at $env:TEAMCITY_BUILD_PROPERTIES_FILE, and if you load the XML version it's fairly easy to loop through and push them all into scope (though you do get everything as a string of course). I posted a gist on how to do this (https://gist.github.com/piers7/6432985). Or, if using Psake, modify the script above to return you a hashtable which you can pass directly to Psake's -properties argument.
It is posible. Here is example how to pass system properties into PSake script:
& .\psake.ps1 -parameters #{build_number=%build.number%; personal_build=%build.is.personal%}
If you don't use Psake, you can define your variables like this:
$build_number = %build.number%
The %build.number% part will be replaced with TeamCity provided data. I think, it works only in Source code script input mode.
I created a meta-runner that will pass through System parameters to parameters declared in the Powershell script. It's not perfect (if you put '# in your source it will break) but it works for what I needed, you can find it here: https://gist.github.com/anonymous/ef60ada3f48f0fb25093

clear powershell session

Is there a commandlet that clears the current powershell session variables that I have added?
I am using the Add-Type commandlet, and I am getting the error "Cannot add type. The type name already exists."
A possible "work around": Open a powershell window and then to run your script enter powershell .\yourScriptHere.ps1
This launches a new powershell instance which exits when your script exits. If you want to "play" in the new instance then change the invocation to powershell -NoExit .\yourScriptHere.ps1 and the new instance will not exit when the script completes. Enter exit when you need another restart and hit the "up arrow" key to get the previous command. All script output will appear in the same window. The overhead for starting a new powershell instance is low -- appears to be less than 1 second on my laptop.
Unfortunately you can't unload .NET assemblies that have been loaded into the default AppDomain which is what Add-Type does. You can rename types or namespaces to limp along but at some point you just have to exit and restart PowerShell.
This is not a PowerShell limitation so much as it is a .NET/CLR limitation. You can load .NET assemblies into separate AppDomains which can be unloaded later but you would have to code that yourself and it imposes restrictions on the types you plan to use in the separate AppDomain. That is, those types need to work through .NET Remoting so they either have to derive from MarshByRefObject or they have to be serializable (and this applies to all the objects referenced by their properties, and so on down the object graph).

Passing REINSTALLMODE to an MSI file

I am using VisualStudio2005 and a vdproj to create a simple MSI file. I need to pass in the REINSTALLMODE property when I launch it.
I know this can be done via command line, like so:
msiexec.exe /i foo.msi REINSTALLMODE=amus
However, if a user chooses to click the msi directly (launching the wizard), the property is not passed. Is it possible to do this via the VS and vdproj?
Some options I've investigated:
When I build the MSI via VS, it also produces a setup.exe. Is there a way to pass the REINSTALLMODE property through this maybe?
I installed Orca, which allows me to view/edit the Property table of the MSI. I could add it this way, but then I'd have to add it every time I do an MSI build.
Thanks for any advice.
I found a more automated way to do this.
Create a script named add_reinstall_prop.vbs(example) with the folowing:
set objArgs = WScript.Arguments
set o_installer = CreateObject("WindowsInstaller.Installer")
set o_database = o_Installer.OpenDatabase(objArgs(0), 1)
s_SQL = "INSERT INTO Property (Property, Value) Values( 'REINSTALLMODE', 'amus')"
set o_MSIView = o_DataBase.OpenView( s_SQL)
o_MSIView.Execute
o_DataBase.Commit
Add a post-build event to your setup project calling the script with the following:
add_reinstall_prop.vbs $(BuiltOuputPath)
This will automatically add the desired entry to the built MSI.
You can then check it with Orca to see the entry is now added automatically after build.
Sadly, I can't find a way to set other MSI properties right in VStudio.
Nonetheless, one method that should work is this:
Use Orca to create a transform (MST) that only change the property REINSTALLMODE. (In short, you edit the property & save as a new transform, then use the "Generate Transform" command to create the MST.)
This transform can be applied directly to your MSI using the MSITRAN.EXE command (available in the same Windows Installer SDK where you found Orca).
You could either:
(a) find a way to have Visual Studio always run your MSITRAN command immediately after the MSI build, or
(b) just run your MSITRAN manually (from a batch file or such) after building but before testing.