My program, when started up with the system, is unable to access a networked location:
fn main() {
ensure_network("\\\\SERVER\\".to_string());
}
fn ensure_network(network_dir: String) {
let timer = std::time::Instant::now();
let mut prev_counter = 0;
loop {
if std::fs::read_dir(&network_dir).is_ok() {
break;
}
if timer.elapsed().as_secs() > prev_counter + 60 {
println!("Still Failing.");
prev_counter = timer.elapsed().as_secs();
}
std::hint::spin_loop();
}
println!("Network access obtained (Time elapsed: {})",
timer.elapsed().as_secs_f32());
}
Edit (Restating problem after much research into the issue):
This program starts up with the PC using Task Scheduler. It is set to "Run only when user is logged on" and to "Run with highest privileges." However, most of the time the program fails to find the connection and gives the error, "The user name or password is incorrect. (os error 1326)."
The program succeeds when run manually with administrator privilege.
On occasion the program will succeed on startup, but this is rare.
The program will succeed if any other application is started as administrator after the program enters its loop.
On Task Scheduler you can delay the execution of the task.
It's okay if you execute it after login, but when Active Directory or anyway a Domain system is between you and the login, the connection to the shared storage may take a while, and the program may try to execute before this happens. Try to put on a 10-20 seconds delay on it and see if this solve your problem.
If it doesn't work, again supposing that you have a domain in the middle, you may need to explicit give user and passwd to access the network where the directory you're looking for.
Related
I want to stop the user from running another instance of an already running program/service in Windows using PowerShell.
Eg: I have notepad opened, then for minute's time period I want to disable the option to open notepad, since it already is running.
As of now, I can detect if the program is open or not, and if not I may have it opened for user (code attached).
$processName = Get-Process notepad -ErrorAction SilentlyContinue
if ( $processName ) {
Write-Host 'Process is already running!'
#stop another instance of notepad to be opened, since it is already running
}
else {
$userChoice = Read-Host 'Process is not running, should I start it? (Y/N) '
if ($userChoice -eq 'Y') {
Start-Process notepad
}
else {
Write-Host 'No Problem!'
}
}
But, how can I disable the option for the user to open another instance of the same?
Any lead for the same would be helpful.
Since Windows doesn't have such a feature that prevents launching multiple copies of an executable, you have two options:
poll process list every now and then. Terminate extra instances of the application
create a wrapper to the application and use a mutex to prevent multiple copies
The first option has its caveats. If additional copies are launched, it takes on the average half the polling interval to detect those. What's more, which of the processes are to be terminated? The eldest? The youngest? Some other criteria?
The second one can be circumvented easily by just launching the application itself.
The only real solution is to implement a single-instance feature in the application itself. Games often do this. For business software, be wary that the users will hate you, if there is a single reason why running multiple instances would be of use. Yes, especially if that use case would be absurd.
As an example of a mutex-based launcher, consider the following function
function Test-Mutex {
$mtx = new-object System.Threading.Mutex($false, "SingleInstanceAppLauncher")
if(-not $mtx.WaitOne(0, $false)) {
write-host "Mutex already acquired, will not launch second instance!"
read-host "Any key"
return
}
write-host "Running instance #1"
read-host "Any key"
# Do stuff
}
As like the solution 2 caveat, any user can work around the limit by just executing the do suff part. Remember, the wrapper prevents launching multiple instances of the wrapper, not about the do stuff.
I've got two servers and a program that I want to run on them (not necessarily simultaneously).
Let's call one server "SA" and the other one "SB".
SB is a backup for SA, and I want that while my program is executing on SA, if SA fails then the program will immediately pick up where it left off and continue executing on SB.
What is the easiest way I can accomplish this?
There are probably a bunch of ways that this could be done, but I'd use an exclusive file lock to do it. To make that happen, you need enough network connectivity between the two servers that both could open a file for writing to.
Your basic algorithm (pseudocode) goes like this:
File f;
while (true) {
myTurn = false
try {
Open Network file for writing
myTurn = true;
} catch (IOException e) {
// not logging anything because this is expected.
// you might log that you tried maybe
myTurn = false;
}
if ( myTurn ) {
Do all of your actual work here.
loop many times if that's what you're doing.
don't exit this bit until your server wants to shut down
(or crashes).
But don't close the file
}
}
Basically what happens is that your app tries to open a file exclusively.
If it can't open it, then the other server is locked, so this server should stay quiet.
If it can open the file, then the other server is not running and this server should do the work.
For this to work, it's absolutely essential that the "work" routine, does not hang - as long as the other server's process is active, it will hang onto that network file lock. So if the other server goes into an infinite loop, you'll be out of luck.
And remember, both servers are trying to open the same network file. If they're trying to open a local file, it's not going to work.
This question has an example that you could probably re-use:
Getting notified when a file lock is released
I tried to execute the bellow perl script and locked the user session...
$n=15;
while($n>0)
{
print "$n,";
$n--;
sleep(1);
}
It worked as usual without any extra code..., There was no output when i locked the session, as i locked the session before the next second.
The output seen when I unlocked the session:
C:\Pradeep>perl test.pl
15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,
C:\Pradeep>
When i run the script bellow which I use to connect to a server using Win32::GuiTest functions like
SetForegroundWindow($_);
SendKeys("Password01");
etc...
it connected without any issues and the server login was successful.
But, when i lock my session in the middle of my execution and unlocked the session, the execution of script was completed, but the server login was not done.
use Win32::GuiTest qw(FindWindowLike GetWindowText SetForegroundWindow SendKeys);
system('"start %windir%\system32\mstsc.exe"');
$Win32::GuiTest::debug = 0;
$max_Sleep_time=3;
$Cur_Sleep_time=0;
do
{
sleep(1);
#windows = FindWindowLike(0, "Remote Desktop Connection");
$number_of_windows_opend = scalar(#windows);
$Cur_Sleep_time++;
}while ($number_of_windows_opend==0&&$Cur_Sleep_time!=$max_Sleep_time);
for (#windows) {
SetForegroundWindow($_);
SendKeys("server_name");
SendKeys("{ENTER}");
sleep(10);
#windows_seq = FindWindowLike(0, "Windows Security");
for (#windows_seq) {
SetForegroundWindow($_);
SendKeys("Password01");
SendKeys("{ENTER}");
}
#windows={};
exit;
}
According to me I used the active windows for doing my functionality. So it is not working.
is there any other way i can successfully do the above functionality if the user session is locked in the middle of the execution process. or do i have to make changes in my code?
Instead of using send keys use WMSetText(); function. It takes the window/control HWND and text as input and sets the text to the specified object.
Note: Using WMSetText(); you can just set the text, you can't send keys like {ENTER},{F1} etc...
You've already been told the answer several times:
http://perlmonks.org/?node_id=1073507
http://perlmonks.org/?node_id=1073302
http://perlmonks.org/?node_id=1073530
This is explained in the documentation of Win32::GuiTest. For obvious security reasons you can't send keys to applications when the screen is locked, you can't send keys to appications which aren't active.
I'm writing a Windows service that needs to know whether there are any users currently logged-on in the machine.
So far I've tried Win32_LogonSession (WMI), and LsaEnumerateLogonSessions/LsaGetLogonSessionData (secur32.dll).
Both work, and seem to return the same data, but they are too slow to update when a user log off:
When the system starts, they return "0 interactive users". (OK)
When I log on, they return "1 interactive user". (OK)
But then when I log off, the number of users is kept at 1. After a new log-on, the number is 2, and so on.
Thus Win32_LogonSession nor LsaEnumerateLogonSessions are good enough. The service needs to know within 5 minutes after the last interactive user leaves.
Not even SysInternals' LogonSessions.exe gives up-to-date answers.
Also, the answer cannot be "monitor logon and logoff events and have a counter variable", because the service can be started at any time.
I ended up with the following approach: count the number of interactive sessions which have at least one process running.
1) Get the logon session id for each interactive session.
LsaEnumerateLogonSessions (secur32.dll)
LsaGetLogonSessionData (secur32.dll)
sessionData.LogonType = SECURITY_LOGON_TYPE.Interactive or sessionData.LogonType = SECURITY_LOGON_TYPE.RemoteInteractive
sessionData.LoginID <- Keep this value in a LUID set.
LsaFreeReturnBuffer (secur32.dll)
2) Get the logon session id for each running process.
[First we need to enable the SeDebugPrivilege to the current application.]
GetCurrentProcess (kernel32.dll)
OpenProcessToken TOKEN_ADJUST_PRIVILEGES (advapi32.dll)
LookupPrivilegeValue SE_DEBUG_NAME (advapi32.dll)
AdjustTokenPrivileges (advapi32.dll)
CloseHandle (kernel32.dll)
[Then retrieve the data we want.]
EnumProcesses (psapi.dll)
OpenProcess PROCESS_QUERY_INFORMATION (kernel32.dll)
OpenProcessToken TOKEN_QUERY (advapi32.dll)
GetTokenInformation TOKEN_INFORMATION_CLASS.TokenStatistics (advapi32.dll)
accessTokenStatistics.AuthenticationId <- Keep this value in a LUID set.
CloseHandle (kernel32.dll)
3) Sets intersection cardinality
interactiveSessionsCount = | { sessionData.LoginID } ∩ { accessTokenStatistics.AuthenticationId } |
Obs: sessionData.LoginID and accessTokenStatistics.AuthenticationId are both of type LUID.
WTSEnumerateSessionsA + WTSQuerySessionInformationA work better with detecting active/interfactive sessions.
I need to merg two PDF files.
However sometimes a file might be locked up
I wrote this code, but I'm wondering if it's not the smartest solution:
private static int FILE_LOCKED_WAIT_PERIOD = 1000;
while (true)
{
// If the file is in use, IOException will be thrown.
// If file is not permitted to be opened because of Permission
// Restrictions, UnauthorizedAccessException will be thrown.
// For all other, Use normal Exception.
try
{
inputDocument1 = PdfReader.Open(fileToMerge, PdfDocumentOpenMode.Import);
break;
}
catch (IOException)
{
Thread.Sleep(FILE_LOCKED_WAIT_PERIOD);
}
catch (UnauthorizedAccessException)
{
Thread.Sleep(FILE_LOCKED_WAIT_PERIOD);
}
catch (Exception)
{
Thread.Sleep(FILE_LOCKED_WAIT_PERIOD);
}
}
You should add a timer so that you sleep for a few clicks before you try the file operation again.
Also you should have counter so you do not wait indefinitely and that you exit after say 15 tries.
Well this depends:
1) Is it a process that is all internal to a system independent of a user? If so you should try to find out what is locking the file and wait for the explicitly. Waiting randomly and then trying over and over again may cause problems on its own.
2) Is it a user that may have the file open? In this case waiting is not helpful since the system could retry all weekend because the user suddenly left for the day. You have no control over user timing. Just tell the user that you cannot do the requested operation because the file is open and have them try again.
Usually waiting for N seconds/minutes is not really a solution. Either you know what the problem may be and poll & resolve the issue or you can't really do anything and just send out notice.
There is no special function to do this. Actually even if this function exists, some process can still easily lock this file between your "lock check" and "file open"