Windows, Block a process from Printing - windows

Is their any way for a windows process to block another process from printing?
Basically we are trying to cut costs in the office and we want to block people from printing their emails. So I was asked if it was possible to write a program to block or cancel any print jobs comming from Outlook.
Can use a solution in any language or API, whatever works.
We have Win XP and Win 7 users.

There really isn't a good way to do this on Windows.
Besides, this doesn't seem like a technology problem.
Supply the printer with only one ream of paper per month. Let everyone know that the paper supply is limited.
The obvious work around is that users will bring in their own paper, but that will greatly reduce the operating cost, so it's not really a problem.

Are you using a network printer? If it is so, you can simply audit the printer's log (or the print server's) and "educate" your users accordingly, it will save you the hassle of writing such a program and deploy it on every pc (and make sure no user can override it).

Basically, this is the closest I could find for doing this. If basically waits for a print Job to show up with a particular job name and then cancel that job.
Technically though, I think the answer to my questing is no, since i asked if I could do this by process. Although the below comes close. It just prints out jobs that are happening and cancels any print job that says MS Outlook in its title. The dictionary thing just keeps it from listing the same jobs a bunch of times.
Imports System.Printing
Module Module1
Sub Main()
Using ps As New PrintServer("\\server")
Using Pq = ps.GetPrintQueue("printer")
Dim DetectedJobs As New Dictionary(Of DateTime, String)
Do
Dim Pj = Pq.GetPrintJobInfoCollection
For Each job In Pj
If Not (DetectedJobs.ContainsKey(job.TimeJobSubmitted) AndAlso DetectedJobs(job.TimeJobSubmitted) = job.Name) Then
DetectedJobs.Add(job.TimeJobSubmitted, job.Name)
Console.WriteLine(job.Name & "," & job.JobIdentifier & "," & job.TimeJobSubmitted)
End If
If job.Name.Contains("Microsoft Office Outlook") Then
job.Cancel()
Console.WriteLine(job.Name & "," & job.JobIdentifier & "," & job.TimeJobSubmitted & " - Cancelled")
End If
job.Dispose()
Next
Pj.Dispose()
Threading.Thread.Sleep("200")
Loop
End Using
End Using
Console.ReadKey()
End Sub
End Module

Related

How to route Matlab input to specific DOS cmd input?

I have a Matlab script that uses the dos command to open an exe. This exe pauses awaiting user input. For this project I need everything to be scripted and dynamic, so matlab has to be able to continue running its script, dynamically determine what to input to the running exe, and then input it.
So far, I have been able to get the exe to run in the background and let the matlab script continue by using dos('test.exe &'), but I cant get then get matlab to send inputs to the running exe. I have tried batch files and I still run into the same issue, which is how do I automate the sending of inputs to the cmd line when the cmd line exe running is paused awaiting user input?
My best guess would be that I need to reroute the standard output of matlab to the standard input of a specific, already open instance of cmd, but I have no idea how to do that and have been unable to find anything so far on the internet. Any insight would be greatly appreciated, thanks.
There is a way. It's just not elegant.
When you call a program with &, its window appears in the foreground and has focus (at least on my system). So you can send it keyboard events from Matlab using the java.awt.Robot class.
If you need to automatize the conversion from characters to key presses, you probably need a big switch statement along these lines. The following example defines the events manually, which is only practical for small inputs.
robot = java.awt.Robot;
dos('copy con &'); % open MS-DOS Window that will just echo the input text
pause(1) % allow some time for the external program to start up
robot.keyPress(java.awt.event.KeyEvent.VK_SHIFT);
robot.keyPress(java.awt.event.KeyEvent.VK_H);
robot.keyRelease(java.awt.event.KeyEvent.VK_H);
robot.keyRelease(java.awt.event.KeyEvent.VK_SHIFT);
robot.keyPress(java.awt.event.KeyEvent.VK_E);
robot.keyRelease(java.awt.event.KeyEvent.VK_E);
robot.keyPress(java.awt.event.KeyEvent.VK_L);
robot.keyRelease(java.awt.event.KeyEvent.VK_L);
robot.keyPress(java.awt.event.KeyEvent.VK_L);
robot.keyRelease(java.awt.event.KeyEvent.VK_L);
robot.keyPress(java.awt.event.KeyEvent.VK_O);
robot.keyRelease(java.awt.event.KeyEvent.VK_O);
robot.keyPress(java.awt.event.KeyEvent.VK_SHIFT);
robot.keyPress(java.awt.event.KeyEvent.VK_1);
robot.keyRelease(java.awt.event.KeyEvent.VK_1);
robot.keyRelease(java.awt.event.KeyEvent.VK_SHIFT);
robot.keyPress(java.awt.event.KeyEvent.VK_ENTER);
robot.keyRelease(java.awt.event.KeyEvent.VK_ENTER);
Here's an example run:
Unfortunately there is no way to do what you are describing.
The fact that the external program pauses and awaits for an input is a serious challenge: for Matlab, there is just a program running in the background, and it has no way to "know" that this program is awaiting for an input at a given moment.
Then, another issue is that there is no "Matlabish" way to send a command to a running thread send in the background. edit The solution proposed by Luis is ugly but works for this.
If you can modify the external program, then you can certainly avoid the problem by defining a different protocol for input tranfer, like TCP/IP. But it's not a general answer and I guess you don't have such a possibility.
You could try to use Sikuli for this, if you are really desperate.
Thanks to the wonderful explanation by Luis Mendo, I have quickly put together a function that takes a string input and outputs the proper robot commands. It works for me!
function typeStringOut(robot,text)
keyMatch = {};
keyMatch(1,:) = {'`','-','=',',','.','/',';','[',']','\'};
keyMatch(2,:) = {'~','_','+','<','>','?',':','{','}','|'};
keyMatch(3,:) = {'BACK_QUOTE','MINUS','EQUALS','COMMA','PERIOD','SLASH','SEMICOLON','OPEN_BRACKET','CLOSE_BRACKET','BACK_SLASH'};
numKeyMatch = {};
numKeyMatch(1,:) = {'1','2','3','4','5','6','7','8','9','0'};
numKeyMatch(2,:) = {'!','#','#','$','%','^','&','*','(',')'};
for i=1:length(text)
if isstrprop(text(i),'alpha')
if isstrprop(text(i),'upper')
robot.keyPress(java.awt.event.KeyEvent.VK_SHIFT);
end
eval(['robot.keyPress(java.awt.event.KeyEvent.VK_',upper(text(i)),');']);
if isstrprop(text(i),'upper')
robot.keyRelease(java.awt.event.KeyEvent.VK_SHIFT);
end
elseif isstrprop(text(i),'digit')
eval(['robot.keyPress(java.awt.event.KeyEvent.VK_',text(i),');']);
elseif isstrprop(text(i),'wspace')&&strcmp(text(i),' ')
eval('robot.keyPress(java.awt.event.KeyEvent.VK_SPACE);');
elseif isstrprop(text(i),'punct')||isstrprop(text(i),'graphic')
switch text(i)
case {'`','-','=',',','.','/',';','[',']','\'}
matchIdx = strcmp(keyMatch(1,:),text(i));
eval(['robot.keyPress(java.awt.event.KeyEvent.VK_',keyMatch{3,matchIdx},');']);
case {'~','_','+','<','>','?',':','{','}','|'}
robot.keyPress(java.awt.event.KeyEvent.VK_SHIFT);
matchIdx = strcmp(keyMatch(2,:),text(i));
eval(['robot.keyPress(java.awt.event.KeyEvent.VK_',keyMatch{3,matchIdx},');']);
robot.keyRelease(java.awt.event.KeyEvent.VK_SHIFT);
case {'!','#','#','$','%','^','&','*','(',')'}
robot.keyPress(java.awt.event.KeyEvent.VK_SHIFT);
matchIdx = strcmp(numKeyMatch(2,:),text(i));
eval(['robot.keyPress(java.awt.event.KeyEvent.VK_',numKeyMatch{3,matchIdx},');']);
robot.keyRelease(java.awt.event.KeyEvent.VK_SHIFT);
otherwise
error([text(i),' is unknown character']);
end
elseif strcmp(text(i),'<')||strcmp(text(i),'>')
robot.keyPress(java.awt.event.KeyEvent.VK_SHIFT);
matchIdx = strcmp(keyMatch(2,:),text(i));
eval(['robot.keyPress(java.awt.event.KeyEvent.VK_',keyMatch{1,matchIdx},');']);
robot.keyRelease(java.awt.event.KeyEvent.VK_SHIFT);
else
error([text(i),' is unknown character']);
end
end
robot.keyPress(java.awt.event.KeyEvent.VK_ENTER);
robot.keyRelease(java.awt.event.KeyEvent.VK_ENTER);
end

automatically logging in to SAP as part of a VBscript

I am working in SAP (PR2) and I have a large report that usually takes a long time (2 or more hours) to run. I have to take the output of this report and drop it into Excel to be manipulated and cleansed before bringing it into Access.
The ideal result would be a script that could launch automatically around 4am, login in to SAP, run the report, and have the results waiting for me when I come in. In short, I am missing parts 1 and 2, the automatic launch and automatic login to SAP.
I have pulled together a script that will start the report and then output the results as I want. The downside of this is that I don't get the results until about noon-ish each day, and that interrupts the workflow of those whom I support.
I have tried to run the necessary report in the background as suggested in other questions, but due to the size of the report and my limited access inside of SAP, it comes out in a way that is completely useless to me.
Thanks in advance for your help. Also, thanks for the help ya'll have given on prior questions :)
PS:As a bonus, if anyone knows how to encrypt a VBscript, that would be helpful as well.
Use the windows task scheduler to set a run daily at time task.
VBS cannot be encrypted but can be encoded. This will only stop the casual person fiddling with the code, decoding scripts are available online for anyone who really wants to get your code.
'ENCODE VBS TO VBE
Set oFilesToEncode = WScript.Arguments
Set oEncoder = CreateObject("Scripting.Encoder")
For i = 0 To oFilesToEncode.Count - 1
file = oFilesToEncode(i)
Set oFile = fso.GetFile(file)
Set oStream = oFile.OpenAsTextStream(1)
sSourceFile = oStream.ReadAll
oStream.Close
sDest = Encoder.EncodeScriptFile(".vbs",sSourceFile,0,"")
sFileOut = Left(file, Len(file) - 3) & "vbe"
Set oEncFile = fso.CreateTextFile(sFileOut)
oEncFile.Write sDest
oEncFile.Close
Next
WScript.quit
I use a software 'exescript' to convert to exe. Seems to work OK for me...

Share Excel.Application executable among multiple WSF processes?

I have a system that launches 50 or so VBS scripts via WSF, that need to stay there until another part of the system connects to them, then they act as servers for a bit until the peer disconnects, then they exit and get restarted.
For initialization purposes, they all use an EXCEL.EXE to read a large number of parameters from a spreadsheet, via
Set objExcel = CreateObject("Excel.Application")
We can't afford to have 50 EXCEL.EXEs running at once, so the restarts are sequentialized, so that there should never be more than one EXCEL.EXE running: usually zero, as they are only used for 15-20 seconds and then released.
However sometimes things go wrong, the WSF scripts exit, and the EXCEL.EXE that it starts stays there. So we do see up to a dozen EXCEL.EXE processes.
My question is about using GetObject() instead of CreateObject(). Would it be possible to use GetObject() so that if there already was an EXCEL.EXE running, it would use that one instead of starting a new one? And if so what other steps are necessary?
There is also a supplementary question here about why the EXCEL.EXEs persist after the VBS that started them has exited, but I can imagine ways in which the VBS could exit (or be killed) that would allow that.
Note that the question is also partly about the re-entrancy of EXCEL.EXE, which I have no information about.
I'm not the author of these scripts, and I'm not very strong in VBS as far as external objects go, so it is is entirely possible that I'm asking a trivial question here.
Usage of GetObject() is documented in this old KB article. Error handling is required to get the first instance created. Like this:
Dim excel
On Error Resume Next
Set excel = GetObject(, "Excel.Application")
If Err.number = 429 Then
Set excel = CreateObject("Excel.Application")
End If
If Err.number <> 0 Then
WScript.Echo "Could not start Excel: " & err.Description
End
End If
'' etc
However, seeing zombie Excel.exe processes surviving is a broad concern, it strongly suggests that the scripting runtime is not exiting normally. Perhaps error handling in your existing scripts is less than ideal, that's not likely to get better when you slam a single instance with multiple scripts. Excel does get pretty cranky when it cannot keep up. Using the OpenXML api or Excel Services are the better way to go about it.

HTA - VBScript - Install program but wait for installation to complete

If you could give my a hand that would be great?
I have a HTA file nothing to fancy its to install a few programs one by one
I have been reading in a few places on how to wait for installation to complete
then install the next program but none make sense to me for what i want, also
they are saying to use wscript.sleep that would be great but it doesnt work in a HTA right ?
I have firefox, utorrent, symantec antivirus, adobe reader, office 2003 (packaged with KEY already)
and a few others.
i want to find switches to install silently but thats not important if this code someone is willing to show me works...
I hope I make sense ?
If you can help me it would be great ?
Cheers Pavle.
You might find something useful in my answer (https://stackoverflow.com/a/3742182/128427) to this question: How to get an HTA to restart itself?
It uses a VBScript helper to wait for a process to end (the HTA itself) then restarts the HTA. You could modify the vbscript instead to wait for a specific process to end (one of your installers), then return control to the HTA which starts the next installer and calls the wait script again.
I don't think an HTA can call the WScript.Sleep routine, but there are the setTimeout and setInterval methods in HTA that call a routine after X seconds, or repeatedly call a routine after every X seconds until cancelled. You can use these to check periodically if a process is still running (using WMI Win32_Process as I show in my other answer).
To process a list of items like this, instead of using a loop to go through a list and pause after each item, you have a central state-machine routine that calls itself every so often to advance the system.
'!! extremely "pseudo" pseudo-code follows
sub StartSystem()
state = "next program"
list = list of programs to install
AdvanceSystem()
end sub
sub AdvanceSystem()
if state = "next program"
if more items in list
start next installer
remove from list (or increment an index)
set state to "check program"
else
set state to "done"
if state = "check program"
use WMI to see if process is still running
if no
state = "next program"
if state <> "done"
setInterval(AdvanceSystem, 5000) ' call again in 5 seconds
end sub
' then somewhere in your HTA interface have a button to start things off
buttonClick = StartSystem()
Using an arrangement like this you may not even need to run a separate VBScript to check the process and sleep. Also, with this kind of incremental process, you can send output to a DIV somewhere so the user can see progress, whereas when processing things in a loop, output doesn't show up until the whole process has finished. After each pass through AdvanceSystem, the control returns to the HTA level and the system can update itself.
Let me know if you need a more specific example, I'll try to write something up.

Applescript and iCal interaction

I'm trying to write an AppleScript to query iCal and find all the events I've got for a given date, in any calendar.
I started by writing a simple script that does something simple with every event in a given calendar:
tell application "iCal"
tell calendar "Reuniones"
set the_events to every event
repeat with an_event in the_events
-- do something with every event
set value to summary of an_event
end repeat
end tell
end tell
However, this simple script is taken a lot of time to execute (a few seconds), even if I'm not doing anything complex inside the loop. I'm afraid that the real script will really take a lot of time to execute.
I'm not very familiar with Applescript, and thus I imagine I'm doing something silly that has severe performance implications.
Can anybody explain me why this takes that much to execute? Can anybody suggest something to improve my code? I'm now going to start checking the date of the event, with a condition in the loop. I suspect there must be a way to search for events with a date (like the Automator action does), but I haven't been able to find a "native" way to do so ....
EDIT: I'm using Mac OS X Tiger (10.4). It is possible that newer versions of iCal have improved the library of operations available.
I've been grappling with this today and found that you can filter by date (at least on Snow Leopard). So
tell application "iCal"
set out to ""
set todaysDate to current date
set time of todaysDate to 0
repeat with c in (every calendar)
set theEvents to (every event of c whose start date ≥ todaysDate)
repeat with current_event in theEvents
set out to out & summary of current_event & "\n"
end repeat
end repeat
return out
end tell
will return the summary of all future events, and very quickly, compared to iterating through all events.
It isn't AppleScript, but the best of the bunch of other ways to do this seems to be iCalBuddy, which uses the public Cocoa APIs rather than parsing the calendar file directly and handles repeating events sensibly.
icalBuddy -nc -eed -iep title,datetime eventsToday+1
My initial intent was to select only the events for a given date, but apparently there aren't methods in iCal to access only the events for a specific day.
Thus, it is always necessary to go over all the events registered in every calendar. Even when interested in the events of a single calendar, say 'Today's Meetings", it is necessary to go through the entire set of events.
The best alternatives I've found around in the web don't use Apple Script, but instead they process the 'ics' files where the info is actually stored.
For reference, those files are located in '~/Library/ApplicationSupport/iCal'.

Resources