How to start PowerShell in WiX with proper access to Windows Registry? - powershell

Update
Interesting, if I run 32bit powershell to run the script, it gives me the same error. It looks like the 32bit powershell has no access to the 64 bit registry tree? I tried using WixQuietExec64 but it gave the same error. I also tried providing the full path of the powershell (C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe) to ensure the installer to launch the 64bit version, but that STILL gave the same error... It looks like this might be caused by the MSI installer itself being 32bit??
MSI (s) (4C:C0) [14:25:49:955]: Hello, I'm your 32bit Elevated Non-remapped custom action server.
Original post
I have the following test.ps1 script:
$exchangeroot = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\"
$allexchanges = Get-ChildItem -Path Registry::$exchangeroot -Name | Where-Object { $_ -match "^V.." }
$sorted = $allexchanges | Sort-Object -descending
If ($sorted.Count -gt 1) { $latest = $sorted[0] } Else { $latest = $sorted }
$setup = $exchangeroot + $latest + "\Setup"
$properties = Get-ItemProperty -Path Registry::$setup
$properties
Running the script in a normal PowerShell windows yields the following output:
PS C:\Program Files (x86)\TrustValidator Exchange Server Plugin> .\test.ps1
Required machine-level settings. : 1
Services : C:\Program Files\Microsoft\Exchange Server\V15
NewestBuild : 10845
CurrentBuild : 710737954
Information Store Service : 1
Messaging and Collaboration Event Logging : 1
MsiInstallPath : C:\Program Files\Microsoft\Exchange Server\V15\
...
So it works. Now launching PowerShell from WiX installer and executing the script, it doesn't generate the same result:
WixQuietExec: Get-ItemProperty : Cannot find path
WixQuietExec: 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup' because it
WixQuietExec: does not exist.
WixQuietExec: At C:\Program Files (x86)\TrustValidator Exchange Server Plugin\test.ps1:10
WixQuietExec: char:16
WixQuietExec: + $properties = Get-ItemProperty -Path Registry::$setup
WixQuietExec: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
WixQuietExec: + CategoryInfo : ObjectNotFound: (HKEY_LOCAL_MACH...erver\v15\Set
WixQuietExec: up:String) , ItemNotFoundException
WixQuietExec: + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetIt
WixQuietExec: emPropertyCommand
Now if we observe the error message, it is as though it has access of the tree up until HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\, because my script would search and list all the versions, so v15 has to be accessible up to that point, however when it tries to go deeper to get the ItemProperty, it can't.
This lead me to believe that perhaps I'm missing something when launching my PowerShell from WiX installer...?
This is what's in my wxs file:
<SetProperty Id="InstallPlugin"
Before ="InstallPlugin"
Sequence="execute"
Value =""powershell.exe" -Command "cd '[INSTALLFOLDER]'; & '[#TestPS1]' ; exit $$($Error.Count)"" />
<CustomAction Id="InstallPlugin" BinaryKey="WixCA" DllEntry="WixQuietExec" Execute="deferred" Return="ignore" Impersonate="no" />
Below are a list of items that I've already tried or double checked:
I've tried different combinations of -NoProfile, -ExecutionPolicy ByPass, -Version 2.0 and still no good.
I'm already running the installer as InstallPrivileges="elevated"
I'm already running the CustomAction as Execute="deferred" and Impersonate="no"
I've tried with AdminImage="yes"
I've tried setting <Property Id="MSIUSEREALADMINDETECTION" Value="1" />
Any other clue would be appreciated. :(

Oh... my... god...
Ok I finally got it working. There were actually several problems and the solutions for these problems were actually in bits and pieces of information that I gather from across multiple SO questions.
To recap, here is what I was trying to do:
Launch a powershell from WiX to run my install script.
My script search Windows Registry (requires 64bit) for installed Exchange Server's location
My script loads the Exchange Management Shell (EMS) script (requires 64bit AND proper user) from the install location
Under the EMS session, my script run a brunch of other scripts to register an Exchange plugin
Problem 1)
No matter what I did, the WiX installer always launches my powershell in 32bit, this is regardless of setting Platform="x64", Win64="yes", and even WixQuietExec64. I even built the installer in Visual Studio as x64 and everything else as x64.
The solution is to directly reference the sysnative powershell, it has to be sysnative in the SetProperty.
C:\Windows\sysnative\WindowsPowerShell\v1.0\powershell.exe
I actually did tried this before, and thought it wasn't working, but the root cause was being masked by Problem 2 below.
Problem 2)
Everywhere I read, they said you need to run with Execute="deferred" Impersonate="No". I believe this would indeed work for the most cases if you are not doing anything funky. However, I had to Impersonate. I discovered that the WiX installer would run your CA as elevated with user NT Authority/System. This screwed me over because the Exchange Management Shell script I was trying to source would basically use your credential and try to establish a session with the Exchange Server... and of course you can't connect as NT Authority/System!
The solution is to use Impersonate="yes" so that the WiX installer would run your CA as elevated AND the user you are currently logged in. I always had the impression that you must use Impersonate="no" when using Execute="deferred"... but you don't.
I gave up troubleshoot this for a few days and then went back to it and got it working. The 2 most helpful commands that helped me figured this out were actually:
whoami
Get-ChildItem env: (to check the PROCESSOR_ARCHITECTURE)

Related

Can't find the Connect-ServiceFabricCluster cmdlet when using Powershell

I'm trying to follow this article about deploying a service fabric app through powershell, but I have an issue with running the Connect-ServiceFabricCluster cmdlet. I get the following:
Connect-ServiceFabricCluster : The term 'Connect-ServiceFabricCluster' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name,
or if a path was included, verify that the path is correct and try again.
At line:1 char:2
+ Connect-ServiceFabricCluster
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Connect-ServiceFabricCluster:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Following other articles on the internet, I've tried importing the following things:
Import-Module "$ENV:ProgramW6432\Microsoft SDKs\Service Fabric\Tools\PSModule\ServiceFabricSDK\ServiceFabricSDK.psm1"
Import-Module "C:\Windows\System32\WindowsPowerShell\v1.0\Modules\ServiceFabric"
I also saw somewhere to try and set execution policy before importing modules, so I tried this:
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Force -Scope CurrentUser
In the Modules section of the Powershell ISE I see the ServiceFabricSDK module, but I don't see this cmdlet.
How do I get access to these cmdlets?
Thank you for any help.
Current versions:
Running $PSVersionTable.PSVersion, I get
Major Minor Build Revision
----- ----- ----- --------
4 0 -1 -1
Service Fabric SDK is version 2.5.216
You should make sure you are running the Windows Powershell as opposed to just Powershell. This made a difference for me.
Are you running x86 version of Powershell ISE? I got this error as well but when I switched to the other ISE the cmdlet was available again.
First, I would set your policy to bypass. This can't be done from the script itself, because, well, that's what needs to run with this policy. You could look into setting your powershell ise profile to do this for you.
Set-ExecutionPolicy Bypass
To your question. Not all modules can use the Import-Module feature. For instance, modules from the technet.microsoft.com site must sometimes be manually installed and unzipped. I'm including a script I use below to do this automatically.
#https://www.petri.com/manage-windows-updates-with-powershell-module\
$url = "https://gallery.technet.microsoft.com/scriptcenter/2d191bcd-3308-4edd-9de2-88dff796b0bc/file/41459/47/PSWindowsUpdate.zip"
$module = "PSWindowsUpdate"
$zipped = "$($PSScriptRoot)\$($module).zip"
$unzipped = "C:\Windows\System32\WindowsPowerShell\v1.0\Modules"
#$unzipped = "$PSScriptRoot\$($module)"
if (Get-Module -Name $($module)) {
Write-Host "Module exists $($module)"
} else {
Write-Host "Getting Module $($module)"
if(!(Test-Path $zipped)){
(New-Object System.Net.WebClient).DownloadFile($url, $zipped)
if($?){Write-Output "Downloaded zip $($zipped)"}
}else{
Write-Output "Zip found $($zipped)"
}
if(!(test-path "$($unzipped)\$($module)")){
Add-Type -assembly “system.io.compression.filesystem”
[io.compression.zipfile]::ExtractToDirectory($zipped, $unzipped)
if($?){Write-Output "Unzipped to $($unzipped)"}
}
Unblock-File -Path "$($unzipped)\$($module)" -Confirm
if($?){Write-Output "Unblocked file $($unzipped)"}
Import-Module $unzipped\*\$($module).psd1 -Verbose
if($?){Write-Output "Imported module $($unzipped)"}
}
I was too hasty in my first answer. (which is weird, cuz it took awhile to type...) anyhow. It looks like the install process actually unpacks the psm1 for you.
Be sure you are running as admin, use this to check.
([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(`
[Security.Principal.WindowsBuiltInRole] “Administrator”)
Make sure the file name you made in step 3 matches the path in step 6.
When you run the import module command, follow that up with $?. This will tell you if it imported correctly. You can also use these commands to see if it worked.
get-command -name "Cluster"; get-module
I have just experienced the same problem on my Win10 box,
when cmdlets were not recognized as valid and downloading/installing relevant modules that contained those cmdlets didn't work.
The only solution that worked for me was as follows:
Go to the Control Panel -> "Programs and Features"
Uninstall Service Fabric SDK
click "Turn Windows features on or off" link and uninstall PowerShell
Next, reboot the Windows
Go back to the Control Panel -> "Programs and Features" -> "Turn Windows features on or off"
And install PowerShell
After which download/install Service Fabric SDK
Once again, restart your PC, start the Service Fabric Cluster Manager (if it doesn't auto-start), then right-click its icon on the task-bar and try creating 1-node or 5-node cluster again. In my case, it took less than a minute.

Error Running Powershell Script Using PSCX

We're running a Team City build server which already executes this script locally with no problem. However, when I try to run this script manually I have the following problem:
Windows PowerShell
Copyright (C) 2012 Microsoft Corporation. All rights reserved.
PowerShell Community Extensions Imported.
PS C:\Users\user.domain> cd D:\pkg\platform-2b0c7e3f71f9-BUILD01; powershell.exe -noprofile -executionpolicy Bypass -file D:\pkg\platform-2b0c7e3f71f9-BUILD01\stage.ps1 production \\192.168.x.x\staging \\testserver.domain.com\staging
D:\pkg\platform-2b0c7e3f71f9-BUILD01
Start Staging: 12/15/2014 11:18:14
Verifying target environment configuration and staging targets
Copying source and environment switch
...
Verifying configuration files are valid XML files
Test-Xml : The 'Test-Xml' command was found in the module 'Pscx', but the module could not be loaded. For more information, run 'Import-Module Pscx'.
At D:\pkg\platform-2b0c7e3f71f9-BUILD01\stage.ps1:72 char:9
+ if (!(Test-Xml $file))
+ ~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Test-Xml:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CouldNotAutoloadMatchingModule
So I see the PowerShell Community Extenstions are getting imported (line 4) which makes me wonder what is going on. I am running the script as the exact same user that runs it under Team City. I've checked the build step I'm trying to replicate:
and I can't think of anything that I've missed (working directory option is set to the script file's directory). Any ideas would be appreciated...
Line 4 loads Pscx, Line 5 opens up a new powershell session with -NoProfile option, so it's unlikely that Pscx is loaded in that Powershell session.

PowerShell: "Get-Help Cannot find Help for topic" error with script Comment_Based_Help

Trying to retrieve help from a script gives the following error:
Get-Help : Cannot find Help for topic ".\Process-Test.ps1".
At line:1 char:9
+ get-help <<<< .\Process-Test.ps1
+ CategoryInfo : ResourceUnavailable: (:) [Get-Help], HelpNotFoundException
+ FullyQualifiedErrorId : HelpNotFound,Microsoft.PowerShell.Commands.GetHelpCommand
I've encountered the same error when attempting to retrieve help information from any custom PowerShell script. This does not happen when viewing help information from built-in cmdlets.
A test script is below:
<#
.SYNOPSIS
Adds a file name extension to a supplied name.
.DESCRIPTION
Adds a file name extension to a supplied name.
Takes any strings for the file name or extension.
.EXAMPLE
C:\PS> extension -name "File"
File.txt
#>
Write-Host "Test script"
Troubleshooting steps I've taken:
I've copied this script (or similar scripts) to other machines with PowerShell installed and used it to view help successfully.
I've also been able to view the help using a different account (User2) on my computer successfully, but only when logged in as the other user (versus running the PowerShell console as User2 when logged in as User1).
I've tried viewing the help with and without my PowerShell profile loaded, with the same result (I only have one profile loaded, my personal profile versus machine profiles).
I took this to be a sign that there was a problem with my Windows user profile, so I deleted my profile and re-created it with the same result. I've also tried running System Restore, with no change.
This happens in the PowerShell console along with the ISE.
Occurs when using both Get-Help as well as help.
I noticed, however, that my PowerShell console settings stayed consistent throughout deleting and re-creating my Windows user profile (height, width, colors, etc), which I wouldn't have expected since I deleted my user profile.
Since I'm using Windows 7, I'm not able to uninstall PowerShell and re-install as it's baked into the OS.
Google wasn't helpful for me in this case, but my google skills could be lacking. Any ideas as to further troubleshooting steps, or anyone who's seen this error before?
Edit: this only happens with the 64-bit version of the console and ISE, not with the 32-bit version, and persists through profile deletion
Have you tried to set execution policy?
Set-ExecutionPolicy -ExecutionPolicy remotesigned -Scope process
Then do Get-Help .\script.ps1.
I had the same problem. That was because my script was located on a networkshare in a DFS folder. So I am pointing to network file. When I copied the file locally, directly on the root of my C drive, and called the help option for my script with the normal get-help myscript.ps1 parameter, it worked!

IIS 7.5 powershell module usage issues

Has anyone managed to use this module with success, i'm running 32bit Windows 7, where i have opened an administrator shell using run as administrator, i have imported the WebAdministration module and then attempted to use the commands with some issues, have provided two examples here
Websites
I created a web site with the following command
new-website -name testsite -port 80 -hostheader testsite -physicalpath c:\temp
Then i attempted to get the sites details using the command
get-website -name testsite
but it always returns all sites, seems to ignore the -name parameter. Only way i can get the site is using a filter
get-website | ? { $_.name -eq 'testsite' } | get-member
When i use appcmd it works as expected using the following command
C:\> C:\Windows\System32\inetsrv\appcmd.exe list site testsite
AppPools
When i try to list the apppools using the following command
dir iis:\apppools
i get the following error
Get-ChildItem : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
Yet when i use appcmd as follows i get all the apppools as expected without any error
C:\Windows\System32\inetsrv\appcmd.exe list apppool
Has anyone successfully managed to use the WebAdministration module ?
Thanks in advance
Pat
If you are already running PowerShell as an administrator and have Windows UAC disabled and you are still seeing this error, make sure WAS (Windows Process Activation Service) is running. You can stop W3SVC but PowerShell will definitely give the same head-scratching "access denied" error if WAS is stopped.
You need to make sure that the PowerShell window is running elevated, try right-clicking in the Start Menu and using the "Run as administrator" option to ensure it runs elevated.
Regarding Get-Website ignoring the -Name parameter, this appears to be a bug according to this forum post. The workaround is to use Get-Item
$website = "Default Web Site"
Get-Item "IIS:\sites\$website"
Be sure to use double quotes, variables are not expanded when single quotes are used.
Regarding browsing the application pools I suspect this is a permissions issue as CarlosAg mentioned. Make sure that you are running PowerShell with elevated privileges. I typically launch PowerShell by right-clicking on it and selecting "Run as administrator".

PowerShell Script in PostBuild

Continuous Integration
I have been working on a PowerShell script to keep our development process streamlined. I was planning on running it as a post-build event, but I'm having some trouble.
From the PowerShell prompt, the following works wonderfully:
PS C:\> ./example.ps1
However, when attempting to run this from cmd.exe as follows:
C:\> powershell -command "&\"C:\path to script\example.ps1\""
The script executes but I get a round of errors back from PowerShell, consisting mostly of path resolution errors from the resolve-path function:
Resolve-Path : Cannot find path 'C:\Documents and Settings\bdunbar\My Documents
\Visual Studio 2008\Projects\CgmFamilyComm\FamilyComm\iirf\cms\isapirewrite4.dl
l' because it does not exist.
At C:\Documents and Settings\bdunbar\My Documents\Visual Studio 2008\Projects\C
gmFamilyComm\scripts\cms.ps1:4 char:27
+ $iirfpath = (resolve-path <<<< ../iirf/cms/isapirewrite4.dll).path,
Resolve-Path : Cannot find path 'C:\Documents and Settings\bdunbar\My Documents
\Visual Studio 2008\Projects\CgmFamilyComm\FamilyComm\familycomm' because it do
es not exist.
At C:\Documents and Settings\bdunbar\My Documents\Visual Studio 2008\Projects\C
gmFamilyComm\scripts\cms.ps1:5 char:27
+ $vdirpath = (resolve-path <<<< ../familycomm).path
Is there a way to work around this? Could it be an issue with running resolve-path under cmd.exe?
[Update]
I've been able to change things to get around the errors that are occurring, but I still receive errors that work perfectly fine from the powershell command prompt. I can't figure out what the difference is.
I've made this work in the past (see http://sharepointpdficon.codeplex.com/SourceControl/changeset/view/13092#300544 if interested):
C:\WINDOWS\system32\windowspowershell\v1.0\powershell.exe -NoLogo
-NonInteractive -Command .'$(ProjectDir)Deployment\PostBuildScript.ps1'
-ProjectDir:'$(ProjectDir)' -ConfigurationName:'$(ConfigurationName)' -TargetDir:'$(TargetDir)' -TargetFileName:'$(TargetFileName)' -TargetName:'$(TargetName)
Then throw these parameters in the first line of your post-build script (if you think you may be able to use them):
param($ProjectDir, $ConfigurationName, $TargetDir, $TargetFileName)
Also I should point out, I am not using this presently. I did like using it as a quick scratchpad to reload test data for running integration tests.
Looks like your problem is how relative paths are resolved. Relative paths are resolved based on the current location (stored in $pwd) and not based on the location of the script. So if you launched the script from C:\, it definitely would not work.
I would suggest you calculate the paths based on an argument (like Peter Seale shows), or grab the actual location of the script from:
$MyInvocation.MyCommand.Path