Powershell operating system architecture vs NodeJs process.arch - node.js

I am using a NodeJs app which internally calls process.arch to get system architecture and then builds a path based on the result, eg. - path/to/file/x64/file (application is selenium-standalone NPM package).
Now I need to build the same path in PowerShell script so I also need to get system arcitecture. But doing that with f.ex. (Get-WmiObject Win32_Processor).AddressWidth returns result without x - just 64 so my path ends up path/to/file/64/file which is wrong. My current fix is to explicitly add x:
$arch = (Get-WmiObject Win32_Processor).AddressWidth
if ($arch -eq 32) { $arch = 'x32' }
if ($arch -eq 64) { $arch = 'x64' }
Do you consider this as as safe thing to do? Or is there a way from powerShell to get it already with x assigned?

process.arch describes the bitness (or word width, or architecture or whatever you wanna call it) of the current process - because it's entirely possible to run a 32-bit (or even 16-bit) process on a 64-bit operating system.
To figure out whether a running PowerShell process is 32- or 64-bit (regardless of OS architecture), use [Environment]::Is64BitProcess:
$arch = if([Environment]::Is64BitProcess) { 'x64' } else { 'x32' }

Related

How to configure the content of module.paths in a nodejs environment

On my debian 10 system I do the follwing as user "joerg":
joerg#h2257088:~/temporary/play$ export NODE_PATH=myOwnNodePath
joerg#h2257088:~/temporary/play$ node
Welcome to Node.js v12.20.0.
Type ".help" for more information.
> module.paths
[
'/home/joerg/temporary/play/repl/node_modules',
'/home/joerg/temporary/play/node_modules',
'/home/joerg/temporary/node_modules',
'/home/joerg/node_modules',
'/home/node_modules',
'/node_modules',
'/usr/lib/node'
]
>
Doing the same as user "root" gives:
root#h2257088:/home/joerg/temporary/play# export NODE_PATH=myOwnNodePath
root#h2257088:/home/joerg/temporary/play# node
Welcome to Node.js v12.20.0.
Type ".help" for more information.
> module.paths
[
'/home/joerg/temporary/play/repl/node_modules',
'/home/joerg/temporary/play/node_modules',
'/home/joerg/temporary/node_modules',
'/home/joerg/node_modules',
'/home/node_modules',
'/node_modules',
'myOwnNodePath',
'/root/.node_modules',
'/root/.node_libraries',
'/usr/lib/node'
]
>
Here I have three additional entries (which, by the way I want to have (with the obvious change of "/root" to "/home/joerg")):
'myOwnNodePath',
'/root/.node_modules',
'/root/.node_libraries',
What is defining the content of module.paths in a nodejs environment? What can I do, to get the missing entries?
This question is related to (the not answered) question: NODE_PATH has no effect on module.paths or finding modules.
EDIT:
After an
apt-get purge -y nodejs
apt-get install -y nodejs
it works. That is: Identical for both users root and joerg, with the behaviour formerly appearing for root only and hence, as I want to have it. This solves my principal problem, but does not answer the question.
This is actually not a configuration issue. Instead there is some dynamics in putting entries into the module.paths array. On Unix (not on Windows), if the node binary should be treated securely, certain entries stemming from unsecure environment variables are not included in the module.paths array.
More precisely, if the node binary has set-user-ID or set-group-ID or has capabilities, the entries stemming from the environment variables HOME and NODE_PATH will not be included in the module.paths array, which are exactly the three entries mentioned as missing by the question.
To solve my problem I will copy the node binary so that I have two: node for "normal" execution (running javascript scripts) and nodeServer, which will get the capabilities (to use low port numbers), for execution as an http-server.
Even more precisely, if the AT_SECURE entry of the auxiliary vector has a non-zero value (see man getauxval), the three entries
$NODE_MODULES
$HOME/.node_modules
$HOME/.node_libraries
are not included. To quote man getauxval:
Most commonly, a nonzero value of AT_SECURE indicates that the process is executing a set-user-ID or set-group-ID binary (so that its real and effective UIDs or GIDs differ from one another), or that it gained capabilities by executing a binary file that has capabilities. Alternatively, a nonzero value may be triggered by a Linux Security Module.
After reinstalling node the capabilities are not longer set, which explains the observation in the EDIT of the question. Re-doing the
setcap CAP_NET_BIND_SERVICE=+eip /usr/bin/node
will re-introduce the unwanted behaviour.
Evidence comes out of the source for node (version 12 because this is what I use):
In lib/internal/modules/cjs/loader.js:
Module._initPaths = function() {
const homeDir = isWindows ? process.env.USERPROFILE : safeGetenv('HOME');
const nodePath = isWindows ? process.env.NODE_PATH : safeGetenv('NODE_PATH');
...
In src/node_credentials.cc:
bool SafeGetenv(const char* key, std::string* text, Environment* env) {
#if !defined(__CloudABI__) && !defined(_WIN32)
if (per_process::linux_at_secure || getuid() != geteuid() ||
getgid() != getegid())
goto fail;
#endif
...
And in src/node_main.cc:
#if defined(__linux__)
char** envp = environ;
while (*envp++ != nullptr) {}
Elf_auxv_t* auxv = reinterpret_cast<Elf_auxv_t*>(envp);
for (; auxv->a_type != AT_NULL; auxv++) {
if (auxv->a_type == AT_SECURE) {
node::per_process::linux_at_secure = auxv->a_un.a_val;
break;
}
}
#endif

How to verify the machine configuration using PhantomJS

I have PhantomJS being used by karma-phantom-launcher plugin on my local machine. I want to get the machine configuration whether it is 32 bit or 64 bit.
Similar to what we can do with node.js i.e. after running node we can simply type
process.arch to get the machine configuration on which node is running.
The following code will meet your requirement
var system = require('system');
var os = system.os;
console.log(os.architecture); // '32bit'
console.log(os.name); // 'windows'
console.log(os.version); // '7'
You will get the informations in the console....
A little digging in the documentation would show that you can use the system module to do this:
var system = require('system');
console.log(system.os.architecture);

node.js - how to get the OS platforms user data folder

I am looking for a way to get the userdata folder using Node.js, that will work on both Windows and macOS.
The Node.js instance would be running on the user's machine.
I need something that returns the following:
C:\Documents and Settings\JohnD\Application Data (Windows XP)
C:\Users\JohnD\AppData\Roaming (Windows Vista and Up)
/Users/JohnD/Library/Preferences (macOS)
Is this possible?
Try the following:
process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Preferences' : process.env.HOME + "/.local/share")
The expected result is:
OS X - '/Users/user/Library/Preferences'
Windows 8 - 'C:\Users\user\AppData\Roaming'
Windows XP - 'C:\Documents and Settings\user\Application Data'
Linux - '/home/user/.local/share'
You can check user environment which is stored in process.env
Also, take a look at process.platform
To be specific:
% node
> console.log(process.env.HOME)
/Users/miktam
> console.log(process.platform)
darwin
Having this information, you will be able to achieve what you need.

SharePoint script fails when run as a Visual Studio post-deployment command

I have written a script that inserts some test data into a document library. I intend to use it as a post-deployment step in Visual Studio 2010, so that the library is not empty after a retract & deploy.
The relevant portions of the script are:
Install.ps1:
$scriptDirectory = Split-Path -Path $script:MyInvocation.MyCommand.Path -Parent
. "$scriptDirectory\Include.ps1"
$webUrl = "http://localhost/the_site_name"
$web = Get-SPWeb($webUrl)
...
Include.ps1:
function global:Get-SPSite($url)
{
return new-Object Microsoft.SharePoint.SPSite($url)
}
function global:Get-SPWeb($url,$site)
{
if($site -ne $null -and $url -ne $null){"Url OR Site can be given"; return}
#if SPSite is not given, we have to get it...
if($site -eq $null){
$site = Get-SPSite($url);
...
}
It works fine when run as follows from the command line, even immediately after a Visual Studio re-deploy:
powershell \source\ProjectFiles\TestData\Install.ps1
However, it does not work when I use the exact same command as a post-deployment command line in the SharePoint project's properties in Visual Studio:
Run Post-Deployment Command:
New-Object : Exception calling ".ctor" with "1" argument(s): "The Web applicati
on at http://localhost/the_site_name could not be found. Verify that you have t
yped the URL correctly. If the URL should be serving existing content, the syst
em administrator may need to add a new request URL mapping to the intended appl
ication."
At C:\source\ProjectFiles\TestData\Include.ps1:15 char:18
+ return new-Object <<<< Microsoft.SharePoint.SPSite($url)
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvoca
tionException
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.Power
Shell.Commands.NewObjectCommand
Interestingly, I can reproduce the error on the command line if I run:
c:\windows\Syswow64\WindowsPowerShell\v1.0\powershell \source\ProjectFiles\TestData\Install.ps1
However, the post-deployment command fails even if I explicitly run \windows\System32\WindowsPowerShell\v1.0\powershell and \windows\Syswow64\WindowsPowerShell\v1.0\powershell.
Update: Solution found
I seem to be having a similar problem to the one discussed here:
http://social.technet.microsoft.com/Forums/en-US/sharepoint2010programming/thread/faa25866-330b-4e60-8eee-bd72dc9fa5be
I cannot access a 64-bit SharePoint API using 32-bit clients. Because Visual Studio is 32-bit, the post-deployment action will run in a 32-bit process and will fail. There is, however, a 64-bit MSBuild. If we let it run the PowerShell script, all is fine.
Wrap the script in an MSBuild file such as this:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Install" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Install">
<Exec Command="powershell .\Install" />
</Target>
</Project>
Then, set the post-deployment command line to:
%WinDir%\Microsoft.NET\Framework64\v4.0.30319\MSBuild $(SolutionDir)\ProjectFiles\TestData\Install.msbuild
Use
%WINDIR%\SysNative\WindowsPowerShell\v1.0\powershell.exe
It’s important that you use the virtual path of %WINDIR%\SysNative and not the actual
path of C:\Windows\System32. The reason for this is that Visual Studio 2010 is a 32-bit
application that needs to call the 64-bit version of powershell.exe to successfully load the
Microsoft.SharePoint.Powershell snap-in.
(c)"Inside Microsoft SharePoint 2010", Microsoft Press, Mar 2011
I had same situation, I needed the Post Deployment powershell script to create dummy data for lists on my local instance. I tried several other ways even using the MSBuild with the .msbuild file as suggested above, but i could not all the variables and had to hard code the file with path and url, this is not what i wanted.
I finally figured out a way to explicitly calling the 64-Bit powershell.exe
I know the 64-bit file has to be there on hard dirve. I know that WinSXS folder has all the files. So quick search for powershell.exe in C:\Windows\winsxs folder i got two files so i grabbed the path for one in amd64 folder.
This is what i have as command in post deployment option
C:\Windows\winsxs\amd64_microsoft-windows-powershell-exe_31bf3856ad364e35_6.1.7600.16385_none_c50af05b1be3aa2b\powershell.exe -command "&{$(ProjectDir)PowerShell\dataload.ps1 -xmlPath "$(ProjectDir)PowerShell\dataload.xml" -webUrl "$(SharePointSiteUrl)"}"
I hope this will help someone in future.
Visual Studio is a 32-bit application, so in 64-bit Windows it runs in a simulated 32-bit environment.
Strangely, the 32-bit environment is called "WoW64" (when 32-bit Windows did this for 16-bit apps, it was called "WoW16". The "WoW" part means "Windows on Windows".
It's similarly strange that "System32" didn't become "System64" with 64-bit Windows. The "32" is from the 16-bit -> 32-bit transition, to differentiate from "System". Whatever, that's legacy/compatibility for you.
In WoW64, everything looks like a 32-bit Windows.
For example, c:\windows\system32 just points to c:\windows\syswow64. 32-bit applications can't (easily) reach anything 64-bit.
It is possible to use PowerShell Remoting to get a 64-bit PowerShell session from a 32-bit environment.
PS>gci env:PROCESSOR_ARCH*
Name Value
---- -----
PROCESSOR_ARCHITECTURE x86
PROCESSOR_ARCHITEW6432 AMD64
PS>Invoke-Command -ConfigurationName Microsoft.PowerShell -ComputerName LOCALHOST { gci env:PROCESSOR_ARCH* }
Name Value PSComputerName
---- ----- --------------
PROCESSOR_ARCHITECTURE AMD64 localhost
I have success doing this as a post deployment command:
%comspec% /c powershell -File "c:\foo\bar.ps1"

How do I detect which kind of JRE is installed -- 32bit vs. 64bit

During installation with an NSIS installer, I need to check which JRE (32bit vs 64bit) is installed on a system. I already know that I can check a system property "sun.arch.data.model", but this is Sun-specific. I'm wondering if there is a standard solution for this.
The JVM architecture in use can be retrieved using the "os.arch" property:
System.getProperty("os.arch");
The "os" part seems to be a bit of a misnomer, or perhaps the original designers did not expect JVMs to be running on architectures they weren't written for. Return values seem to be inconsistent.
The NetBeans Installer team are tackling the issue of JVM vs OS architecture. Quote:
x64 bit : Java and System
Tracked as the Issue 143434.
Currently we using x64 bit of JVM to
determine if system (and thus
Platform.getHardwareArch()) is 64-bit
or not. This is definitely wrong since
it is possible to run 32bit JVM on
64bit system. We should find a
solution to check OS real 64-bitness
in case of running on 32-bit JVM.
for Windows it can be done using WindowsRegistry.IsWow64Process()
for Linux - by checking 'uname -m/-p' == x86_64
for Solaris it can be done using e.g. 'isainfo -b'
for Mac OSX it can't be done using uname arguments, probably it can be
solved by creating of 64-bit binary
and executing on the platform...
(unfortunately, this does not work:(
I've created binary only with x86_64
and ppc64 arch and it was successfully
executed on Tiger..)
for Generic Unix support - it is not clear as well... likely checking
for the same 'uname -m/-p' / 'getconf
LONG_BIT' and comparing it with some
possible 64-bit values (x86_64, x64,
amd64, ia64).
Sample properties from different JVMs all running on 64bit Ubuntu 8.0.4:
32bit IBM 1.5:
java.vendor=IBM Corporation
java.vendor.url=http://www.ibm.com/
java.version=1.5.0
java.vm.info=J2RE 1.5.0 IBM J9 2.3 Linux x86-32 j9vmxi3223-20061001 (JIT enabled)
J9VM - 20060915_08260_lHdSMR
JIT - 20060908_1811_r8
GC - 20060906_AA
java.vm.name=IBM J9 VM
java.vm.specification.name=Java Virtual Machine Specification
java.vm.specification.vendor=Sun Microsystems Inc.
java.vm.specification.version=1.0
java.vm.vendor=IBM Corporation
java.vm.version=2.3
os.arch=x86
os.name=Linux
os.version=2.6.24-23-generic
sun.arch.data.model=32
64bit Sun 1.6:
java.vendor=Sun Microsystems Inc.
java.vendor.url=http://java.sun.com/
java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport.cgi
java.version=1.6.0_05
java.vm.info=mixed mode
java.vm.name=Java HotSpot(TM) 64-Bit Server VM
java.vm.specification.name=Java Virtual Machine Specification
java.vm.specification.vendor=Sun Microsystems Inc.
java.vm.specification.version=1.0
java.vm.vendor=Sun Microsystems Inc.
java.vm.version=10.0-b19
os.arch=amd64
os.name=Linux
os.version=2.6.24-23-generic
sun.arch.data.model=64
64bit GNU 1.5:
java.vendor=Free Software Foundation, Inc.
java.vendor.url=http://gcc.gnu.org/java/
java.version=1.5.0
java.vm.info=GNU libgcj 4.2.4 (Ubuntu 4.2.4-1ubuntu3)
java.vm.name=GNU libgcj
java.vm.specification.name=Java(tm) Virtual Machine Specification
java.vm.specification.vendor=Sun Microsystems Inc.
java.vm.specification.version=1.0
java.vm.vendor=Free Software Foundation, Inc.
java.vm.version=4.2.4 (Ubuntu 4.2.4-1ubuntu3)
os.arch=x86_64
os.name=Linux
os.version=2.6.24-23-generic
(The GNU version does not report the "sun.arch.data.model" property; presumably other JVMs don't either.)
I'm using NSIS and Launch4j to wrap a Java Desktop app. So I need not only to detect any JRE, but the one Launch4j will find with its search algorithm. The only approach that made sense is to run a short Java program within the NSIS installer. Here's the Java:
public class DetectJVM {
private static final String keys [] = {
"sun.arch.data.model",
"com.ibm.vm.bitmode",
"os.arch",
};
public static void main (String [] args) {
boolean print = args.length > 0 && "-print".equals(args[0]);
for (String key : keys ) {
String property = System.getProperty(key);
if (print) System.out.println(key + "=" + property);
if (property != null) {
int errCode = (property.indexOf("64") >= 0) ? 64 : 32;
if (print) System.out.println("err code=" + errCode);
System.exit(errCode);
}
}
}
}
Wrap this with Launch4J. Use the GUI header type but also set to true. Otherwise the error code will be lost. (I put all this in my Netbeans Ant build script.
Here's the matching NSIS code that uses it:
File ... ; unpack files including detectjvm.exe.
ClearErrors
ExecWait '"$INSTDIR\detectjvm.exe"' $0
IfErrors DetectExecError
IntCmp $0 0 DetectError DetectError DoneDetect
DetectExecError:
StrCpy $0 "exec error"
DetectError:
MessageBox MB_OK "Could not determine JVM architecture ($0). Assuming 32-bit."
Goto NotX64
DoneDetect:
IntCmp $0 64 X64 NotX64 NotX64
X64:
File ... 64-bit AMD DLLs.
Goto DoneX64
NotX64:
File ... 32-bit x86 DLLs.
DoneX64:
Delete $INSTDIR\detectjvm.exe
This has worked fine on a very large variety of machines from WinXP with no SP through Vista and Win7 with all SPs, 32- and 64-bit.
Note that in my NSIS script I'm using an existing package that checks to see if the JVM is installed and does that first, so the default 32-bit selection would only occur if something went badly wrong with the JVM install, in which case the set of DLLs you copy won't matter anyway.
Hope this is helpful to somebody.
When writing Java code, how do I distinguish between 32 and 64-bit operation?
http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#64bit_detection
There's no public API that allows you to distinguish between 32 and
64-bit operation. Think of 64-bit as just another platform in the
write once, run anywhere tradition. However, if you'd like to write
code which is platform specific (shame on you), the system property
sun.arch.data.model has the value "32", "64", or "unknown".
import sun.misc.*;
import java.lang.reflect.*;
public class UnsafeTest {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
System.out.println(unsafe.addressSize());
}
}
java -version
For a 64bit java version it'll print :
java version "1.8.0_92"
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
Java HotSpot(TM) ***64-Bit*** Server VM (build 25.92-b14, mixed mode)
For 32 bit it'll be just
java version "1.8.0_92"
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
Java HotSpot(TM) Client VM (build 25.92-b14, mixed mode)
On linux, my (java) vm reports java.vm.name=Java HotSpot(TM) 64-Bit Server VM. The javadocs for System declare that System.getProperty will always have a value for this but are silent on sun.arch.data.model.
Unfortunately they don't specify what the system property will be so some other JVM might just report java.vm.name=Edgar.
BTW, by "installed on the system", I assume you mean "the current running JVM"?
There might be both 32 bit and 64 bit JVM's available on the system, and plenty of them.
If you already have dll's for each supported platform - consider making a small executable which links and run so you can test if the platform supports a given functionality. If the executable links and run, you can install the corresponding shared libraries.
If you have the path to the .exe you want to check, you can use this answer. Basically it just looks at the headers in the .exe file and tells you whether or not it is 64 or 32 bit on Windows.
The following code checks the machineType field in any windows executable to determine if it is 32 or 64 bit:
public class ExeDetect
{
public static void main(String[] args) throws Exception {
File x64 = new File("C:/Program Files/Java/jre1.6.0_04/bin/java.exe");
File x86 = new File("C:/Program Files (x86)/Java/jre1.6.0/bin/java.exe");
System.out.println(is64Bit(x64));
System.out.println(is64Bit(x86));
}
public static boolean is64Bit(File exe) throws IOException {
InputStream is = new FileInputStream(exe);
int magic = is.read() | is.read() << 8;
if(magic != 0x5A4D)
throw new IOException("Invalid Exe");
for(int i = 0; i < 58; i++) is.read(); // skip until pe offset
int address = is.read() | is.read() << 8 |
is.read() << 16 | is.read() << 24;
for(int i = 0; i < address - 60; i++) is.read(); // skip until pe header+4
int machineType = is.read() | is.read() << 8;
return machineType == 0x8664;
}
}
Note that the code has been compacted for brevity...

Resources