Powershell: Script to run with x86 powershell/ise - powershell

The script i've created uses componets which are only available with the 32 bit version of powershell.
By default windows excutes the script with powershell x64 and it causes several errors.
Is the a way to set an value at the beginning of a script to force windows to use powershellx86 instead of x64?
Example:
using powershell(x86).exe
scriptblock
Thank you

Couldn't you just start the "powershell(x86).exe" file?
%SystemRoot%\syswow64\WindowsPowerShell\v1.0\powershell.exe
/Fredrik

There is no straightforward way to do it, but there is a way to invoke another instance of Powershell host in x64 host, and that instance may as well be x86. $env:PROCESSOR_ARCHITECTURE will tell you what version of Powershell host you are running.
Just a sketch, use chisel and sand paper to finish.
function Execute-Scriptx86
{
param(
[Parameter(Mandatory=$True,Position=1)]
[string]$ScriptFile
)
if($env:PROCESSOR_ARCHITECTURE -eq "AMD64")
{
$powershellx86 = $env:SystemRoot + "\syswow64\WindowsPowerShell\v1.0\powershell.exe"
& $powershellx86 -File $ScriptFile
}
else
{
& $ScriptFile
}
}

Related

calling VBScript from Powershell ..Is this right way to do it?

I have a VBscript file. I run this VBscript using CScript on windows 2012 server. The VBscript runs fine on the server.
But I need to call this VBScript file from Powershell. This is what I did.
For simplicity, this is what I have in my VBscript file
echo.vbs
Msgbox("hello world")
I wrote the test.ps1
$acommand = "C:\Windows\System32\Cscript.exe C:\deleteit\echo.vbs"
Invoke-Expression $acommand
It is the right way to run an external application and you can use the same technique if you are using command line exe's or VBS scripts.
Personally, I would be looking to add the functionality to a PowerShell script rather then calling an external VBS script, but that's just my 2 cents worth :)
Aside from simply running
Cscript.exe C:\deleteit\echo.vbs //nologo
There's a com object that can embed vbscript right into powershell, but it's 32-bit only. There's a way to run jobs as 32 bit. In powershell 7 you have to use the 32-bit version.
start-job {
$sc = New-Object -ComObject MSScriptControl.ScriptControl.1
$sc.Language = 'VBScript'
$sc.AddCode('
Function MyFunction(byval x)
MyFunction = 2 * x
End Function
')
$sc.codeobject.MyFunction(1)
$sc.codeobject.MyFunction(2)
} -runas32 | wait-job | receive-job
Output:
2
4

Local Powershell script to trigger VBS script inside Citrix instance

I am trying to get a local powershell script to trigger a VBS script inside a citrix instance. The events should be this:
Citrix Instance opening Windows Explorer ----> Network Path of script typed into the windows explorer session
I'm using the WfIcaLib.dll (ICOSDK) that came with the Citrix receiver install. Documentation PDF for the Citrix ICOSDK is available here
So this is the code I'm using, which works PERFECTLY in Powershell command line, but when I use the 32-bit ISE, it does nothing other than telling me the DLL has been loaded. I get no errors, but the Citrix Client never actually opens like it does when I run the same exact commands through Powershell command line.
#load Citrix ICA Client SDK
[System.Reflection.Assembly]::LoadFile("C:\Program Files (x86)\Citrix\ICA Client\WfIcaLib.dll")
$ICA = New-Object WFICALib.ICAClientClass
$ICA.Address = "***.***.***.***:****"
$ICA.Application = "Windows ExplorerFED6"
$ICA.Username = "******"
$ICA.Domain = "**"
$ICA.Launch = $true
$ICA.Outputmode = [WfIcaLib.OutputMode]::OutputModeNormal
$ICA.SetProp("Password", "*********")
$ICA.TWIMode=$true
$ICA.Connect()
Any ideas?
EDIT: SOLVED - after reopening under 32-bit ISE and getting code to work, I could not run the .ps1 file since it kept defaulting to 64-bit (even if using Open With on 32-bit powershell version). Running the script via command prompt or 32-bit powershell console both worked.
Using any method suggested by Mike Garuccio worked just fine. I will most likely end up using a Task Scheduler to run the script.
It looks like the problem is a versioning one, which you can deal with using start-job (was originally going to do this with a runspace but that's a lot more code for no real benefit). This will start a job to run your code under 32-bit powershell, it should still place any GUI elements or popups on screen but if you need to get any data out from the script later you'll need to receive the job. code would look something like below.
$SB = {
[System.Reflection.Assembly]::LoadFile("C:\Program Files (x86)\Citrix\ICA Client\WfIcaLib.dll")
$ICA = New-Object WFICALib.ICAClientClass
$ICA.Address = "***.***.***.***:****"
$ICA.Application = "Windows ExplorerFED6"
$ICA.Username = "******"
$ICA.Domain = "**"
$ICA.Launch = $true
$ICA.Outputmode = [WfIcaLib.OutputMode]::OutputModeNormal
$ICA.SetProp("Password", "*********")
$ICA.TWIMode=$true
$ICA.Connect()
}
Start-Job -ScriptBlock $SB -RunAs32
get-job | Receive-Job
Alternatively, you could also use a simple .bat file as a launcher with something like C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -file yourscript.ps1
or if you need everything to be wrapped in powershell and the job does not work you can use the solution Here that basically does the same thing but from within powershell (drop the if statement they use tho, just use the stuff contained inside it like below, with any changes you need to make wrt the profile and interactive settings.)
&"$env:windir\syswow64\windowspowershell\v1.0\powershell.exe" -noninteractive -noprofile -file "C:\Path o\script.ps1" -executionpolicy bypass
hope one of those works for you!

Powershell running a cmdlet from a called script

I have a script that calls another script (with arguments). The called script contains the Install-WindowsFeature cmdlet. When I run the script, the called script runs, but returns the following error:
Install-WindowsFeature : The term 'Install-WindowsFeature' 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
Of course, I can run the cmdlet just fine from a PowerShell console. I can also run the called script from a PowerShell console and Install-WindowsFeature works fine. So, is it something to do with calling a script from a script that runs a cmdlet? Here is my calling code:
$script = "C:\Path\script.ps1"
$argumentList = #()
$argumentlist += ("-Arg1", "value")
$argumentlist += ("-Arg2", "value")
$argumentlist += ("-Arg3", "value")
Invoke-Expression "$script $argumentList"
In the called script, I called Install-WindowsFeature as below:
if ($someValue) { Invoke-Command -ScriptBlock {Install-WindowsFeature -Name RSAT-AD-Tools} }
I've also tried it as below:
if ($someValue) { Install-WindowsFeature -Name RSAT-AD-Tools }
12/16/16 EDIT: This script is running in a GUI built with Sapien PowerShell Studio. When I change the build type to "Native" it works. I have to reset my lab to check, but I suspect it will also run if I just run it in the x64 context. This article explains why I think this matters.
Running on Windows Server 2012 R2
Unless you've got a compelling reason for it, let's see if we can clean up your calling pattern a bit - and hopefully make your other issues go away by avoiding the contortionism.
Rather than creating your parameter list as a string, take advantage of parameter splatting. It's good to get out of the habit of treating PowerShell like other scripting languages that don't work with objects.
$splat = #{
Arg1 = "value1";
Arg2 = "value2";
Arg3 = "value3"
}
& c:\path\script.ps1 #splat
Using that on a script.ps1 something like this:
param(
$Arg1,
$Arg2,
$Arg3
)
Write-Host "Arg1 = $Arg1, Arg2 = $Arg2, Arg3 = $Arg3
You'll get an expected output of:
Arg1 = value1, Arg2 = value2, Arg3 = value3
Once you've got that, there's probably no reason to use Invoke-Command on the call to Install-WindowsFeature, unless you're leaving out details like invoking remotely to a server. Invoke-Command { Install-WindowsFeature } still works fine for me on Server 2012R2 with PowerShell 5, and there's no reason it shouldn't.
This assumes you're running this script on a Server that support Install-WindowsFeature, as the other comments point out. Client Windows doesn't support Install-WindowsFeature, and the RSAT tools are installed via a stand-alone RSAT .MSU package, which you manage differently.
Install-WindowsFeature is natively provided with Server Manager on Server 2012R2 - there's no need to Import-Module... unless you've done something to your profile or fouled up your modules folders. One of the earlier versions of Windows Server needed it - but that was a couple versions back. Likewise, Add-WindowsFeature was the old name - and it's still available as an alias for Install-WindowsFeature.
I'm assuming you've tried Install-WindowsFeature directly from the command line to ensure it's in working order, and Get-Module Install-WindowsFeature looks reasonable.
PS C:\Windows\system32> get-module ServerManager
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 2.0.0.0 ServerManager {Get-WindowsFeature, Install-WindowsFeature, Uninstall-Win...
While we're on the topic, there's very little reason to drop to DISM on Server that supports Install-WindowsFeature, and a number of reasons not to.
Server Manager and several other tools (including Win32_ServerFeature) rely on the feature states parsed and understood by the WMI provider used by Install-WindowsFeature. It's possible to enable the right set of features using DISM, but needs attention and detail. Enabling only "part" of a role and feature may get the functionality you want for specific cases, but the role or feature may not show up as installed in Get-WindowsFeature, may not be uninstallable via Remove-WindowsFeature, and may not offer relevant UI features in Server Manager like monitoring health of the role, viewing relevant events, or offering tools for administering it.
Install-WindowsFeature integrates with additional code from the role & features you're installing, and may run additional health and pre-requisite checks to ensure your correctly configured.
DISM featurenames tend to change more often than the role & feature name of Server Manager, so your script portability will be better.
There are other points, but I won't go into them since DISM was primarily a comment fork.
You are probably right, it seems like the script gets executed with x86 PowerShell. I want to share a snippet with you which I use for scripts that needs to run in a specific environment (e. g. x64 PowerShell).
The script restarts itself in a x64 PowerShell if its started as x86 process. Just put this at the top of your script:
# Reinvoke the script as x64 if its called from a x86 process.
if ($env:Processor_Architecture -eq "x86")
{
&"$env:windir\sysnative\WindowsPowerShell\v1.0\powershell.exe" -noprofile -file $myinvocation.Mycommand.path -executionpolicy bypass
exit
}
Also note that the Install-WindowsFeature cmdlet doesn't work on all windows versions so consider to use dism instead:
$featuresToInstall = #('RSAT-AD-Tools')
$dismParameter = #('/online', '/Enable-Feature', ($featuresToInstall | % { '/FeatureName:{0}' -f $_ }), '/NoRestart')
dism #dismParameter
The running environment determines what modules you have access to. When I created this project in PowerShell Studio, it took the default of x86 (a 32 bit environment). This worked but because I was running it on Windows Server 2012 R2 (a 64-bit environment) I did not have access to the powershell modules such as Import-Module and Install-WindowsFeature. Changing this to a x64 project resolved my issue.
In order to avoid this scenario, it is important to make sure you run PowerShell scripts and modules in the architecture that is native to the OS. You can do this by setting the project correctly (if using a tool like PowerShell Studio) or by verifying that you are running in the native mode for that OS with the code Martin Brandl provided.

Unbinding BizTalk orchestrations with PowerShell

What is the cleanest way to unbind an orchestration using PowerShell?
I'd like to have something that works on both 32bit and 64bit platform.
I know I can load and use the Microsoft.BizTalk.ExplorerOM assembly (forcing 32bit mode with something like "Start-Job -RunAs32") and do something similar to what is explained here: http://msdn.microsoft.com/en-us/library/dd792703(v=bts.10).aspx
But I'd like to find something better.
I see the sample script you linked is loading this DLL from the GAC:
[System.reflection.Assembly]::LoadWithPartialName("Microsoft.BizTalk.ExplorerOM")
I'm not familiar with this assembly but if it's pre-compiled to x86 in the GAC then you'll need to load it with 32bit PowerShell (when on a 64bit Windows system). In your script you can do a check to see what PowerShell process bitness is:
if ( [IntPtr]::Size -eq 4 ) { # x86 } else { # x64 }
If your script is not running in the right bitness there's three things I can think of:
Start a 32 bit background job as you noted
Re-launch your script using 32 bit PowerShell (doesn't work well if your script has params):
if (-not $correctBitness) {
Start-Process "C:\WINDOWS\syswow64\windowspowershell\v1.0\powershell.exe" -ArgumentList "-file", $Invocation.MyCommand.Path
exit
}
Tell the user they need to re-launch the script using the 32 bit PowerShell and exit.

Determine if PowerShell script has been dot-sourced

From a PowerShell script, how can I determine if the script has been dot-sourced, i.e. it has been called with
. .\myscript.ps1
rather than
.\myscript.ps1
NOTE an interesting blog post (also) about this: http://poshoholic.com/2008/03/18/powershell-deep-dive-using-myinvocation-and-invoke-expression-to-support-dot-sourcing-and-direct-invocation-in-shared-powershell-scripts/
To complement mjolinor's helpful answer:
tl;dr
$isDotSourced = $MyInvocation.InvocationName -eq '.' -or $MyInvocation.Line -eq ''
While $MyInvocation.InvocationName -eq '.' mostly tells you whether a given script is being dot-sourced, there is one exception:
When you run a script from the - obsolescent[1] - Windows PowerShell ISE with Debug > Run/Continue (F5), it is implicitly sourced, yet $MyInvocation.InvocationName contains the full script filename rather than . However, you can detect this case by checking if $MyInvocation.Line is empty.
(The PIC (PowerShell Integrated Console) that comes with Visual Studio Code's PowerShell extension used to behave this way, but as of at least version v2023.1.0 submits explicit dot-sourcing commands).
Note: Detecting whether a function is being dot-sourced is not subject to the exception above, so testing for $MyInvocation.InvocationName -eq '.' is sufficient (but the above will work too).
[1] The PowerShell ISE is no longer actively developed and there are reasons not to use it (bottom section), notably not being able to run PowerShell (Core) 7+. The actively developed, cross-platform editor that offers the best PowerShell development experience is Visual Studio Code with its PowerShell extension.
Check $myinvocation.line
It will show the line that was used to call the script.
PS C:\scripts\test> gc test.ps1
$myinvocation.line
PS C:\scripts\test> ./test.ps1
./test.ps1
PS C:\scripts\test> . ./test.ps1
. ./test.ps1
You can also check the .invocationname property. If the script was dot-sourced, it will just be a dot. If not, is will be ./scriptname.ps1