I am trying to work out how to detect whether a user is running with admin rights under Windows XP. This is fairly easy to do in Vista/Win7 thanks to the whoami command. Here's a snippet in Ruby for how to do it under Vista:
Note, the following link now incorporates the solution suggested by muteW
http://gist.github.com/65931
The trouble is, whoami doesn't come with Windows XP and so the above linked method will always return false on WinXP, even if we're running as an administrator.
So, does anyone know of a way to detect whether we're running as an admin under Windows XP using Ruby, command-line tools, batch-files, or even third-party (needs to be open source, really) tools?
This will detect if the user is running in elevated mode (eg a command prompt that was "Run As" Administrator). It relies on the fact that you require admin privileges to read the LOCAL SERVICE account reg key:
reg query "HKU\S-1-5-19"
this will return a non-zero error code if it cannot be read, and zero if it can.
Works from XP up...
If you run
>net localgroup administrators
in a command shell you should get the list of administrator accounts in Windows XP. Simply parse and scan the output to check for the particular user account you want. For e.g. to check if the current user is an administrator you could do -
>net localgroup administrators | find "%USERNAME%"
Piskvor option its fine, or check this url
http://weseetips.com/2008/04/16/how-to-check-whether-current-user-have-administrator-privilege/
this is the code in that page
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
PSID AdministratorsGroup;
// Initialize SID.
if( !AllocateAndInitializeSid( &NtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&AdministratorsGroup))
{
// Initializing SID Failed.
return false;
}
// Check whether the token is present in admin group.
BOOL IsInAdminGroup = FALSE;
if( !CheckTokenMembership( NULL,
AdministratorsGroup,
&IsInAdminGroup ))
{
// Error occurred.
IsInAdminGroup = FALSE;
}
// Free SID and return.
FreeSid(AdministratorsGroup);
return IsInAdminGroup;
Check out the CheckTokenMembership method. There is a sample there of IsUserAdmin() implementation plus some other useful community feedback on when that function does not return what is expected and what to do to improve it.
This will find out without shelling out:
require 'win32/registry'
is_admin = false
begin
Win32::Registry::HKEY_USERS.open('S-1-5-19') {|reg| }
is_admin = true
rescue
end
The strategy is similar to Peter's, but with less overhead.
Here is the better (PowerShell) way of doing it: https://stackoverflow.com/a/16617861/863980
In one line, you can say (copy/paste in posh and it will work):
(#(([ADSI]"WinNT://./Administrators,group").psbase.Invoke("Members")) | `
foreach {$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)}) -contains "Administrator"
=> returns True when user belongs to Administrators group (as opposed to checking user IS Administrator)
(Note: backtick or grave accent ` escapes the carriage return in PowerShell, in Ruby it executes the shell commands, like C++'s system('command')..)
So in Ruby, you can say (copy/paste in irb):
def is_current_user_local_admin?
return `powershell "(#(([ADSI]'WinNT://./Administrators,group').psbase.Invoke('Members')) | foreach {$_.GetType().InvokeMember('Name', 'GetProperty', $null, $_, $null)}) -contains 'Administrator'"`.include? "True"
end
Don't know the (even better) WMI way of doing it though. With that, you could have done something like (in Ruby again):
require 'win32ole'
wmi = WIN32OLE.connect('WinNT://./Administrators,group')
# don't know what should come here...
Related
I am using this code and it works fine in the ISE but not when run as a script. The error I get is "Specified cast is not valid" and it occurs at the last line shown here. I am thinking it is the Set-Type that is actually the problem, but I removed -ignoreWarnings and I get no indication of a problem. I get the same error if I launch the script with Run as administrator or not. My hope is that WinAPIs isn't something that is limited to the ISE
Add-Type -typeDefinition #'
using System;
using System.Runtime.InteropServices;
namespace WinAPIs {
public class UserAccountPicture {
[DllImport("shell32.dll", EntryPoint = "#262", CharSet = CharSet.Unicode, PreserveSig = false)]
public static extern void SetUserTile(string username, int notneeded, string picturefilename);
}
}
'# -ignoreWarnings
[WinAPIs.UserAccountPicture]::SetUserTile($userName, 0, $imagePath)
I also tried an alternate approach with the same results.
$methodDefinition = #'
[DllImport("shell32.dll", EntryPoint = "#262", CharSet = CharSet.Unicode, PreserveSig = false)]
public static extern bool SetUserTile(string username, int notneeded, string picturefilename);
'#
$shell32 = Add-Type -memberDefinition:$methodDefinition -name:'shell32' -namespace:'Win32' -passThru
$shell32::SetUserTile("RTC", 0, "$scriptPath\RTC.bmp")
I am rather out of my element here, so hopefully someone can point me at my mistake. Or verify that I just can't do this in a script.
thanks!
From this post:
CoInitialize(NULL)/CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) must
be called prior to calling this function.
Have you tried to call this functions beforehand?
What's your PowerShell version? Because this may be related to STA\MTA modes:
Did you know that in Windows PowerShell 3.0, we changed the Windows
PowerShell console from multi-threaded apartment (MTA) to
single-threaded apartment (STA)? If you did not notice the change, you
are probably not doing anything that requires MTA mode. If all of a
sudden, you have some Windows PowerShell 2.0 or even Windows
PowerShell 1.0 scripts that no longer work, now you know why.
You can check your PS host's mode this way: $host.Runspace.ApartmentState
Even if you're using PS 3 and higher, you could try to launch PowerShell.exe with -Sta or -Mta parameters and see, if this makes any difference.
Moreover, I've tried your code on PS 5.0 and it works both in ISE and PowerShell console.
UPDATE: This is defintely STA\MTA issue:
The function is in shell32.dll. It doesn’t have a name but the ordinal
262. It takes a username (MACHINE\user or DOMAIN\user format), a zero (the usual reserved stuff, I guess), and a picture path (can be any
well known format or size) parameter, and returns an HRESULT. If you
pass a null username, then the result of GetUserNameEx with a
NameSamCompatible parameter will be used. It uses COM inside, and
only works on STA threads (otherwise throws an InvalidCastException (0×80004002, E_NOINTERFACE)).
The thing I don't understand, is that why your PowerShell console runs as MTA, it shouldn't do this.
I'd like to have some usage statistics for a bunch of my modules.
It would be handy if I could run code whenever a function is called from a set of modules. Is it doable? Do powershell generate internal events we can hook on? I can not find any guidance yet
It's not completely clear to me whether you're more interested in logging events or executing code (hooking).
Logging
There are 2 places where in the event log where Powershell writes to the logs:
Applications and Services > Windows PowerShell
Applications and Services > Microsoft > Windows > PowerShell
On a per-module level, you can enable the LogPipelineExecutionDetails property. To do it on load:
$mod = Import-Module ActiveDirectory
$mod.LogPipelineExecutionDetails = $true
Or for an already loaded module:
$mod = Get-Module ActiveDirectory
$mod.LogPipelineExecutionDetails = $true
After that you check the first of the event log locations I listed (Windows PowerShell) and you'll see logs that show the calls to various cmdlets with the bound parameters.
You can also enable this via Group Policy as a Computer or User setting:
Administrative Templates > Windows Components > Windows PowerShell > Turn On Module Logging
You can specify the module(s) you want to enable logging for.
In PowerShell v5, there will be even more detailed logging available (see the link).
Source
You can see more detailed information about the logging settings (current and upcoming) on Boe Prox's blog: More New Stuff in PowerShell V5: Extra PowerShell Auditing
Hooking
As far as I know there is no direct way to hook calls in an existing module, but I have a crappy workaround.
You can effectively override existing cmdlets/functions by creating functions or aliases with the same name as the original.
Using this method, you could create wrappers around the specific functions you want to track. Consider something like this:
# Override Get-Process
function Track-GetProcess {
[CmdletBinding()]
param(
# All the parameters that the original function takes
)
# Run pre-execution hook here
& { "before" }
$params = #{}
foreach($h in $MyInvocation.MyCommand.Parameters.GetEnumerator()) {
try {
$key = $h.Key
$val = Get-Variable -Name $key -ErrorAction Stop | Select-Object -ExpandProperty Value -ErrorAction Stop
if (([String]::IsNullOrEmpty($val) -and (!$PSBoundParameters.ContainsKey($key)))) {
throw "A blank value that wasn't supplied by the user."
}
Write-Verbose "$key => '$val'"
$params[$key] = $val
} catch {}
}
Get-Process #params # call original with splatting
# run post execution hook here
& { "after" }
}
The middle there uses splatting to send the given parameters and sending them to the real cmdlet.
The hardest is part is manually recreating the parameter block. There are ways you could likely do that programmatically if you wanted to quickly run something to hook any function, but that's a bit beyond the scope of this answer. If you wanted to go that route, have a look at some of the code in this New-MofFile.ps1 function, which parses powershell code using powershell's own parser.
I have some perl scripts which are scheduled using task scheduler in windows 2003 R2 and 2008. These scripts are called directly using perl.exe or via a batch file.
Sometimes these scripts fails to execute (crashes maybe) and we are not aware of these crashes.
Are there any ways a mail can be sent when these script crashes? more or less like monitoring of these scripts
Thanks in advance
Karthik
Why monitor the scripts from the outside when you can make the plugins to monitor theirself? First you can use eval in order to catch errors, and if an error occours you can send an email with the Net::SMTP module as rpg suggested. However I highly recommend you to use some kind of log file in order to keep trace of what happened right before the error and what caused the error. Your main goal should be to avoid the error. That ofcourse requires you to modify the scripts, if, for any reason, you cannot do that then the situation may be a little more complicated because you need another script.
With the Win32::Process::Info module you can retrieve running processes on Windows and check if your plugin is running or not.
while(1) {
my $found = false;
my $p = Win32::Process::Info->new;
foreach my $proc ($pi->GetProcInfo) {
if ($proc->{Name} =~ /yourscriptname/i ) {
found = true;
}
}
if ($found eq 'false') {
# send email
my $smtp = Net::SMTP->new("yoursmtpserver");
eval {
$smtp->mail("sender#test.it");
$smtp->recipient("recipient#test.it");
$smtp->data;
$smtp->datasend("From: sender#test.it");
$smtp->datasend("\n");
$smtp->datasend("To: recipient#test.it");
$smtp->datasend("\n");
$smtp->datasend("Subject: Plugin crashed!");
$smtp->datasend("\n");
$smtp->datasend("Plugin crashed!");
$smtp->dataend;
$smtp->quit;
};
}
sleep(300);
}
I did not test this code because I don't have Perl installed on Windows but the logic should be ok.
For monitoring - Please check the error code. This will help you for its failure.
For mail sending - You can use Net::SMTP module to send email. Let me know if you need a code snippet for it.
You can use PushMon to monitor your scripts. What you do is create PushMon URLs that matches the schedule of your Perl scripts. Then you should "ping" these URLs when your scripts run successfully. If these URLs are not accessed, maybe because your scripts crashed or there's a power failure, PushMon will notify you by email.
Disclaimer: I am associated with PushMon.
i am trying to run a code in c++ which will result in an .exe file running at startup using registry...but the problem is that the code results fails without showing any errors...i compiled the code in devcpp...
the code is
void createkey(char *path)
{
int reg;
HKEY hkey,Hkey1;
DWORD ptr;
reg=RegOpenKeyEx(HKEY_LOCAL_MACHINE,TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"),0,KEY_SET_VALUE,&hkey);
if(reg=ERROR_SUCCESS)
cout<<"success"<<endl;
else
cout<<"failure"; //(a)
cout<<reg<<endl; //(b)
if(reg==0)
{
RegSetValueEx(hkey,TEXT("key"),0,REG_SZ,(BYTE*)path,strlen(path));
}
}
in the command line failure and 0 got printed as a result of (a) and (b)...(dont know how as the two mean completely opposite things )....the char *path passed to regsetvalueex was "c:/Dev-Cpp/bin/Untitled2.exe"...i am sure that the functions are not working as key doesnt appear in run key(i checked using regedit)...
if(reg=ERROR_SUCCESS)
That's an assignment, you need to use the == operator. Most modern compilers warn about this, be sure to update yours. You probably got an access denied error, can't write to HKLM\Software without elevation.
Standard users don't have write access to HKLM. You need to run this process elevated.
I have to create a console application which needs certain parameters. If they are missing or wrong I print out an error message.
Now the problem: If someone starts the program from the explorer by double-clicking the console window disappears immediately. (But the application is not entirely useless from the explorer, you could drag files onto it and it would work)
I could always wait for a keypress, but I don't want that if the user did start it from the command line.
Is there some way to distinguish between these situations?
See http://support.microsoft.com/kb/99115, "INFO: Preventing the Console Window from Disappearing".
The idea is to use GetConsoleScreenBufferInfo to determine that the cursor has not moved from the initial 0,0 position.
Code sample from #tomlogic, based on the referenced Knowledge Base article:
// call in main() before printing to stdout
// returns TRUE if program is in its own console (cursor at 0,0) or
// FALSE if it was launched from an existing console.
// See http://support.microsoft.com/kb/99115
#include <stdio.h>
#include <windows.h>
int separate_console( void)
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
if (!GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE), &csbi))
{
printf( "GetConsoleScreenBufferInfo failed: %lu\n", GetLastError());
return FALSE;
}
// if cursor position is (0,0) then we were launched in a separate console
return ((!csbi.dwCursorPosition.X) && (!csbi.dwCursorPosition.Y));
}
GetConsoleTitle()
I've seen code which performs
if (!GetConsoleTitle(NULL, 0) && GetLastError() == ERROR_SUCCESS) {
// Console
} else {
// GUI
}
BUT... I've found that AttachConsole() is more helpful
In C++ (off the top of my head, and I'm no C++ programmer)
if (!AttachConsole(ATTACH_PARENT_PROCESS)) {
// GUI
} else {
// Console, and you have a handle to the console that already exists.
}
Is more effective. Additionally, if you find yourself in a GUI environment and would like to stay there as long as you can, but later find something catastrophic has happened that could really use a dump to a console window (you can't be arsed writing an edit box window to lot it to or attach to the NT System log and throw up a MessageBox()) well then you can AllocConsole() later on in the process, when GUI methods have failed.
I've found a much better solution using GetConsoleProcessList to get the attached process count to the current console.
If this process is the only one attached it will be closed when the process exists.
I found it in a post https://devblogs.microsoft.com/oldnewthing/20160125-00/?p=92922
But it had a bug (at least in windows 10) since the documentation forbids invoking this function with null.
My solution was:
DWORD procId;
DWORD count = GetConsoleProcessList(&procId, 1);
if (count < 2) ...
I believe cmd.exe sets the CMDCMDLINE and CMDEXTVERSION environemntal variables when it starts. So if these are set your program was most probably started from a shell.
This isn't foolproof but it's something.
It's also possible to determine your parent PID in a few convoluted and possibly unreliable ways, or so I gather. You may want to look into that.
Here is the excellent answer from #DanielBenSassoon adapted for C#. Tested in Visual Studio 2019 and Windows 10.
// Gets a list of the process IDs attached to this console
[DllImport("kernel32.dll", SetLastError = true)]
private static extern uint GetConsoleProcessList(uint[] processList, uint processCount);
public static bool IsFinalProcess()
{
// See: https://devblogs.microsoft.com/oldnewthing/20160125-00/?p=92922
uint[] procIDs = new uint[64];
uint processCount = GetConsoleProcessList(procIDs, 64);
return (processCount < 2);
}
This approach allows you to distinguish between four scenarios:
Debugging from the IDE (F5) [process count = 1]
Running from the IDE, but not debugging (Ctrl + F5) [process count = 2]
Double-clicking in Explorer [process count = 1]
Running from a command-prompt window [process count = 2]
When IsFinalProcess is true, you can use Console.ReadKey(false); to prevent the console window from disappearing after your application exits.
EDIT: I've been using this .bat/.cmd wrapper successfully for a couple of years now:
#ECHO OFF
REM Determine if script was executed from an interactive shell
(echo %CMDCMDLINE% | find /i "%~0" >NUL 2>&1) && (set IS_INTERACTIVE=false) || (set IS_INTERACTIVE=true)
<call console application here>
REM Wait for keystroke
if "%IS_INTERACTIVE%" == "false" (
echo.
echo Hit any key to close.
pause >NUL 2>&1
)
The advantage here is that this will work for all console applications, be it your own or someone else's (for which you might not have sources you could modify). The downside is, well, that you have a separate wrapper.
My original answer back in 2014 was this:
This works like a charm:
#echo off
for %%x in (%cmdcmdline%) do if /i "%%~x"=="/c" goto nonconsole
:console
<do something>
goto exit
:nonconsole
<do something>
pause
:exit
Copied from this thread. I also tried evaluating %cmdcmdline% myself, however there's an issue regarding quote characters ("), which prevents something like if "%cmdcmdline%" == "%ComSpec%" goto [target] from working.