A Roth
Consulting Accounts C++ library.
Back to the top
The Deal With UserCheckPassword()
The deal with
UserCheckPassword() is that Win32 does not really support this
function so I hacked one together. What it is actually doing is attempting to
change the password for
$User
in the domain
$Domain to be
$Password. Now the theory is
that if
$Password is the user's
current password then you are simply changing it to be itself. This returns a
success. If
$Password is not
the current password then the Win32 function that allows you to change passwords
will not grant you authorization to change the password hence failure. Cool?
Almost...
You see, there can be several reasons
why this fails even though the password is correct. Let's say that the system
admin has set the domain so that you can not use the same password again. Or
let's say that that particular user does not have authority to change his
password. Another more practical way to to attempt to log on as the user. You
still need the domain, userid and password but this time all you need to do is
make sure that the user has the authority to log on (as either batch or
interactive).
Windows 95/98
Note:
Many of the functions that this extension
supports do not exist in Windows 95 so it may fail. If you have troubles with
this extension on a Win 95 machine try running the script on an NT box.
Back to the top
What is this Parse Exception error all about?
The ActiveState builds occasionally
change the way extensions internally work. This causes a problem when you are
attempting to load an extension designed for, let's say, build 303 into build
306. If you tried to do this you would get an error message indicating that a
"parse exception" has occurred.
The easy way to contend with this is to either...
recompile the extension with the headers for your build
of Perl OR
download a build of the extension that matches your
build of Perl.
You will need to know which build of Win32 Perl you are using.
The rule of thumb is you want to use the build that is
closest or earlier than your current build. So if you are using build 313 then
you want to download AdminMisc_Build_311.zip since there are none for 313 or 312. (This
is because all three of these builds are compatible with each other)
The AdminMisc_Build_xxx.zip is a replacement for the AdminMisc.PLL file. You need to
download and install the entire package then, if you need it, download the
specific build.
The package and builds are
available from our FTP site as
ftp://ftp.roth.net/pub/ntperl/adminmisc//
Back to the top
How to discover your Win32 Perl build number
You can discover which build of Win32 Perl you have by
entering:
of which you should see something similar to:
c:\> perl -v Copyright 1987-1996, Larry Wall
+ suidperl security patch
Win32 port Copyright (c) 1995-1996 Microsoft Corporation.
All rights reserved.
Developed by ActiveWare Internet Corp.
Perl for Win32 Build 306 - Built 17:50:28 Apr 10 1997 c:\> |
The bold text is the build number.
Back to the top
List of Functions:
ComputerAliasAdd( $Machine, $Alias
)
This will add a computer alias to the computer specified
by $Machine.
$Machine must be a proper
computer an alias name ( such as \\server1 ). If the first parameter is left as an empty string then
the local machine will be assumed.
The second parameter ($Alias) is a name (not a proper computer name) so don't prepend
any slashes.
A computer alias is another name which a machine will
respond to. If you give \\server1 an alias of Fred then the following paths are identical:
\\Server1\Files\myfile.txt
\\Fred\Files\myfile.txt
The alias will be in effect until the machine specified
by the first parameter ($Machine) is rebooted or until the alias is removed
(with the ComputerAliasDel() ) function.
NOTE: There is a bug in NT
4.0 in which machines are unable to connect to printer shares using an alias. It
is possible to either:
a) Physically map a printer port as in : net use lpt4: \\Fred\printer1
b) Edit the Registry so that your machine is "hard
wired" to know about the alias:
HKEY_Local_Machine\System\CurrentControlSet\Services\LanmanServer\Parameters
Add a value called "OptionalNames>",
make it a REG_MULTI_SZ type.
Next add all aliases names (one per line) that you want your machine to
recognize.
Refer to Microsoft's knowledge support
article: http://support.microsoft.com/support/kb/articles/q187/3/32.asp
(Microsoft referes to an Alias
as an OptionalName).
(Thanks to Peter Thomas for this info!)
Example:
Win32::AdminMisc::ComputerAliasAdd( '\\\\Server1', 'fred' );
Returns:
0 if not successful
1 if
successful
Back to the top
ComputerAliasDel( $Machine, $Alias
)
This will remove a computer alias from the computer
specified by $Machine.
$Machine
must be a proper computer name ( such as \\server1 ). If the first
parameter is left as an empty string then the local machine will be assumed.
The second parameter ($Alias) is an alias name (not a proper computer name) so don't
prepend any slashes.
The alias will be removed immediately. All
resources connected to the machine using it's alias will become invalid.
This means drive letters and printers mapped to the machine by means of the
alias name will no longer be effective unless the alias is recreated. You
can use the ComputerAliasAdd()
function to create aliases.
Example:
Win32::AdminMisc::ComputerAliasDel( '\\\\Server1', 'fred' );
Returns:
0 if not successful
1 if
successful
Back to the top
CreateProcessAsUser($CommandString [, $DefaultDirectory] [,
%Config])
This will create a process that will be running under
the account that you are impersonating with LogonAsUser().
- $CommandString
- The full command line of the processes to run.
- $DefaultDirectory
- The default directory that the process runs in.
- %Config
- A hash of values that specify a configuration the
process is to run with.
The %Config hash can consist of any of the following:
- Title
- The title of the processes window.
- Desktop
- A virtual desktop. Leave this blank if you are not
familiar with it. The default is "winsta0\default".
- X
- The X coordinate of the upper left corner of the
processes window.
- Y
- The Y corrdinate of the upper left corner of the
processes window.
- XSize
- The width of the processes window (in pixels).
- YSize
- The height of the processes window (in pixels).
- XBuffer
- Number of chars the X buffer should be. This
applies only to console applications.
- YBuffer
- Number of chars to Y buffer should be. This applies
only to console applications.
- Fill
- The color to fill the window. This applies only to
console applications. Possible values can be logically OR'ed together:
BACKGROUND_RED
BACKGROUND_BLUE
BACKGROUND_GREEN
BACKGROUND_INTENSITY
FOREGROUND_RED
FOREGROUND_GREEN
FOREGROUND_BLUE
FOREGROUND_INTENSITY
- Priority
- The priority to run the process under. It can use
one of the following:
HIGH_PRIORITY_CLASS
IDLE_PRIORITY_CLASS
NORMAL_PRIORITY_CLASS
REALTIME_PRIORITY_CLASS
- Flags
- Flags specifying process startup options. Some of
these can be logically ORed together:
CREATE_DEFAULT_ERROR_MODE
CREATE_NEW_CONSOLE
CREATE_NEW_PROCESS_GROUP
CREATE_SEPARATE_WOW_VDM
CREATE_SUSPENDED
CREATE_UNICODE_ENVIRONMENT
DEBUG_PROCESS
DEBUG_ONLY_THIS_PROCESS
DETACHED_PROCESS
- ShowWindow
- State of the processes window during startup.
Possible values are:
SW_HIDE
SW_MAXIMIZE
SW_MINIMIZE
SW_RESTORE
SW_SHOW
SW_SHOWDEFAULT
SW_SHOWMAXIMIZED
SW_SHOWMINIMIZED
SW_SHOWMINNOACTIVE
SW_SHOWNOACTIVATE
SW_SHOWNORMAL
- StdInput
StdOutput
StdError
- Specifies which handle to use for standard STDIN, STDOUT and STDERR. If one of these is specified all must be specified. You can use GetStdHandle() to retrieve the handle for the current
standard handle.
- Inherit
- Specifies to inherit file handles.
- Directory
- Specifies a default directory. This is the same
attribute as the $DefaultDirectory.
This function requires the calling process to have the
following rights assigned:
Privilege Display
Name
---------------
-----------------------------------
SeTcbPrivilege.....Act as part of the
operating system
SeAssignPrimary....Replace a process level token
SeIncreaseQuota....Increase quotas
Example:
use Win32::AdminMisc;
use Win32;
if (Win32::AdminMisc::LogonAsUser($Domain, $User, $Password, LOGON32_LOGON_INTERACTIVE)){
print "Successfully logged on.\n";
print "\nLaunching $Program...\n";
$Result = Win32::AdminMisc::CreateProcessAsUser(
$Process,
"Flags", CREATE_NEW_CONSOLE,
"XSize", 640,
"YSize", 400,
"X", 200,
"Y", 175,
"XBuffer", 80,
"YBuffer", 175,
"Title", "Title: $User" . "'s $Process program",
"Fill", BACKGROUND_BLUE |
FOREGROUND_RED |
FOREGROUND_BLUE |
FOREGROUND_INTENSITY |
FOREGROUND_GREEN,
);
if ($Result){
print "Successful! The new PID is $Result.\n";
}else{
print "Failed.\n\tError: " . Win32::FormatMessage(Win32::AdminMisc::GetError()) . "\n";
}
}else{
print "Failed to logon.\n\tError: " . Win32::FormatMessage(Win32::AdminMisc::GetError()) "\n";
}
Returns:
undef if unsuccessful
process
id (PID) if successful
Back to the top
DelEnvVar( $Name [, $Type [, $Timeout ] ]
)
This will delete an environmental variable $Name.
The
affect of this function will be seen globally, not only the currently running
process.
If $Timeout is specified then the broadcast announcement will be
aborted if it takes longer than $Timeout seconds (some applications may be in a hung state so they
can not acknowledge the broadcast). If this timeout occurs the variable will
still be updated but broadcasting it's change will be aborted.
If $Type is specified it can be one of:
- ENV_SYSTEM
- Specifies that $Name will be a system environmental variable. (default if
$Type is not specified)
- ENV_USER
- Specifies that $Name will be a user environemental variable.
-
This function is the equivalent to setting an
environental variable in the control panel's system applet.
NOTE: Your script will not
see the new value. For that you should set $ENV{xxx}.
Example:
Win32::AdminMisc::DelEnvVar("Path", ENV_USER, 10);
Returns:
0 if not successful
1 if
successful
Back to the top
DNSCache( [1|0] )
Sets the local DNS cache on (1) or off (0). If nothing
is specified it only returns the current state of the DNS cache.
Example:
Win32::AdminMisc::DNSCache(1);
0 local DNS cache is not active
1 local DNS cache is active
Back to the top
DNSCacheCount()
Returns the current number of cached elements. This can
not exceed the value of DNSCacheSize().
$Elements = Win32::AdminMisc::DNSCacheCount();
Returns:
Current number of cached elements
Back to the top
DNSCacheSize([$Size])
Sets the local DNS cache size to $Size elements (or name/ip associations). If nothing
is specified then it only returns the current size of the cache.
NOTE: If a number is
specified then the cache will be reset and every thing in it will be lost.
NOTE: The size could be
anything. Don't make it too large for memory and speed sake. The default size is
600.
Example:
$Size = Win32::AdminMisc::DNSCacheSize(1024);
Current size of the DNS cache
Back to the top
ExitWindows($Flag)
This will start the exit windows process.
$Flag can be one of the following:
- EWX_LOGOFF
- Log the user off. Applications will be told to
quite so you may be prompted to save files.
- EWX_POWEROFF
- Force the system to shutdown and power off. The
system must support poweroff. (NT: calling process
must have the SE_SHUTDOWN_NAME privilege)
- EWX_REBOOT
- Shut down the system and reboot the computer. (NT: calling process must have the SE_SHUTDOWN_NAME privilege)
- EWX_SHUTDOWN
- Shut down the system but don't reboot. (NT: calling process must have the SE_SHUTDOWN_NAME privilege)
The following flag can be logically OR'ed with
one of the above flags:
- EWX_FORCE
- Log the user off. Applications will be forced to
exit without saving. This is a hostile way to force a log off.
Example:
# Force the user to log off without saving any open files
Win32::AdminMisc::ExitWindows(EWX_LOGOFF | EWX_FORCE);
# Log off the user prompting for saving open files
Win32::AdminMisc::ExitWindows(EWX_LOGOFF);
# Shutdown the PC and reboot and do not ask to save open files
Win32::AdminMisc::ExitWindows(EWX_REBOOT | EWX_FORCE);
Returns:
0 if unsuccessful
non zero
value if successful
Back to the top
GetComputerName()
This will return the name of the computer. This performs
the same function as the GetNodeName() found in the Win32 module.
Example:
$Machine = Win32::AdminMisc::GetComputerName();
Returns:
undef if not successful
Computer's name if successful
Back to the top
GetDC()
This will return a domain controler of the domain $Domain. If $Domain is empty then use primary domain is assumed.
$Domain can be either an NT domain or an NT computer.
Example:
GetDC("ENGINEERING");
GetDC("\\\\Server1");
GetDC("//Server1");
undef if unsuccessful
name of a
DC for the sepecified domain if successful
Back to the top
GetDriveGeometry($Drive)
This will return an array consisting of drive
information in the following order:
Sectors per
Cluster
Bytes per Sector
Number
of free clusters
Total number of
clusters
If an UNC is used instead of $Drive then it must end with a backslash as in:
Example:
@Geometry = Win32::AdminMisc::GetDriveGeometry("c:\\");
$Free = $Geometry[0] * $Geometry[1] * $Geometry[2];
$Total = $Geometry[0] * $Geometry[1] * $Geometry[3];
print "Sectors per cluster: $Geometry[0]\n";
print "Bytes per Sector: $Geometry[1]\n";
print "Free clusters: $Geometry[2]\n";
print "Total clusters: $Geometry[3]\n";
print "Total Drive Size: $Total\n";
print "Total Free Space: $Free\n";
Returns:
nothing if unsuccessful
array
if successful
Back to the top
GetDrives([$Type])
This will return an array of drive roots. If no
parameters are passed then the list will be all drives (cdroms, floppy, fixed,
net, etc.).
If you specify $Type the list will only contain drive roots that
are of the specified type.
The types are:
DRIVE_FIXED
DRIVE_REMOVABLE
DRIVE_REMOTE
DRIVE_CDROM
DRIVE_RAMDISK
Example:
@Drives = Win32::AdminMisc::GetDrives();
@CDROMs = Win32::AdminMisc::GetDrives( DRIVE_CDROM );
Returns:
nothing if unsuccessful
array
if successful
Back to the top
GetDriveType($Drive)
This will return an integer relating to a drive type of
the root $Drive.
Drives need to be specified as a root such as "c:\" or "a:\" (notice the need to specify
the root directory).
The types are:
DRIVE_FIXED
DRIVE_REMOVABLE
DRIVE_REMOTE
DRIVE_CDROM
DRIVE_RAMDISK
If an error occurs a 0 will be returned and if the type
could not be determined (maybe a a disk is not in the drive) then a 1 will
return, otherwise the drive type will return.
Example:
if (GetDriveType("G:\\") == DRIVE_REMOTE){
print "G: is a network drive.\n";
}
Returns:
0 if
unsuccessful
1 if unable to determine
drive type if
successful
Back to the top
GetDriveSpace($Drive)
This will return an array consisting of the total drive
capacity and the available space on the drive.
Drives
need to be specified as a root such as "c:\" or "a:\" (notice the need to specify the root directory not just
the drive letter).
NOTE: The values returned
may not be accurate if you are running on a Windows 95 OSR 1 machine due to a
bug in the OS. This was fixed with OSR 2.
If an UNC is used instead of $Drive then it must end with a backslash as in:
Example:
($Total, $Free) = Win32::AdminMisc::GetDriveSpace("c:\\");
Returns:
nothing if unsuccessful
array
($Total, $Free) if successful
Back to the top
GetEnvVar( $Name | \%List [, $Type ] )
This will return the value of the environmental variable
$Name. If the first parameter is a hash reference (\%List)
then all of the specified type of environment variable names and their values will populate the hash.
An optional $Type can be specified
as can one of the following:
- ENV_SYSTEM
- Specifies that $Name will be a system environmental variable. (this is the
default if $Type is not
specified)
- ENV_USER
- Specifies that $Name will be a user environemental variable.
Example:
$SystemPath = Win32::AdminMisc::GetEnvVar("Path");
$UserPath = Win32::AdminMisc::GetEnvVar("Path", ENV_USER);
Returns:
undef if not successful
value
of the environmental variable if successful
Back to the top
GetFileInfo( $::ThisPage, \%Info )
This will return a 1 if there is information available
for the file $::ThisPage. If the
function is successful then the hash %Info will be populated with file information that is available on
that file. Information returned in the hash include copyright, company, original
filename, etc.
Example:
if (Win32::AdminMisc::GetFileInfo( "c:\\temp\\test.exe", \%Attribute)){
print "File has the following copyright: $Attribute{LegalCopyright}\n";
}
Returns:
0 if not successful
1 if
successful
Back to the top
GetGroups( [ $Machine | $Domain ],
$GroupType, ( $List | \@List | \%List ) [, $Prefix ] )
This will return, if successful, an array ( @List ) or a hash (%List) populated with the names of
user groups that are of the type $GroupType.
The $GroupType parameter can be
one of the following constants:
GROUP_TYPE_ALL |
All of the groups |
GROUP_TYPE_LOCAL |
Only local groups |
GROUP_TYPE_GLOBAL |
Only global groups |
Note: If a scalar 3rd parameter ($List) is
specified then it is converted and treated as a hash reference. This would be equivilent to
specifying a hash reference (\%List).
If the 3rd parameter is an array reference then upon success the user names populate the
array. If it is a hash reference then it is populated with the group name, comment,
type (local or global) and if the it is a global group then the groups flags.
If $Prefix exists then the list returned will only be group names that begin with $Prefix.
The first parameter can be either a machine name (such
as "\\\\server" or "//server"), a domain name (such as
"roth.net") or an empty string (''). This determines what machine will
perform the looking up of group names. If an empty string is specified then the
local machine will be used.
Example:
$Machine = "\\\\server";
if( Win32::AdminMisc::GetGroups( $Machine, GROUP_TYPE_GLOBAL, \@List ) )
{
print "The global groups are:\n";
map { print "\t$_\n";} @List;
}
Returns:
0 if not successful
1 if
successful
Back to the top
GetHostAddress($DNS_Name)
GetHostName($IP_Address)
gethostbyname($DNS_Name)
gethostbyaddr($IP_Address)
These four functions are the same but go by different
names for the sake of sanity. You can freely mix and match any of these.
Providing either an IP address or a DNS name it will return the opposite of what
you provided or return a 0 if it fails.
Example:
$Host = Win32::AdminMisc::GetHostName("172.19.239.191");
$IP = Win32::AdminMisc::GetHostName( "www.microsoft.com" );
As of version
Returns:
0 if failure
IP address or DNS
name if successful
Back to the top
GetIdInfo()
This will return an array with the following information
(in order):
- Process
ID (PID)
- The process ID (PID).
- Thread ID
(TID)
- The Thread ID (TID).
- Priority
Class for PID
- The priority of the process. Currently Broken.
- Thread
Priority
- The priority of the thread. Currently Broken.
- Command
Line
- The command line used to start the process.
Example:
@IDInfo = Win32::AdminMisc::GetIdInfo();
print "This script was run with the command line: $IDInfo[4]\n";
Returns:
Back to the top
GetLogonName()
This will return the name of the user this account is
logged on as. This is NOT necessarily the same as
the account the perl script is running under. An account can log on as another
user (known as "impersonating" another account).
Returns a name that the current account is logged in as.
This differs from the Win32::GetLogonName() function
because this will accurately reflect an impersonated user instead of the physically logged in account
name.
Example:
$name =
Win32::AdminMisc::GetLogonName();
Returns:
String if successful
undef if
failed
Back to the top
GetMachines( $Server, $MachineType, (
$List | \\@List | \\%List ) [, $Prefix ] );
This will return, if successful, an array ( @List ) or a hash (%List) populated with the names of
computers that are of the type specified by $MachineType. If $Prefix exists then the list returned will only be machines names that begin with $Prefix. If $Prefix is empty then all of the
machine names are returned.
The $GroupType parameter can be one of the following
constants:
UF_SERVER_TRUST_ACCOUNT |
Backup Domain Controllers in the specified
domain |
UF_INTERDOMAIN_TRUST_ACCOUNT |
Accounts between domains (trust accounts) |
UF_WORKSTATION_TRUST_ACCOUNT |
Workstation or Servers which are non domain
controlers |
Note: If a scalar 3rd parameter ($List) is
specified then it is converted and treated as a hash reference. This would be equivilent to
specifying a hash reference (\%List).
If the 3rd parameter is an array reference then upon success the machine names populate the
array. If it is a hash reference then it is populated with the machine id, name, comment, and flags.
Example:
if( Win32::AdminMisc::GetMachines( $Server, UF_WORKSTATION_TRUST_ACCOUNT, \@List, "" ) )
{
print "The list of all workstations accounts on $Server:\n";
map { print "\t$_\n";} @List;
}
Returns:
0 if not successful
1 if
successful
Back to the top
GetMemoryInfo()
This will return a hash of memory related information.
Returned values are:
- Load
- Current load on memory (in percentages)
- RAMTotal
- Total amount of physical RAM installed (in bytes)
- RAMAvail
- Total amount of RAM currently available (in bytes)
- PageTotal
- Total amount of paged ram (in bytes)
- PageAvail
- Total amount of paged ram currently available (in
bytes)
- VirtTotal
- Total amount of virtual memory (in bytes)
- VirtAvail
- Total amount of virtual memory currently available
(in bytes)
Example:
%Memory = Win32::AdminMisc::GetMemoryInfo();
print "Total Ram: $Memory{RAMTotal}\n";
Returns:
nothing if unsuccessful
hash if
successful
Back to the top
GetPDC( $Domain )
This will return the primary domain controler of the
domain $Domain. If $Domain is empty then use primary
domain is assumed.
$Domain can be either an NT domain or an NT computer.
Example:
GetPDC("ENGINEERING");
GetPDC("\\\\Server1");
GetPDC("//Server1");
undef if unsuccessful
name of
the PDC for the sepecified domain if successful
Back to the top
GetProcessorInfo()
This will return a hash of processor related
information.
Returned values are:
- OEMID
- OEM identifier
- NumOfProcessors
- Number of microprocessors installed
- ProcessorType
- Type of microprocessor
- ProcessorLevel
- Level of microprocessor (eg. 4=486, 5=Pentium [586],
6=Pentium Pro)
- ProcessorRevision
- Revision of microprocessor
- PageSize
- Paged memory size (how much memory is paged to disk
at one time)
Example:
%OS = Win32::AdminMisc::GetProcessorInfo();
print "There are $OS{NumOfProcessors} processor(s).\n";
Returns:
nothing if unsuccessful
hash if
successful
Back to the top
GetStdHandle( $Handle )
This will return the win32 handle to the standard handle
specified in $Handle.
This can be used to determine a handle when using CreateProcessAsUser().
Possible options for $Handle are:
STD_INPUT_HANDLE
STD_OUTPUT_HANDLE
STD_ERROR_HANDLE
Example:
$Handle = Win32::AdminMisc::GetStdHandle(STD_OUTPUT_HANDLE);
Returns:
undef if unsuccessful
Win32
handle if successful
Back to the top
GetTOD( $Server )
This will retrieve the time of day from the computer
$Server. If $Server is empty then the current
computer is used.
The return value is in the same
format that time() returns.
Example:
$Time = Win32::AdminMisc::GetTOD("\\\\MyServer");
print "The time is " . localtime(Win32::AdminMisc::GetTOD(''));
Returns:
value if successful
undef if not successful
Back to the top
GetUsers( $Server, $Prefix, ( $List | \\@List |
\\%List ) )
This will return, if successful, an array ( @List ) or a
hash (%List) populated with the names of user accounts.
If $Prefix exists then the list returned will only
be user accounts that begin with $Prefix. If
$Prefix is empty then all of the user accounts are returned.
Note: If a scalar 3rd parameter ($List) is
specified then it is converted and treated as a hash reference. This would be equivilent to
specifying a hash reference (\%List).
If the 3rd parameter is an array reference then upon success the user names populate the
array. If it is a hash reference then it is populated with the user id, full
name, comment, and account flags.
This function is similar to it's siblings GetMachines()
and GetGroups() however their syntaxes are different.
Example:
if( Win32::AdminMisc::GetUsers( "\\MyServer", "Test_", \@List ) )
{
print "The list of test user accounts are:\n";
map { print "\t$_\n";} @List;
}
Returns:
0 if not successful
1 if successful