Jump to content
Sign in to follow this  

Access server resources using machine permissions, not user permissions

Recommended Posts


I've hit a wall here and don't know how to get over it.

I need to access a server using WMI to retrieve Win32_Printer information to load printers based on location.  I have admin rights on the server and have no problem accessing the WMI service. My regular users cannot access WMI on the server due to not having permission.  I'm wondering if you can use the machine account to gain permission?

Is it possible to use the machine account, which is in Active Directory, to access the WMI service on the server?  I checked the security settings for the machine account and it has the same groups that I have all-be-it 2 containers below me in Active Directory.

Any help would be appreciated.  Below is the code that I am using for WMI access. I have tried the impersonationLevel and authentication entries and nothing seems to work.


Local $objWMIService, $wbemFlagReturnImmediately = 0x10, $wbemFlagForwardOnly = 0x20

$colItems = ""
$objWMIService = ObjGet("winmgmts:" & $strComputer & "rootCIMV2")
if IsObj($objWMIService) Then
     $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_Printer"), "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
   MsgBox(0,"", "WMI Service did not connect. Not an object " & @error)
   Exit ;stop the program since WMI doesn't have access




Share this post

Link to post
Share on other sites

create a domain admin account (it has admin rights to the pc and to the server), and call the script under that user context (e.g. by scheduled task).

Share this post

Link to post
Share on other sites

Sorry for the delayed response.  Sadly, I do not have access to create a domain admin account, I'm in the middle, so to speak. I can create users below me, but not above me.

I do know the PC has rights to the server with the proper credentials, but not sure how to tell the script to use the PC credentials rather than the user credentials.



Share this post

Link to post
Share on other sites

unless you enlighten me, i believe you are mistaken here. computer objects do not have access privileges to objects like network shares, because they never initiate communication to such resources - it's always the user account that is initiating the communication. this may be the computer local SYSTEM account, but this is still considered a user account.

(frankly, i can't imagine the logic that made MS put "users" and "computers" objects in the same AD group, as they have nothing in common).

can you provide a link to MSDN or such, that supports your claim?

if you have a user account (e.g. yours) that has admin rights on the server - be it a domain admin or not - then make this account also be admin over pc's, and problem solved.

if you can't do that, then how about running the script as local SYSTEM account on the client pc, but runas /netonly using the server admin account?

b.t.w what do you do with the retrieved information? it may be that you do not need admin rights on the pc, so your case becomes much easier.

please explain better your final intention - there may be a completely different and easier way to do what you need.

Share this post

Link to post
Share on other sites

Since the computers are defined in AD with specific rights I was hoping that maybe the computer itself could ask the server for the information using it's rights rather than the user's rights.  I am most likely misunderstanding the reason for those rights.

What we need to do is contact the server's Win32_Printer resource and request information about printers on the server then we filter those servers based on location. I have enough rights to access the resource, but a regular user does not have access to the resource. I currently have 25 printers just where I am and we have them seperated into 7 different locations to limit access within that location.  We don't need a user pulling a printer from the other end of the floor and trying to print to it so we limit what printers they get. Think of it as limiting your printers based on floor.

The RunAs /netonly might do the trick, I will have to look a bit more into it.

Hope this explains better.  Thanks.

Share this post

Link to post
Share on other sites

This may not be the most elegant solution, but...

You could periodically run an updater utility (script) under your credentials that would poll the server's printer resources, then write the data out to a file that can be stored in a location available to all domain users.  Then when the user logs in, they (the script you are writing now) would not have to access the server's resources, but the snapshot of just the resource information you deem necessary for them to have, and nothing more.  I would assume your printer resources are not changing so often that this would not work.  Worst case would be that you would not have the updated information after a printer resource change until the next time you run the updater.

It would be very dangerous if a user without access were able to bypass the rights limitations set by the domain admins by telling a script to say "hi, I am a domain member PC.  Let me have access."

Now for another solution to consider.  Unless your users are moving from location to location on a frequent basis (hourly, daily, weekly)  you might consider doing it similarly to the way we do at my office.

We have a domain group for each physical work area.  If a department or user relocates, we change the users' group membership to the new location accordingly.  The login script then maps their default printer based on group membership to the printer designated for that work area, and a secondary printer to one physically nearby, but not necessarily the closest (in cases where one printer already heavily used), so they have a backup if their primary has problems.

We do not necessarily stop users from accessing other printers.  Sometimes they like to print reports that they need for a meeting to a printer near the conference room where the meeting is being held, so that it will be done printing by the time they walk over there.  Considering they often need to go from one building to another, and often make last minute changes before meetings, they don't like to have to wait for the print job before they start walking.  They like having it ready and waiting for them when they get there.

Any way, there are two possible solutions for you.  I hope one of them is helpful to you.

Edited by willichan

Share this post

Link to post
Share on other sites

if i read you correctly, you want to install/remove printers based on pc location, at logon or on schedule.

if this is so, then several methods for this can be implemented.

first you must ask: how does the pc know where it is located?

pending this answer you formalize a solution. let us know, we can direct you further.

Share this post

Link to post
Share on other sites

How is AD set up regarding the location of the computers? If you have the computers in an OU that is specific to which printer you need to load on the computer, then you can create a Group Policy log in script for that OU, if you have access to GPMC that is.

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Share this post

Link to post
Share on other sites

Well I had a long reply here but accidently deleted it and don't want to retype the entire thing again.  I was answering a couple of the questions that was asked.  I'm going to try and post the code again, but each time I try to post the code window is blank even thought I put something in it.
Going to try again.  I found a solution.

Can't seem to add code to the message so I'm going to upload a text file with it.  I think our browser is to old.

The process requests all objects then filters them down to print queues only. The result is referred back to the calling function that puts the results into an array with name and location. The array is then sorted and filtered by location based on a workstation environment variable.
Thanks for all the advice and help.


Edited by Malkavian99

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Similar Content

    • FrancescoDiMuro
      By FrancescoDiMuro
      Good evening everyone
      I'm working on a little project of mines, and I was trying to use WMI Object.
      The question which I don't find an answer is: 
      Once I do the query with WMI Object, something like "SELECT * FROM Win32_LogonSession", instead of specify the field of the collection returned, ( i.e. $colItems.Caption ), can I loop though each property and each value of the property, writing so one row of code only?
      Hope my question was clear enough.
      Thanks in advance.

      Best Regards.
    • ahmet
      By ahmet
      I am trying to make a program that will uninstall some software, provided by some form of a list. I have this
      ; Generated by AutoIt Scriptomatic June 08, 2010 ;#RequireAdmin $sPartialName="java" $wbemFlagReturnImmediately = 0x10 $wbemFlagForwardOnly = 0x20 $colItems = "" $strComputer = "localhost" ;$objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\CIMV2") ;$objWMIService=ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & @ComputerName & "\root\cimv2") $objWMIService=ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & @ComputerName & "\root\cimv2") $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_Product", "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly) If IsObj($colItems) then For $objItem In $colItems If StringInStr($objItem.Name,$sPartialName)=1 Then ConsoleWrite("Full name:" & $objItem.Name & @CRLF) RunAs("USERNAME",@ComputerName,"PASSWORD",0,@ComSpec & " /c" & ' wmic product where name="Java 9.0.4 (64-bit)" call uninstall /nointeractive',"C:\WINDOWS\system32\wbem",@SW_MAXIMIZE) ;Run('wmic product where name="Java 9.0.4 (64-bit)" call uninstall /nointeractive',"",@SW_MAXIMIZE) ExitLoop EndIf Next Else Msgbox(0,"WMI Output","No WMI Objects Found for class: " & "Win32_Product" ) Endif The script above fails uninstalling software despite providing username and password for admin account. If I run script with admin rights then the software gets uninstalled.
      At the following link there is a script by JLogan3o13 but it does not either uninstall software, unless run as admin..
      Is there some way to uninstall software using wim or wimc by providing user name and password?
    • Bilgus
      By Bilgus
      #include <Array.Au3> ;WMI EXAMPLE Local $strComputer = "localhost" Local $sClass = "" Local $objClass Local $objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\cimv2") ; Display all available Classes in this object _ArrayDisplay(Get_Classes($objWMIService), "AVAILABLE WMI CLASSES", "", 0, Default, "NAME") ;Split string at \n(@LF) place each into an array $sClass = "Win32_BIOS" ;<-The Class I've choosen ;Lets Try out one of the classes Local $objClass = ObjGet("winmgmts:\\" & $strComputer & "\root\cimv2:" & $sClass) ConsoleWrite($sClass & @CRLF & "------------------------------------------" & @CRLF) _ArrayDisplay(Split_Properties(Get_Properties($objClass)), $sClass & " Properties", "", 0, Default, "NAME|VALUE") ;No methods available for this one but... ConsoleWrite("Methods:" & @CRLF & @CRLF) Get_Methods($objClass) ;Lets Do it again for the network adapter Class $sProperties = "" $sClass = "Win32_NetworkAdapterConfiguration" ;<-The Class I've choosen ;Lets Try out one of the classes $objClass = ObjGet("winmgmts:\\" & $strComputer & "\root\cimv2:" & $sClass) ConsoleWrite($sClass & @CRLF & "------------------------------------------" & @CRLF) _ArrayDisplay(Split_Properties(Get_Properties($objClass)), $sClass & " Properties", "", 0, Default, "NAME|VALUE") ConsoleWrite("Methods:" & @CRLF & @CRLF) Get_Methods($objClass) Func Get_Classes($obj) ; Display all available Classes in this object If IsObj($obj) Then Local $sClasses = "" For $objClass In $obj.SubclassesOf() ;<--WMI Method $sClasses &= ($objClass.Path_.Class) & @LF ;Build a string seperated by \n(@LF) Next EndIf Return StringSplit($sClasses, @LF) EndFunc ;==>Get_Classes Func Get_Methods($objClass) Local $sResults = "" If IsObj($objClass) Then For $objMethods In $objClass.Methods_ ConsoleWrite(@TAB & $objMethods.Name & @CRLF) $sResults &= $objMethods.Name & @LF Next EndIf Return $sResults EndFunc ;==>Get_Methods Func Get_Properties($objClass) Local $sProperties = "" If IsObj($objClass) Then For $objClassProp In $objClass.Properties_() ;<-Another WMI Method For $obj In $objWMIService.ExecQuery("Select * from " & $sClass) ;<-Another WMI Method $sProperties &= $objClassProp.Name & @CR $sProperties &= Parse_Value($obj.Properties_($objClassProp.Name).Value) ;Use the Properties_ Method to call our desired property Next Next EndIf Return $sProperties EndFunc ;==>Get_Properties Func Parse_Value($vValue) Local $sRet = "" Switch StringLower(VarGetType($vValue)) Case "keyword" ; Not really sure what this one is probably NULL $sRet = Number($vValue) = 0 ? "" : Number($vValue) Case "array" $sRet = _ArrayToString($vValue, ", ") Case "string", "bool", "int32", "int64", "double", "binary" $sRet = $vValue Case "pointer" $sRet = "[PTR]:" & $vValue Case Else $sRet = "[" & VarGetType($vValue) & "]: " & $vValue EndSwitch $sRet &= @LF Return $sRet EndFunc ;==>Parse_Value Func Split_Properties($sProperties) Local $aDisp = StringSplit($sProperties, @LF) ;Split string at \n(@LF) place each into an array Local $aTmp If IsArray($aDisp) Then _ArrayColInsert($aDisp, 1) For $i = 1 To $aDisp[0][0] ; String Split stores Count in the first element by default $aTmp = StringSplit($aDisp[$i][0], @CR) ;Split string at \r(@CR) place each into an array If IsArray($aTmp) Then $aDisp[$i][0] = $aTmp[0] > 0 ? $aTmp[1] : "?" ;Check if this element exists if not make it "?" $aDisp[$i][1] = $aTmp[0] > 1 ? $aTmp[2] : " " ;Check if this element exists if not make it " " EndIf Next EndIf Return $aDisp EndFunc ;==>Split_Properties  
    • DrLarch
      By DrLarch
      Curious if anyone knows if the permissions UDF can be used with certificates and if so, how.
      This is the code in the UDF for $_SE_OBJECT_TYPE which doesn't state anything about certs and not sure if it would fall under one of the object types listed:
      Global Enum _ ;$_SE_OBJECT_TYPE $SE_UNKNOWN_OBJECT_TYPE = 0, _ ;Unknown object type. $SE_FILE_OBJECT, _ ;Indicates a file or directory. Can be an absolute path, such as FileName.dat, C:\DirectoryName\FileName.dat, or a handle to an opened file $SE_SERVICE, _;Indicates a Windows service. A service object can be a local service, such as ServiceName, or a remote service, such as \\ComputerName\ServiceName, or a handle to a service $SE_PRINTER, _;Indicates a printer. A printer object can be a local printer, such as PrinterName, or a remote printer, such as \\ComputerName\PrinterName. $SE_REGISTRY_KEY, _;Indicates a registry key. The names can be in the format 'HKLM\SOFTWARE\Example', or 'HKEY_LOCAL_MACHINE\SOFTWARE\Example'. It can also be a handle to a registry key $SE_LMSHARE, _;Indicates a network share. A share object can be local, such as ShareName, or remote, such as \\ComputerName\ShareName. $SE_KERNEL_OBJECT, _;Indicates a local kernel object. All types of kernel objects are supported. ie, A process handle obtained with _Permissions_OpenProcess $SE_WINDOW_OBJECT, _;Indicates a window station or desktop object on the local computer. $SE_DS_OBJECT, _;Indicates a directory service object or a property set or property of a directory service object. e.g.CN=SomeObject,OU=ou2,OU=ou1,DC=DomainName,DC=CompanyName,DC=com,O=internet $SE_DS_OBJECT_ALL, _;Indicates a directory service object and all of its property sets and properties. $SE_PROVIDER_DEFINED_OBJECT, _;Indicates a provider-defined object. $SE_WMIGUID_OBJECT, _;Indicates a WMI object. $SE_REGISTRY_WOW64_32KEY;Indicates an object for a registry entry under WOW64. ;$_SE_OBJECT_TYPE What I'm trying to do is add another user to a cert in Certificates (Local  Computer) > Personal > Certificates as if using the "manage private keys" command via the MMC.
    • nikink
      By nikink
      Hi all,
      I have a bit of code that works on my old Win10 PC, that fails on my new Win10 PC, and I think the only significant difference is the version of Autoit - old PC has 3.3.12, new has 3.3.14.
      I couldn't find anything mentioned in the change logs though, so perhaps I'm wrong.
      Anyway, the code to replicate my issue is:
      Test('username', 'DOMAIN') ; THIS ERRORS: ;Test('localun', 'DOMAIN') ; THIS ERRORS: ;Test(' ', ' ') ; THIS ERRORS: ;Test('', '') ; THIS ERRORS: ;Test('localun', '') ; THIS ERRORS: ;Test('', 'DOMAIN') Func Test($un, $dom) $compName = 'PCNAME' $FullName = '.' $Description = '.' ; get the WIM object $objWMIService = ObjGet("winmgmts:\\" & $compName & "\root\cimv2") ; get default user full name and description $objAccount = $objWMIService.Get("Win32_UserAccount.Name='" & $un & "',Domain='" & $dom & "'") If IsObj($objAccount) Then $FullName = $objAccount.FullName $Description = $objAccount.Description EndIf ConsoleWrite($FullName & @CRLF) ConsoleWrite($Description & @CRLF) Return EndFunc  
      On my old PC this code will output just . and . for each of those line currently commented out. Which is fine.
      On my new PC any of those commented out lines of code cause an error, and the script won't even compile.
      $objAccount = $objWMIService.Get("Win32_UserAccount.Name='" & $un & "',Domain='" & $dom & "'") $objAccount = $objWMIService^ ERROR I'm very much a newb with the WMI stuff and objects, but it looks like the .Get property is failing when either $un or $dom aren't valid in v3.3.14, whereas in 3.3.12 the .Get would fail to return an object, which is then caught by the If statement.
      Am I on track with this? Is there some new/better way to code the example so that 3.3.14 will compile it?