Jump to content

RunAs Powershell Set Default Printer


Recommended Posts

I may have to give more details and screenshots, but just trying to get a feel for this problem I am having.

I am making a piece of software that runs in a lab run as the local admin via Autoit because we do not want to give all the users local admin access for the program to run.

 

I was able to do this using some stuff I found on the forums and it works great.

 

#include <Date.au3>
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
#include <WinAPIError.au3>
#include <WindowsConstants.au3>
#Include <Crypt.au3>

Global $sAdminUser = "Administrator"
Global $sDomain = @ComputerName
Global $iLogOnFlag = 0
Global $sParameters = ""
Global $sKey = "REDACTED"
Global $sInput = FileRead(@ScriptDir & "\seed.automation")
Global $sSeed = _Crypt_DecryptData($sInput, $sKey, $REDACTED)
Global $sAdminPassword = BinaryToSTring($sSeed)
Global $sSoftware = "C:\Program Files\Hinterland\PC-Titrate V3\PCTitrateV3.exe"


;Elevate with Admin account.
If @UserName <> $sAdminUser And Not IsAdmin() Then
   $sParameters = ""
   If Not @Compiled Then
      $sParameters = ' "' & @ScriptFullPath & '"'
   EndIf

   If RunAs($sAdminUser, $sDomain, $sAdminPassword, $iLogOnFlag, @AutoItExe & $sParameters) Then
   Exit

   Else
      Exit MsgBox(16 + 262144, "ERROR!", "Unable to run under administrator account.")
   EndIf
   EndIf

   ; Run with Admin Token in Windows Vista and Higher.
   If @UserName = $sAdminUser And Not IsAdmin() And Not StringRegExp(@OSVersion, "_(XP|200(0|3))") Then
   $sParameters = ""
   If Not @Compiled Then
   $sParameters = '"' & @ScriptFullPath & '"'
   EndIf

   If ShellExecute(@AutoITExe, $sParameters, "", "runas") Then
   Exit
   Else
   Exit MsgBox(16+262144, "ERROR!", "Unable to elevate to Admin due to UAC.")
   EndIf
   EndIf

   ; Script for MSI


; Under Vista the Windows API "SetLocalTime" may be rejected due to system security
ShellExecute($sSoftware)

 

Except one strange problem, the users can not print reports.  It crashes the program, and I found the reason why is that there is no default printer set.

Now since the program is running under the local admin context, that is where the default printer needs to be set.

 

Sure enough if I run powershell as another user inside windows manually and use some powershell to set the default printer, it works.  And it fixes the printing problem.

 

$wsObject = New-Object -COM WScript.Network
$wsObject.SetDefaultPrinter("Nitro PDF Creator (Pro 12)")

 

The strange thing is I can not for the life of me get this scripted.  I have tried RunAs() with 0, 1, 2 and 4 .  I tried different powershell scripts.

I feel like I need RunAs 0 for this to work right and I get an error

he system cannot find the file specified. (Exception from HRESULT: 0x80070002)
At C:\Automate\Set_Default_Printer.ps1:2 char:1
+ $wsObject.SetDefaultPrinter("Nitro PDF Creator (Pro 12)")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (:) [], FileNotFoundException
    + FullyQualifiedErrorId : System.IO.FileNotFoundException

This is referring to the printer not being found, even though if will clearly list it if I use something like get-printer

It will not give an error under runas context 1 or 2, but the printer is not set and it doesn't fix my issue.

 

The strange thing is if I run powershell as another user manually via the windows interface, run my script and have it work.  Then go back and try running my autoit code again it does work!

But the fix is already implemented.

 

I tried doing this run as admin, I tried using the same code I am using to run the application itself.  i am totally stuck with this one.

Link to comment
Share on other sites

Where in the process are you actually attempting to set the default printer?  Are you doing it in your elevation script right before the execution of $sSoftware, in PCTitrateV3.exe, or somewhere else?

Link to comment
Share on other sites

8 minutes ago, TheXman said:

Where in the process are you actually attempting to set the default printer?  Are you doing it in your elevation script right before the execution of $sSoftware, in PCTitrateV3.exe, or somewhere else?

I am not setting the default printer for the program, but for Windows but it needs to be see as the default printer for the local admin account, as the program is running as local admin.  Not for the current user.

 

So if I run powershell as local admin from right click run as in Windows and then execute a script to set the default printer it works (can be before, or after I run the program, just before we try to print) but when I try to use RunAs() in AutoIT it fails to work no matter what settings I try.

 

I have logged in as the local admin to set a default printer, that did not fix the issue, and even after I fix this issue for a user, it returns at next login.  So some system variable obviously does not carry thru based on how I am having to launch this program.  And that is that the local non admin user must launch a program as an administrator without admin rights. 

Link to comment
Share on other sites

I think I know why, but the answer is a long one having to do with the differences between runas() and ShellExecute with the 'runas' verb.

Can you try this:

  1. Duplicate your elevation script.
  2. Replace the line that runs $sSoftware with a line that runs your script that sets the default printer.  So basically the same script as before but it sets the default printer.  There will be no need for RunAs(), you can just use Run() or ShellExecute(), because you'll already be running under the Administrator context with elevation.

If it works that way, then my assumption as to why it is not working is true. If it works and you need an explanation of why, I can point you to some information that will explain it in detail.

FYI, you can also set the default printer using the Win32_printer WMI object.  If you did it that way, you wouldn't need to shell out to run your PS script.  I assume that you do it using PS because your more comfortable using PS than COM?

Edited by TheXman
Link to comment
Share on other sites

48 minutes ago, TheXman said:

I think I know why, but the answer is a long one having to do with the differences between runas() and ShellExecute with the 'runas' verb.

Can you try this:

  1. Duplicate your elevation script.
  2. Replace the line that runs $sSoftware with a line that runs your script that sets the default printer.  So basically the same script as before but it sets the default printer.  There will be no need for RunAs(), you can just use Run() or ShellExecute(), because you'll already be running under the Administrator context with elevation.

If it works that way, then my assumption as to why it is not working is true. If it works and you need an explanation of why, I can point you to some information that will explain it in detail.

FYI, you can also set the default printer using the Win32_printer WMI object.  If you did it that way, you wouldn't need to shell out to run your PS script.  I assume that you do it using PS because your more comfortable using PS than COM?

I already did try this actually, but I may need to try again and see if I can tweak it to work. (elevation script)

and I tried using the WMI object too :)

 

This gives the same error as otherwise.  So it is running, just failing.

 

#include <Date.au3>
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
#include <WinAPIError.au3>
#include <WindowsConstants.au3>
#Include <Crypt.au3>

Global $sAdminUser = "Administrator"
Global $sDomain = @ComputerName
Global $iLogOnFlag = 0
Global $sParameters = ""
Global $sKey = "REDACTED"
Global $sInput = FileRead(@ScriptDir & "\seed.automation")
Global $sSeed = _Crypt_DecryptData($sInput, $sKey, REDACTED)
Global $sAdminPassword = BinaryToSTring($sSeed)
Global $sSoftware = "powershell.exe -executionpolicy Bypass -File C:\Automate\Set_Default_Printer.ps1"


;Elevate with Admin account.
If @UserName <> $sAdminUser And Not IsAdmin() Then
   $sParameters = ""
   If Not @Compiled Then
      $sParameters = ' "' & @ScriptFullPath & '"'
   EndIf

   If RunAs($sAdminUser, $sDomain, $sAdminPassword, $iLogOnFlag, @AutoItExe & $sParameters) Then
   Exit

   Else
      Exit MsgBox(16 + 262144, "ERROR!", "Unable to run under administrator account.")
   EndIf
   EndIf

   ; Run with Admin Token in Windows Vista and Higher.
   If @UserName = $sAdminUser And Not IsAdmin() And Not StringRegExp(@OSVersion, "_(XP|200(0|3))") Then
   $sParameters = ""
   If Not @Compiled Then
   $sParameters = '"' & @ScriptFullPath & '"'
   EndIf

   If ShellExecute(@AutoITExe, $sParameters, "", "runas") Then
   Exit
   Else
   Exit MsgBox(16+262144, "ERROR!", "Unable to elevate to Admin due to UAC.")
   EndIf
   EndIf

   ; Script for MSI


; Under Vista the Windows API "SetLocalTime" may be rejected due to system security
Run($sSoftware)

Even going so far as to just shellexecute("powershell.exe") and then trying to run the commands or script manually does not work, gives the same error.

Edited by ViciousXUSMC
Link to comment
Share on other sites

I just want to make sure that we are on the same page.  If you are testing this on Windows 10, by default, the administrator account named Administrator is disabled.  If the account named Administrator is disabled, then your script, as currently written, will not work.  You can verify whether the status of the Administrator account executing the following command at a cmd prompt and look for the value of "Account active":

net user administrator

If the account named Administrator is not active, then you will need to use a valid admin account & password in your script or you'll need to make the account active.

 

Edited by TheXman
Link to comment
Share on other sites

The administrator account is Active, you can log into it as a user (and I did that as part of my testing)

Part of my validating as I go working on this is to type whoami in the PS or CMD windows to verify I am running as the local administrator under the computer domain.

 

We know it works because the shells are running, and the program is running.  If the account was not active/working those things would fail.

The process I am trying to get working... I would just assume it cant be done, except.... It works just fine if done like this.

 

Start Button -> Search Powershell -> Right Click Run As Different User -> Type in Local Admin Credentials -> Run any script or commands I want and they work.

 

But no matter how I try to do that via AutoIT it has not worked.

 

The RunAs() is working or Run() / ShellExecute() if used as part of the elevation script.

I can run powershell commands and such, but they cant seem to "find" the printer and set it, but again it works when just doing a normal "Run As" from Windows itself. 

Edited by ViciousXUSMC
Link to comment
Share on other sites

I see possible issues with the script in your original post.  Since discussions of how to get around UAC are off limits, I do not want to say anything directly related to that subject other than your script is not the same as the ones you may have found in your searches on this forum (at least not the ones that worked correctly). 

I have tested changing the default printer using the basic methodology you are trying to use and it works.  Meaning, if you find the issue(s) with your script, you should be golden.

Edited by TheXman
Link to comment
Share on other sites

4 minutes ago, TheXman said:

I see issues with the script in your original post.  Since discussions of how to get around UAC are off limits, I do not want to say anything directly related to that subject other than your script is not the same as the ones you may have found in your searches on this forum (at least not the ones that worked correctly). 

I have tested changing the default printer using the basic methodology you are trying to use and it works.  Meaning, if you find the issue(s) with your script, you should be golden.

I cant get this to work even before running my script.  A fresh log in and it still will not work.

Link to comment
Share on other sites

For those looking for your solution, I think you may have written it to the wrong topic. ;)

 

Link to comment
Share on other sites

Yes I had it working, we did more testing and it's still not working.

 

WHEN it is working the powershell will exit 0, running as RunAs 0.

When it is not working it will exit 2.

 

what it appeared was happening is RunAs 1, which always exits 0, if run first would then have the next run of RunAs 0 work.

I repeated it a couple of times I thought, but at the end of the day had a user I could not get it working.

I wonder if maybe one of my test users was a local admin and the other was not, and I am still stuck with this one.

 

It still works 100% of the time every time when done manually, but of course that requires me to type in the credentials for UAC and thus gives me administrative elevation when just RunAs() does not.  So I need to find a way to get this working in my elevation script I suppose. 

Link to comment
Share on other sites

Have you tried the set default printer function?

_PrintMgr_SetDefaultPrinter("Name of your Printer")


Func _PrintMgr_SetDefaultPrinter($sPrinterName)
    Local $iRet = 1
    Local $oWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
    If NOT IsObj($oWMIService) Then Return SetError(1, 0, 0)
    Local $oPrinters = $oWMIService.ExecQuery ("Select * from Win32_Printer where DeviceID = '" & $sPrinterName & "'")
    If NOT IsObj($oPrinters) Then Return SetError(1, 0, 0)
    For $oPrinter in $oPrinters
        $iRet = $oPrinter.SetDefaultPrinter()
    Next
    Return ($iRet = 0 ? 1 : SetError($iRet, 0, 0))
EndFunc ; ==> _PrintMgr_SetDefaultPrinter

 

Link to comment
Share on other sites

On 3/1/2021 at 8:52 AM, xcaliber13 said:

Have you tried the set default printer function?

_PrintMgr_SetDefaultPrinter("Name of your Printer")


Func _PrintMgr_SetDefaultPrinter($sPrinterName)
    Local $iRet = 1
    Local $oWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
    If NOT IsObj($oWMIService) Then Return SetError(1, 0, 0)
    Local $oPrinters = $oWMIService.ExecQuery ("Select * from Win32_Printer where DeviceID = '" & $sPrinterName & "'")
    If NOT IsObj($oPrinters) Then Return SetError(1, 0, 0)
    For $oPrinter in $oPrinters
        $iRet = $oPrinter.SetDefaultPrinter()
    Next
    Return ($iRet = 0 ? 1 : SetError($iRet, 0, 0))
EndFunc ; ==> _PrintMgr_SetDefaultPrinter

 

Not yet, but sure will :)

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...