Creating a script to gather PC information - to assist those asking for help

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
aGerman
Expert
Posts: 4654
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Creating a script to gather PC information - to assist those asking for help

#76 Post by aGerman » 25 Aug 2016 13:17

penpen
I tested your approach and it took ages. But you're right that it looks pretty much the same :? Let me try again tomorrow ...

Steffen

douglas.swehla
Posts: 75
Joined: 01 Jun 2016 09:25

Re: Creating a script to gather PC information - to assist those asking for help

#77 Post by douglas.swehla » 25 Aug 2016 14:35

aGerman wrote:Thanks! Tried it at work and it returns the right results in no time :)
I'm curious what Douglas' results will be using your approach.
n


Runs in under a second, with accurate results.

penpen wrote:That's nearly the same solution, i've given above (with a removed flaw, but a (probably slower) "for /F" instead of "AND ...").
I thought you've tested it, and it is slower because it's "querying the Win32_GroupUser class"?!


That's what I thought, too. Apparently, the manner of querying Win32_GroupUser affects the processing speed. The key difference is in this line, where %%b is the admin group name:

Code: Select all

WMIC path Win32_GroupUser Where (GroupComponent^="Win32_Group.Name=\"%%b\",domain=\"%computername%\""^) get PartComponent


We've got nested equals signs in the WHERE clause (GroupComponent="Win32_Group.Name=\"Administrators\"), so maybe we're comparing 'GroupComponent' to the object returned by 'Win32_Group.Name="Administrators"', rather than the text string "Administrators". Maybe? I don't understand it at all. Compo, can you explain what's happening, here?

Meanwhile, I'm all for dropping GPRESULT and going with this.

Edit: Whoops. Spoke too soon. This approach find IT-group admins, but not me. See next post for details.
Last edited by douglas.swehla on 25 Aug 2016 17:35, edited 1 time in total.

douglas.swehla
Posts: 75
Joined: 01 Jun 2016 09:25

Re: Creating a script to gather PC information - to assist those asking for help

#78 Post by douglas.swehla » 25 Aug 2016 17:34

penpen wrote:

Code: Select all

2>nul wmic path win32_groupuser where (GroupComponent="win32_Group.Name=\"%adminGroupName%\",Domain=\"%userDomain%\"" ^
AND PartComponent="Win32_UserAccount.Name=\"%userName%\",Domain=\"%userDomain%\"")



aGerman wrote:penpen
I tested your approach and it took ages. But you're right that it looks pretty much the same :? Let me try again tomorrow ...

Steffen


I just tested penpen's code (didn't test earlier, sorry penpen), and rather than taking ages, I immediately got "No Instance(s) Available." More on that in a second.

douglas.swehla wrote:The key difference is in this line, where %%b is the admin group name:

Code: Select all

WMIC path Win32_GroupUser Where (GroupComponent^="Win32_Group.Name=\"%%b\",domain=\"%computername%\""^) get PartComponent


. . . I don't understand it at all.


I've been experimenting to understand all this, and there are a few interesting things going on here. The first is that penpen's code searches for Domain=\"%userDomain%\", while compo's searches for domain=\"%computername%\". On my machine, "%userDomain%" expands to "US", rather than the local machine name. That explains why I get no results: there are no local admins that are part of the nation-wide domain. I thought it might account for the long search search time that aGerman is getting (searching the whole network rather than local machine), but if that were the case, then I would expect my search to take ages, and then say "No Instances", so I don't quite know what to make of that.

The next is the difference between the format of the query and the result. Both of these commands return the same result:

Code: Select all

WMIC path Win32_GroupUser Where (GroupComponent^="Win32_Group.Name=\"Administrators\",domain=\"%computername%\""^) get
WMIC path Win32_GroupUser Where (GroupComponent^="Win32_Group.domain=\"%computername%\",Name=\"Administrators\""^) get

GroupComponent                                              PartComponent                                                                           
Win32_Group.domain="MyComputerName",Name="Administrators"  \\MyComputerName\root\cimv2:Win32_UserAccount.Domain="MyComputerName",Name="SomeITGuy" 
Win32_Group.domain="MyComputerName",Name="Administrators"  \\MyComputerName\root\cimv2:Win32_Group.Domain="US",Name="Domain Admins"               
Win32_Group.domain="MyComputerName",Name="Administrators"  \\MyComputerName\root\cimv2:Win32_Group.Domain="US",Name="XYZ_WKSTN_ADMINS"             
Win32_Group.domain="MyComputerName",Name="Administrators"  \\MyComputerName\root\cimv2:Win32_Group.Domain="US",Name="ALL_WKSTN_ADMINS"


Note that in the results, the domain portion of the group always comes before the name portion, even though the order is reversed in the first command. So, even though the query looks like it's matching a string, it's not, exactly. I think there must be some kind of implied AND syntax that's used to identify and match on object IDs. Again, not a WMI master, so if anybody knows otherwise, please chime in.

The last and biggest thing is the issue that I pointed out when proposing GPRESULT. My organization does some kind of weird security thing where my login name (%username%) is used as the first part of two different local account names, neither of which is assigned to any local groups. Both the NET command and WMI's Win32_UserAccount use these account names, and neither uses my login name, so both of these tools fail to recognize me as an administrator.

Since WMI doesn't recognize me as an admin, even when it's working at a sane speed, I have to retract my earlier endorsement of Compo's method, at least for now.

For what it's worth, my admin rights are handled by a third-party program. To get to an admin prompt, I search the Start menu for CMD, right-click on the result, and instead of "Run as admin", click "Run with Third-Party Program Name". That opens an instance of CMD.EXE with the title "Administrator: c:\windows\system32\cmd.exe" and current directory set to "C:\windows\system32", just like I'd get normally. This is a fairly recent change, and I'm pretty sure the weird account name stuff was in place before that, so I don't think they're directly related. If anyone has ideas on how to take that into account and still get a working solution from WMIC, I'd love to hear it.

penpen
Expert
Posts: 1996
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Creating a script to gather PC information - to assist those asking for help

#79 Post by penpen » 25 Aug 2016 19:44

My code has (at minimum) one flaw:
Instead of "Administratoren" there should be "%adminGroupName%" (which contains localized version of "Administrators" ; all without doublequotes);
other localizations just give the wrong answer (because there is no group "Administratoren"), german localized windows should return the right answer.

I'm unsure about your (douglas.swehla) value of the environment variable "UserDomain":
I thought (but i may error an that point) that it should contain the name of the domain that contains the user's account ("US" is very unlikely because it is probably stored at your companies server pcs which i assume doesn't hold all "US" accounts) and not the name of the domain, the computer/server belongs to (which i assume why this value is set to "US").

But this should explain why you got no result.
Using "%ComputerName%" is probably better because that domain node most probably exists.


douglas.swehla wrote:Note that in the results, the domain portion of the group always comes before the name portion, even though the order is reversed in the first command. So, even though the query looks like it's matching a string, it's not, exactly. I think there must be some kind of implied AND syntax that's used to identify and match on object IDs. Again, not a WMI master, so if anybody knows otherwise, please chime in.
If i remind right:
When using parentheses "()" in the "where-Clause" strings may contain serialized calls to constructors (which is needed here, because "GroupComponent" is no simple string or integer value):
So '(GroupComponent^="Win32_Group.Name=\"Administrators\",domain=\"%computername%\""^)' advices to compare the "GroupComponent" with the object created by the constructor 'Win32_Group(AttributeList("Name=Administrators", domain="%computername%"))'.
If you reverse the order then 'Win32_Group(AttributeList(domain="%computername%", "Name=Administrators"))' is called, which should result in an equal object.

Sidenotes:
1) One cannot use
'GroupComponent="\\\\%computername%\\root\\cimv2:Win32_Group.Domain\=\"%computername%\"\,Name\=\"Administrators\""'
because types are mismatching (Win32_Group versus string), so the verb should be invalid.

2) Using different lists ('(GroupComponent^="Win32_Group.Name=\"Administrators\"")', or '(GroupComponent^="Win32_Group.Name=\"Administrators\",domain="%computername%",Caption=\"abc\"")' ) should be valid but should result in nothing found, because the objects doesn't match, so one have to use exactly "Name" and "Domain".


penpen

Edit 1: Nearly completely changed.
Last edited by penpen on 25 Aug 2016 21:59, edited 1 time in total.

penpen
Expert
Posts: 1996
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Creating a script to gather PC information - to assist those asking for help

#80 Post by penpen » 25 Aug 2016 21:58

douglas.swehla wrote:The last and biggest thing is the issue that I pointed out when proposing GPRESULT. My organization does some kind of weird security thing where my login name (%username%) is used as the first part of two different local account names, neither of which is assigned to any local groups. Both the NET command and WMI's Win32_UserAccount use these account names, and neither uses my login name, so both of these tools fail to recognize me as an administrator.
...
I never heard about something like that.
If that is really is a third-party program which name has it?

The method of creating a directory under system32 does not mean you have admin rights (although i must admit it is highly probable); you also could be:
- a user/group member of "SYSTEM" (don't know if this is a user / group account),
- a group member of "NT SERVICE\TrustedInstaller" (which is a virtual account that is a virtual member of "Administrators"),
But you should really fire any admin who adds you to one of the above groups... (i hope this is not how your (douglas.swehla) organization has implemented it :roll: ).


penpen

PS: I nearly completely changed my above post.

aGerman
Expert
Posts: 4654
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Creating a script to gather PC information - to assist those asking for help

#81 Post by aGerman » 26 Aug 2016 08:06

penpen

My apologies. I tried your code again and it worked great. I don't know what happened last time. Probably I overwrote the old code but forgot to save the file or something like that :oops:
(When that didn't work last time I run wmic path win32_groupuser separatly and without WHERE clause which took ages again. FWIW That was confirmed today as well.)

Steffen

douglas.swehla
Posts: 75
Joined: 01 Jun 2016 09:25

Re: Creating a script to gather PC information - to assist those asking for help

#82 Post by douglas.swehla » 26 Aug 2016 11:03

penpen wrote:Instead of "Administratoren" there should be "%adminGroupName%" (which contains localized version of "Administrators" ; all without doublequotes)

I made that change when testing, and also substituted "Administrators" directly. Both had the same result: No Instances.

penpen wrote:I'm unsure about . . . the environment variable "UserDomain":
I thought (but i may error an that point) that it should contain the name of the domain that contains the user's account ("US" is very unlikely because it is probably stored at your companies server pcs which i assume doesn't hold all "US" accounts) and not the name of the domain, the computer/server belongs to (which i assume why this value is set to "US").

But this should explain why you got no result.
Using "%ComputerName%" is probably better because that domain node most probably exists.

I couldn't say where accounts are stored, and don't really understand what "domain node" means in this context. When I log into Windows on this machine, I log into domain "US". When I run tools that identify local users in the format 'domain\name", the domain portion is the name of the local machine, which is the same as the asset tag. Since admin privileges are granted on a per-machine basis, it makes sense to me that we'd want to match on %computername%. If that's what you mean by domain node, then I agree.

penpen wrote:When using parentheses "()" in the "where-Clause" strings may contain serialized calls to constructors (which is needed here, because "GroupComponent" is no simple string or integer value):
So '(GroupComponent^="Win32_Group.Name=\"Administrators\",domain=\"%computername%\""^)' advices to compare the "GroupComponent" with the object created by the constructor 'Win32_Group(AttributeList("Name=Administrators", domain="%computername%"))'.
If you reverse the order then 'Win32_Group(AttributeList(domain="%computername%", "Name=Administrators"))' is called, which should result in an equal object.

Excellent explanation, thanks! I wondered why it broke when I tried changing the parentheses to quotes. I thought it was just messing up the character escaping.

I wanted to try using the PartComponent to identify the GroupComponent, but kept getting "invalid query" error. Can you tell me what's wrong with the code below? Is it to do with escaping the backslashes, or something else entirely?

Code: Select all

rem :: Compo's code to find GroupComponent, with group name already found
WMIC path Win32_GroupUser Where (GroupComponent^="Win32_Group.Name=\"Administrators\",domain=\"%computername%\""^) get PartComponent

rem :: Results from above. (Note mix of "%computername%" and "US" in Domain fields.)
rem :: I've manually substituted "%computername%" for the actual text, and obfuscated some other details.
PartComponent                                                                           
\\%computername%\root\cimv2:Win32_UserAccount.Domain="%computername%",Name="ITGuy74" 
\\%computername%\root\cimv2:Win32_Group.Domain="US",Name="Domain Admins"               
\\%computername%\root\cimv2:Win32_Group.Domain="US",Name="XYZ_WKSTN_ADMINS"             
\\%computername%\root\cimv2:Win32_Group.Domain="US",Name="ALL_WKSTN_ADMINS"             

rem :: To reverse the search, I should be able to just flip it around, right?
rem :: I provide the Domain and Name properties of the PartComponent (Win32_Account object),
rem :: and get back the GroupComponent. Except, none of these work.
rem :: The middle one returns "Invalid query", and the other two just sit there.
rem :: I can't tell if they're hung, just running forever.
rem :: Same results with "Win32_Account" instead of "Win32_UserAccount".
WMIC path Win32_GroupUser Where (PartComponent^="Win32_UserAccount.Domain=\"%computername%\",Name=\"ITGuy74\""^) get GroupComponent
WMIC path Win32_GroupUser Where (PartComponent^="\\%computername%\root\cimv2:Win32_UserAccount.Domain=\"%computername%\",Name=\"ITGuy74\""^) get GroupComponent
WMIC path Win32_GroupUser Where (PartComponent^="\\\\%computername%\\root\\cimv2:Win32_UserAccount.Domain=\"%computername%\",Name=\"ITGuy74\""^) get GroupComponent



douglas.swehla
Posts: 75
Joined: 01 Jun 2016 09:25

Re: Creating a script to gather PC information - to assist those asking for help

#83 Post by douglas.swehla » 26 Aug 2016 11:34

penpen wrote:I never heard about something like that.
If that is really is a third-party program which name has it?

It's called Avecto Defendpoint. Here is a blurb from the support team describing it:
In an on-going effort to strengthen the security of our ecosystem with respect to privileged access, Identity and Access Management has invested in an endpoint security product for workstations known as Avecto Defendpoint. The purpose of Defendpoint is to provide a more granular elevation of privileged access for users that require local administrative rights to their workstation while also providing more robust metrics around what applications and activities end-users are using their elevated rights for.

For workstation admin rights please follow instructions on the below attachment to get the software loaded on the machine where you need workstation admin rights. Once the software is loaded you will have admin rights - no other action needs to be done.


I skimmed the info at https://www.avecto.com/defendpoint/privilege-management, and it sounds like the tool grants privileges to applications, rather than to users. On a normal system, when you are logged in as a standard user, and you select "Run as administrator...", you're prompted to enter an admin user's credentials. On my work machine, when I select "Run with Defendpoint", I'm not prompted for other credentials, so there must be someplace where "UserID can tell CMD.EXE to run in elevated mode" is recorded. I expect GPRESULT is pulling its data from that place. If we can figure out what that place is, then maybe we can get to it through WMIC or REG or some other faster tool. There is an "Avecto Defendpoint Modified Token" group on my machine, so maybe access is brokered through that somehow. I'm still trying to figure that out.

penpen wrote:The method of creating a directory under system32 does not mean you have admin rights (although i must admit it is highly probable); you also could be:
- a user/group member of "SYSTEM" (don't know if this is a user / group account),
- a group member of "NT SERVICE\TrustedInstaller" (which is a virtual account that is a virtual member of "Administrators")


I don't think I'm a member of either of those. Will check in a bit to confirm.

I take your point that I might not strictly be an admin on this machine, using the normal definition. We must remember, though, that the question "Is the user a member of the Administrators group?" is a proxy for "Does the user have administrator-like rights?", which is in turn a proxy for "Can the user use command-line tools that are normally restricted to admin-level users?". In my case, the answers are "No", "Kind of", and "Yes", respectively. What we really want to know is whether the user can run FSUTIL or edit the Registry or do any of the things that require elevation, and I can do those things.

So, given the funky way that account permissions are handled by my workplace, how can we determine that programatically? So far, the only way I've found is with GPRESULT. I'm going dig a little deeper into the account/group/permissions info, and try to get you guys a better description of what's going on so that, if there's a better way to do this, we can figure it out. Hopefully, that will be later today, but might be tomorrow.

penpen
Expert
Posts: 1996
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Creating a script to gather PC information - to assist those asking for help

#84 Post by penpen » 26 Aug 2016 15:36

@aGerman
Np, i have formulated it too hard: Sorry for that.
I just was curious why there was such big difference.


douglas.swehla wrote:I couldn't say where accounts are stored, and don't really understand what "domain node" means in this context. When I log into Windows on this machine, I log into domain "US". When I run tools that identify local users in the format 'domain\name", the domain portion is the name of the local machine, which is the same as the asset tag. Since admin privileges are granted on a per-machine basis, it makes sense to me that we'd want to match on %computername%. If that's what you mean by domain node, then I agree.
+


douglas.swehla wrote:I wanted to try using the PartComponent to identify the GroupComponent, but kept getting "invalid query" error. Can you tell me what's wrong with the code below? Is it to do with escaping the backslashes, or something else entirely?

Code: Select all

rem :: Compo's code to find GroupComponent, with group name already found
WMIC path Win32_GroupUser Where (GroupComponent^="Win32_Group.Name=\"Administrators\",domain=\"%computername%\""^) get PartComponent

rem :: Results from above. (Note mix of "%computername%" and "US" in Domain fields.)
rem :: I've manually substituted "%computername%" for the actual text, and obfuscated some other details.
PartComponent                                                                           
\\%computername%\root\cimv2:Win32_UserAccount.Domain="%computername%",Name="ITGuy74" 
\\%computername%\root\cimv2:Win32_Group.Domain="US",Name="Domain Admins"               
\\%computername%\root\cimv2:Win32_Group.Domain="US",Name="XYZ_WKSTN_ADMINS"             
\\%computername%\root\cimv2:Win32_Group.Domain="US",Name="ALL_WKSTN_ADMINS"             

rem :: To reverse the search, I should be able to just flip it around, right?
rem :: I provide the Domain and Name properties of the PartComponent (Win32_Account object),
rem :: and get back the GroupComponent. Except, none of these work.
rem :: The middle one returns "Invalid query", and the other two just sit there.
rem :: I can't tell if they're hung, just running forever.
rem :: Same results with "Win32_Account" instead of "Win32_UserAccount".
WMIC path Win32_GroupUser Where (PartComponent^="Win32_UserAccount.Domain=\"%computername%\",Name=\"ITGuy74\""^) get GroupComponent
WMIC path Win32_GroupUser Where (PartComponent^="\\%computername%\root\cimv2:Win32_UserAccount.Domain=\"%computername%\",Name=\"ITGuy74\""^) get GroupComponent
WMIC path Win32_GroupUser Where (PartComponent^="\\\\%computername%\\root\\cimv2:Win32_UserAccount.Domain=\"%computername%\",Name=\"ITGuy74\""^) get GroupComponent
The first and third command should be what you are searching for (if i understand it right).
Actually i can't see a reason why it should fail.

Have you tested them from within a for loop (or why did you escape some characters)?
(If yes, then try from cmd line.)


douglas.swehla wrote:It's called Avecto Defendpoint (...)
(...)
(...) I'm still trying to figure that out.
Thanks, i will read into (as early as i got some more time).
There are too many possibilities to just guess.
In additon you won't see all accounts using wmi only.
The best summary about that i found here:
http://superuser.com/questions/248315/list-of-hidden-virtual-windows-user-accounts/638376.


douglas.swehla wrote:I don't think I'm a member of either of those. Will check in a bit to confirm.
I also don't think this.


douglas.swehla wrote:What we really want to know is whether the user can run FSUTIL or edit the Registry or do any of the things that require elevation, and I can do those things.
You are right: I lost that out of my eyes.
But i don't like to create fiules/directories only to check for admin rights:
In "my" University such accesses (creating/deleting/writing to objects in system directries) are logged, and our admin invites that user to explain herself/himself.
(Only on "important" computers.)


penpen

aGerman
Expert
Posts: 4654
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Creating a script to gather PC information - to assist those asking for help

#85 Post by aGerman » 28 Aug 2016 09:53

I removed the JScript part and replaced it with WMIC in order to shorten the code. All of you guys are very welcome to try it out and give a feedback. Thanks!

Code: Select all

@echo off
set ex_noreg=Disabled
2>nul set "ex_noreg=Enabled "
set de_noreg=Disabled
if "!!"=="" (set de_noreg=Enabled )

setlocal EnableExtensions DisableDelayedExpansion
cd /d "%~dp0"
>"%temp%\info.txt" echo [code^]

:: prepare some variables to shorten lines in the script
set "International=Control Panel\International"
set "CurrentVersion=SOFTWARE\Microsoft\Windows NT\CurrentVersion"
set "CodePage=SYSTEM\CurrentControlSet\Control\Nls\CodePage"
set "CMDproc=Software\Microsoft\Command Processor"
set /a "HKCU=80000001, HKLM=80000002, HKU=80000003"

:: try to assign variables for used tools in order to make the script run even if the path or pathext variables are corrupted
if exist "%__APPDIR__%chcp.com" (set "chcp=%__APPDIR__%chcp.com") else (set "chcp=echo" &>>"%temp%\info.txt" echo chcp.com not found.)
if exist "%__APPDIR__%find.exe" (set "find=%__APPDIR__%find.exe") else (set "find=echo" &>>"%temp%\info.txt" echo find.exe not found.)
if exist "%__APPDIR__%findstr.exe" (set "findstr=%__APPDIR__%findstr.exe") else (set "findstr=echo" &>>"%temp%\info.txt" echo findstr.exe not found.)
if exist "%__APPDIR__%gpresult.exe" (set "gpresult=%__APPDIR__%gpresult.exe") else (set "gpresult=" &>>"%temp%\info.txt" echo gpresult.exe not found.)
if defined gpresult >nul 2>nul %gpresult% /? || (set "gpresult=" &>>"%temp%\info.txt" echo gpresult.exe not accessible.)
if exist "%__APPDIR__%net.exe" (set "net=%__APPDIR__%net.exe") else (set "net=echo" &>>"%temp%\info.txt" echo net.exe not found.)
if exist "%SystemRoot%\notepad.exe" (set "notepad=%SystemRoot%\notepad.exe") else if exist "%__APPDIR__%notepad.exe" (
  set "notepad=%__APPDIR__%notepad.exe"
) else (set "notepad=%__APPDIR__%cmd.exe /k type" &>>"%temp%\info.txt" echo notepad.exe not found.)
if exist "%__APPDIR__%ping.exe" (set "ping=%__APPDIR__%ping.exe") else (set "ping=(for /l %%i in (0 1 10000) do echo %%i>nul)&echo" &>>"%temp%\info.txt" echo ping.exe not found.)
if exist "%__APPDIR__%reg.exe" (set "reg=%__APPDIR__%reg.exe") else (set "reg=foo?.exe" &>>"%temp%\info.txt" echo reg.exe not found.)
if exist "%__APPDIR__%whoami.exe" (set "whoami=%__APPDIR__%whoami.exe") else (set "whoami=" &>>"%temp%\info.txt" echo whoami.exe not found.)
if defined whoami >nul 2>nul %whoami% /? || (set "whoami=" &>>"%temp%\info.txt" echo whoami.exe not acessible.)
if exist "%__APPDIR__%wbem\WMIC.exe" (set "wmic=%__APPDIR__%wbem\WMIC.exe") else (set "wmic=" &>>"%temp%\info.txt" echo wmic.exe not found.)
if defined wmic >nul 2>nul %wmic% /? || (set "wmic=" &>>"%temp%\info.txt" echo wmic.exe not accessible.)
>>"%temp%\info.txt" echo --------------------------------------------------------------------------------

:: shorten WMI StdRegProv command lines
set "RegHead=set "dat="&for /f "tokens=1* delims==" %%i in ('2^>nul %wmic% /NameSpace:\\root\default Class StdRegProv Call"
set "RegTail=^|%findstr% /rc:"\^<[su]Value = "') do for %%k in (%%j) do set "dat=%%~k""


:: list of directories to check if missing in the path variable
set dirs="%SystemRoot%","%SystemRoot\System32%","%__APPDIR__%wbem","%__APPDIR__%WindowsPowerShell\v1.0"

:: list of tools to check if missing in the path environment
set tools=certutil,choice,clip,debug,forfiles,gpresult,icacls,openfiles,powershell,robocopy,timeout,whoami,wmic

:: check reg access
%reg% query "HKCU\%International%" >nul 2>&1 && (set "RegUserInternational=1") || (set "RegUserInternational=0")
%reg% query "HKU\.DEFAULT\%International%" >nul 2>&1 && (set "RegDefInternational=1") || (set "RegDefInternational=0")
%reg% query "HKLM\%CurrentVersion%" >nul 2>&1 && (set "RegSysCurrentVersion=1") || (set "RegSysCurrentVersion=0")
%reg% query "HKLM\%CodePage%" >nul 2>&1 && (set "RegSysCodePage=1") || (set "RegSysCodePage=0")
%reg% query "HKCU\%CMDproc%" >nul 2>&1 && (set "RegUserCMDproc=1") || (set "RegUserCMDproc=0")
%reg% query "HKLM\%CMDproc%" >nul 2>&1 && (set "RegSysCMDproc=1") || (set "RegSysCMDproc=0")

:: check AutoRun settings
set "AutoRunUser="
>"%temp%\autorun.tmp~" type nul
if %RegUserCMDproc%==1 (
  2>nul %reg% query "HKCU\%CMDproc%" /v AutoRun |>"%temp%\autorun.tmp~" %find% "REG_"
) else if defined wmic (
  2>nul %wmic% /NameSpace:\\root\default Class StdRegProv Call GetExpandedStringValue hDefKey="&H%HKCU%" sSubKeyName="%CMDproc%" sValueName="AutoRun" |>"%temp%\autorun.tmp~" %findstr% /rc:"\<[su]Value = "
)
<"%temp%\autorun.tmp~" set /p "AutoRunUser="
set "AutoRunSys="
>"%temp%\autorun.tmp~" type nul
if %RegSysCMDproc%==1 (
  2>nul %reg% query "HKLM\%CMDproc%" /v AutoRun |>"%temp%\autorun.tmp~" %find% "REG_"
) else if defined wmic (
  2>nul %wmic% /NameSpace:\\root\default Class StdRegProv Call GetExpandedStringValue hDefKey="&H%HKLM%" sSubKeyName="%CMDproc%" sValueName="AutoRun" |>"%temp%\autorun.tmp~" %findstr% /rc:"\<[su]Value = "
)
<"%temp%\autorun.tmp~" set /p "AutoRunSys="
del "%temp%\autorun.tmp~"

:: check elevation and Admin membership
set "RunAs="
%net% session >nul 2>&1 && (set "RunAs=Yes")
if not defined RunAs if defined wmic (
  2>nul %wmic% /NameSpace:\\root\default Class StdRegProv Call CheckAccess hDefKey="&H%HCU%" sSubKeyName="S-1-5-19" uRequired="&H1" |>nul %find% "TRUE" && set "RunAs=Yes"
)
if not defined RunAs set "RunAs=No"
set "LocalAdmin="
if defined whoami 2>nul %whoami% /groups|>nul %findstr% /i "\<S-1-5-32-544\>" && set "LocalAdmin=Yes" || set "LocalAdmin=No"
if not defined LocalAdmin if defined wmic (
  for /f "tokens=1* delims==" %%i in (
    '%wmic% path Win32_Group WHERE "LocalAccount='TRUE' AND SID='S-1-5-32-544'" GET Name /value'
  ) do for /f "delims=" %%k in ("%%j") do (
    for /f "tokens=1* delims=:" %%l in ('2^>nul %gpresult% /r /scope user ^| %findstr% /n /c:"--------" /c:"%%k"') do (
      set "check="
      for /f "delims=- " %%n in ("%%m") do set "check=1"
      if not defined check (
        set "n=%%l"
        set "LocalAdmin=No"
      ) else for /f %%n in ('set /a n') do if %%n lss %%l set "LocalAdmin=Yes"
    )
  )
) else set "LocalAdmin=Not found"

:: International
for %%a in ("iDate" "LocaleName") do set "%%~a="
if %RegUserInternational%==1 (call :RegInternational) else if defined wmic call :WmiInternational
if not defined iDate set "iDate=0"
if not defined LocaleName call :MUI
if "%iDate%"=="0" (set "format=mm/dd/yy") else if "%iDate%"=="1" (set "format=dd/mm/yy") else if "%iDate%"=="2" (set "format=yy/mm/dd")

:: ProductName
set "ProductName="
if %RegSysCurrentVersion%==1 (call :RegProductName) else if defined wmic call :WmiProductName
if not defined ProductName for /f "tokens=1* delims==" %%i in ('2^>nul %wmic% os get Caption /value') do set "ProductName=%%j"

:: Extensions and DelayedExpansion
for %%a in (es eu ds du) do set "%%a=Disabled"
if %RegUserCMDproc%==1 (call :RegUserProc) else if defined wmic call :WmiUserProc
if %RegSysCMDproc%==1 (call :RegSysProc) else if defined wmic call :WmiSysProc
if not defined eu set "eu=%ex_noreg%"
if not defined du set "du=%de_noreg%"

:: Code Pages
set "OEMCP=" &set "ACP="
if %RegSysCodePage%==1 (call :RegCodePage) else if defined wmic call :WmiCodePage
if not defined OEMCP for /f "tokens=2 delims=:" %%i in ('%chcp%') do set /a "OEMCP=%%~ni"
if not defined ACP (
  if defined wmic (
    for /f "tokens=2 delims==" %%i in ('%wmic% os get CodeSet /value') do set /a "ACP=%%i"
  )
)

:: checks path
:: removes random double quotes, adds double quotes, removes trailing slash
:: http://stackoverflow.com/questions/5471556/pretty-print-windows-path-variable-how-to-split-on-in-cmd-shell/5472168#5472168
set "p=%path:"=""%"
set "p=%p:^=^^%"
set "p=%p:&=^&%"
set "p=%p:|=^|%"
set "p=%p:<=^<%"
set "p=%p:>=^>%"
set "p=%p:;=^;^;%"
set p=%p:""="%
set "p=%p:"=""%"
set "p=%p:;;="";""%"
set "p=%p:^;^;=;%"
set "p=%p:""="%"
set "p=%p:"=""%"
set "p=%p:"";""=";"%"
set "p=%p:"""="%"
set "p=%p:\"="%"

:: Check for 64 bit windows.
set "bit="
if defined wmic (
  for /f "tokens=1* delims==" %%i in ('2^>nul %wmic% os GET OSArchitecture /value') do for /f "delims=" %%k in ("%%j") do set "bit=%%k"
)
if defined bit (echo "%bit%"|%find% "64" >nul && set "bit=64" || set "bit=32") else (
  echo "%PROCESSOR_ARCHITECTURE%"|%find% "86" >nul && set "bit=32" || (
    if exist "%SystemRoot%\SysWOW64\" (set "bit=64") else set "bit=32"
  )
)

:: RAM space
set "ram="
if defined wmic (
  for /f "tokens=1* delims==" %%i in ('2^>nul %wmic% os GET TotalVisibleMemorySize /value') do for /f "delims=" %%k in ("%%j") do set "ram=%%k"
)

:: get Windows version and the DIR command format to display
if "%notepad:~-3%"=="exe" (
  >nul %chcp% %ACP%
  for /f "delims=" %%a in ('^>nul %chcp% %ACP% ^&ver') do set "WinVer=%%a"
  if exist "%SystemDrive%\pagefile.sys" (
    for /f "delims=" %%a in ('^>nul %chcp% %ACP% ^&dir "%SystemDrive%\pagefile.sys" /a ^|%find% ":"') do set "DirFormat=%%a"
  ) else for /f "delims=" %%a in ('^>nul %chcp% %ACP% ^&dir "%__APPDIR__%ntoskrnl.exe" /a ^|%find% ":"') do set "DirFormat=%%a"
  >nul %chcp% %OEMCP%
) else (
  for /f "delims=" %%a in ('ver') do set "WinVer=%%a"
  if exist "%SystemDrive%\pagefile.sys" (
    for /f "delims=" %%a in ('dir "%SystemDrive%\pagefile.sys" /a ^|%find% ":"') do set "DirFormat=%%a"
  ) else for /f "delims=" %%a in ('dir "%__APPDIR__%ntoskrnl.exe" /a ^|%find% ":"') do set "DirFormat=%%a"
)

set "pad=                          "
:: create the information file and send the information to the clipboard if clip is available
>>"%temp%\info.txt" (
  setlocal EnableDelayedExpansion
  echo Windows version        :  !WinVer!
  echo Product name           :  !ProductName!, !bit! bit
  echo Performance indicators :  Processor Cores: !NUMBER_OF_PROCESSORS!      Visible RAM: !ram! kilobytes&echo(

  echo Date/Time format       :  (!format!^)  !date!  !time!
  echo __APPDIR__             :  !__APPDIR__!
  echo ComSpec                :  !comspec!
  echo PathExt                :  !PathExt!
  echo Extensions             :  system: !es!  user: !eu!
  echo Delayed expansion      :  system: !ds!  user: !du!
  echo Locale name            :  !LocaleName!       Code Pages: OEM  !OEMCP!    ANSI !ACP!
  echo DIR  format            :  !DirFormat!
  echo Permissions            :  Elevated Admin=!RunAs!, Admin group=!LocalAdmin!
  if defined AutoRunSys echo System  Autorun found  :  !AutoRunSys!
  if defined AutoRunUser echo User    AutoRun found  :  !AutoRunUser!
  endlocal&echo(

  rem report if path elements are missing
  for %%i in (%dirs%) do (
    set "found="
    setlocal EnableDelayedExpansion
    for %%j in ("!p!") do (
      endlocal
      if /i "%%~i"==%%j set "found=1"
      setlocal EnableDelayedExpansion
    )
    endlocal
    if not defined found echo(%pad%Missing from the PATH environment: %%~i
  )

  rem report if tools are missing
  for %%i in (%tools%) do for /f "tokens=1,2 delims=?" %%j in ("%%~i.exe?%%~i.com") do if "%%~$PATH:j%%~$PATH:k"=="" (
    echo(%pad%Missing from the tool collection:  %%i
  )
  echo [/code^]
)

:: load the information into Notepad where it can also be copied to the clipboard
start "" %notepad% "%temp%\info.txt" & %ping% -n 2 127.0.0.1 >nul & del "%temp%\info.txt"

goto :eof

:: ~~~~~~~~~ Sub Routines ~~~~~~~~~
:RegInternational
for /f "tokens=1,2*" %%a in ('%reg% query "HKCU\%International%" /v "iDate" 2^>nul ^| %find% "REG_"') do set "%%~a=%%~c"
if %RegDefInternational%==1 for /f "tokens=1,2*" %%a in ('%reg% query "HKU\.DEFAULT\%International%" /v "iDate" 2^>nul ^| %find% "REG_"') do if not defined %%~a set "%%~a=%%~c"
for /f "tokens=1,2*" %%a in ('%reg% query "HKCU\%International%" /v "LocaleName" 2^>nul ^| %find% "REG_"') do set "%%~a=%%~c"
goto :eof

:WmiInternational
%RegHead% GetStringValue hDefKey^="&H%HKCU%" sSubKeyName^="%international%" sValueName^="iDate" %RegTail%
if not defined dat %RegHead% GetStringValue hDefKey^="&H%HKU%" sSubKeyName^=".DEFAULT\%international%" sValueName^="iDate" %RegTail%
if defined dat (set "iDate=%dat%") else set "iDate=0"
%RegHead% GetStringValue hDefKey^="&H%HKCU%" sSubKeyName^="%international%" sValueName^="LocaleName" %RegTail%
if defined dat (set "LocaleName=%dat%") else set "LocaleName="
goto :eof

:MUI
for /f "tokens=2 delims=={}" %%i in ('2^>nul %wmic% os get MUILanguages /value') do set "LocaleName=%%i"
if defined LocaleName (
  set "LocaleName=%LocaleName:"=%"
) else (
  setlocal EnableDelayedExpansion
  for /f %%i in ('dir /ad /b "%__APPDIR__%??-??"^|%findstr% /x "[a-z][a-z]-[a-z][a-z]"') do (
    if exist "%__APPDIR__%%%i\ulib.dll.mui" set "LocaleName=!LocaleName!,%%i"
  )
  if defined LocaleName (for /f %%j in ("!LocaleName:~1!") do (endlocal &set "LocaleName=%%j")) else endlocal
)
goto :eof

:RegProductName
for /f "tokens=2*" %%a in ('%reg% query "HKLM\%CurrentVersion%"^|%find% /i "ProductName"') do set "ProductName=%%b"
goto :eof

:WmiProductName
%RegHead% GetStringValue hDefKey^="&H%HKLM%" sSubKeyName^="%CurrentVersion%" sValueName^="ProductName" %RegTail%
if defined dat (set "ProductName=%dat%") else set "ProductName="
goto :eof

:RegUserProc
%reg% query "HKCU\%CMDproc%" /v "EnableExtensions" 2>nul|%find% "0x1">nul && set "eu=Enabled "
%reg% query "HKCU\%CMDproc%" /v "DelayedExpansion" 2>nul|%find% "0x1">nul && set "du=Enabled "
goto :eof

:WmiUserProc
%RegHead% GetDWORDValue hDefKey^="&H%HKCU%" sSubKeyName^="%CMDproc%" sValueName^="EnableExtensions" %RegTail%
if "%dat%"=="1" set "eu=Enabled "
%RegHead% GetDWORDValue hDefKey^="&H%HKCU%" sSubKeyName^="%CMDproc%" sValueName^="DelayedExpansion" %RegTail%
if "%dat%"=="1" set "du=Enabled "
goto :eof

:RegSysProc
%reg% query "HKLM\%CMDproc%" /v "EnableExtensions" 2>nul|%find% "0x1">nul && set "es=Enabled "
%reg% query "HKLM\%CMDproc%" /v "DelayedExpansion" 2>nul|%find% "0x1">nul && set "ds=Enabled "
goto :eof

:WmiSysProc
%RegHead% GetDWORDValue hDefKey^="&H%HKLM%" sSubKeyName^="%CMDproc%" sValueName^="EnableExtensions" %RegTail%
if "%dat%"=="1" set "es=Enabled "
%RegHead% GetDWORDValue hDefKey^="&H%HKLM%" sSubKeyName^="%CMDproc%" sValueName^="DelayedExpansion" %RegTail%
if "%dat%"=="1" set "ds=Enabled "
goto :eof

:RegCodePage
for /f "tokens=3" %%a in ('%reg% query "HKLM\%CodePage%" /v "OEMCP"') do set /a "OEMCP=%%a"
for /f "tokens=3" %%a in ('%reg% query "HKLM\%CodePage%" /v "ACP"') do set /a "ACP=%%a"
goto :eof

:WmiCodePage
%RegHead% GetStringValue hDefKey^="&H%HKLM%" sSubKeyName^="%CodePage%" sValueName^="OEMCP" %RegTail%
if defined dat (set "OEMCP=%dat%") else set "OEMCP="
%RegHead% GetStringValue hDefKey^="&H%HKLM%" sSubKeyName^="%CodePage%" sValueName^="ACP" %RegTail%
if defined dat (set "ACP=%dat%") else set "ACP="
goto :eof

Steffen

//EDIT
09/09/2016 replaced %sys32% with %__APPDIR__%, changed code page to get the Windows version, added the contents of %__APPDIR__% and %PATHEXT% to the output, corrected wrong WHOAMI handling
09/07/2016 removed clock hours, added ComSpec and AutoRun check
09/03/2016 corrected the WMIC registry handling
09/01/2016 corrected the code page handling, removed CLIP
08/31/2016 switch to ANSI code page when outputting the DIR format
08/29/2016 corrected unit of visible RAM, added alternative file for DIR format

Compo
Posts: 599
Joined: 21 Mar 2014 08:50

Re: Creating a script to gather PC information - to assist those asking for help

#86 Post by Compo » 28 Aug 2016 14:32

Is there a specific reason for using pagefile.sys?

I'd suggest an essential file, such as %WinDir%\system32\ntoskrnl.exe, one defined in the system environment such as, %comspec% or even using one of the files you've already determined the existence of elsewhere in the script.

aGerman
Expert
Posts: 4654
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Creating a script to gather PC information - to assist those asking for help

#87 Post by aGerman » 28 Aug 2016 15:00

Compo wrote:Is there a specific reason for using pagefile.sys?

Its size is another indicator for the performance. Thus, it's a good choice in my opinion.

Steffen

Compo
Posts: 599
Joined: 21 Mar 2014 08:50

Re: Creating a script to gather PC information - to assist those asking for help

#88 Post by Compo » 28 Aug 2016 15:28

Regardless of reasons why it shouldn't be, I know of many people who remove it or simply move it, and there are many sites explaining how to do so.

aGerman
Expert
Posts: 4654
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Creating a script to gather PC information - to assist those asking for help

#89 Post by aGerman » 29 Aug 2016 05:32

Point taken. Thanks! As soon as I update the script next time I'll choose another file.

Steffen

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: Creating a script to gather PC information - to assist those asking for help

#90 Post by foxidrive » 29 Aug 2016 07:12

Compo wrote:Regardless of reasons why it shouldn't be, I know of many people who remove it or simply move it, and there are many sites explaining how to do so.

You're right Compo, as I ran without a page file for years.

I would comment though that a person who has disabled or moved their page file is likely to have a fairly good ability and understanding of general computer technology and will have a good level of awareness of information needed in batch scripting.

The point of pagefile.sys was that it shows the amount of virtual ram and also the last boot time as a byproduct of the file list itself. These give indications that may be useful in diagnosing a problem but aren't harmful in any way. Accordingly I'd suggest that the c:\pagefile.sys be tested for and if it doesn't exist then a different file can be used.

aGerman, you've taken this a long way with all the input here.
This is the output of your last script as a sample.


Code: Select all

----------------------------------------------------------------------------
Windows version        :  Microsoft Windows [Version 6.3.9600]
Product name           :  Windows 8.1 Pro with Media Center, 32 bit
Performance indicators :  Processor Cores: 8      Visible RAM: 3390680 Bytes

Date/Time format       :  dd/mm/yy (24 hours)     Mon 29/08/2016  23:03:15.81
Extensions             :  system: Enabled   user: Enabled
Delayed expansion      :  system: Disabled  user: Disabled
Locale name            :  en-AU       Code Pages: OEM  850    ANSI 1252
DIR  format            :  29/08/2016  05:42     3,484,418,048 pagefile.sys
Permissions            :  Elevated Admin=No, Admin group=Yes



The RAM figure seems to be Kbytes. I didn't check the script to see (brain fade).

Post Reply