Sending Fax via ColdFusion & VBScript Windows Server 2008 - coldfusion

This is related to a previous thread I started, but it deals with a method that actually works.
I have created a VBScript that ColdFusion executes and sends a fax to a specific number. The following is the VBScript I wrote, taken from a Microsoft TechNet Site:
Set objFaxDocument = WScript.CreateObject("FAXCOMEX.FaxDocument")
Set objFaxServer = WScript.CreateObject("FAXCOMEX.FaxServer")
Dim JobID
objFaxServer.Connect("")
objFaxDocument.Body = "C:\*PATHNAME*\testfax.pdf"
objFaxDocument.DocumentName = "My First Fax"
objFaxDocument.Priority = "2"
objFaxDocument.Recipients.Add("8885551212")
objFaxDocument.AttachFaxToReceipt = True
objFaxDocument.CoverPageType = "1"
objFaxDocument.CoverPage = "generic"
objFaxDocument.Note = "Here is the info you requested"
objFaxDocument.ReceiptAddress = "test#test.com"
objFaxDocument.Subject = "Today's fax"
objFaxDocument.Sender.Title = "Mr."
objFaxDocument.Sender.Name = "Test Man"
objFaxDocument.Sender.City = "Test City"
objFaxDocument.Sender.State = "FL"
objFaxDocument.Sender.Company = "Test Company"
objFaxDocument.Sender.Country = "USA"
objFaxDocument.Sender.Email = "test#test.com"
JobID = objFaxDocument.ConnectedSubmit(objFaxServer)
MsgBox("The Job ID is :" & JobID(0))
objFaxServer.Disconnect()
The following is the ColdFusion code I use to execute this vbscript:
<cfexecute name="C:\Windows\System32\cscript.exe"
arguments="C:\*SCRIPTPATH*\test.vbs">
</cfexecute>
On a machine that has Windows Server 2003, this successfully sent the document to the Windows Fax Service application, and stored the fax correctly in the outbox. However, when I attempted this on Windows Server 2008, it does not work. It should be noted that while the same version of ColdFusion (8) is being used, the 2008 machine is 64-bit while the 2003 is 32-bit.
This may have been answered elsewhere (if so please guide me) but I have had the hardest time with this and there are not many successful solutions out there for me to find. I know I'm missing something but I don't know what. Can anybody help?

This is difficult to answer that precisely because you don't quantify "does not work". In what way does it not work? Is there an error on the screen? Is there an error in the log files anywhere? Does the VBS get called, but does it then fail (it could be a vagary of how it's being called)?
That said, I suspect it's a case that the service account that CF is running under doesn't have permissions to access or execute the VBS, or some other resource the VBS uses.
If you login as the user CF uses, can you execute that statement from a command line?

Related

How to use the WinRM C++ API in a simple example

why is my code failing to run a simple executable using WinRM's C++ API?
//main.cpp
int main()
{
ShellClient *shellClient = new ShellClient();
//Set up the shell client here and connect to the localhost.
//This seems to be working fine because I'm handling every
//possible error code, and none of them are being triggered
PCWSTR commandLine = L"\"MyExampleExecutable.exe\"";
isOk = shellClient->RunCommand(commandLine);
if (!isOk)
return 1;
return 0;
}
//ShellClient.cpp
bool ShellClient::RunCommand(PCWSTR command)
{
WSMAN_SHELL_ASYNC createCommandAsync;
ZeroMemory(&createCommandAsync, sizeof(createCommandAsync));
createCommandAsync.operationContext = this;
createCommandAsync.completionFunction = (WSMAN_SHELL_COMPLETION_FUNCTION)CommandCreatedCallback;
WSManRunShellCommand(shellHandle, 0, command, NULL, NULL, &createCommandAsync, &commandHandle);
if (commandHandle == NULL)//It is *always* NULL
{
std::cout << "command handle null" << std::endl;
system("pause");
return false;
}
return true;
}
One possible clue is that my C++ code thinks the shell gets created fine, but in the Event Viewer for my machine, there is this:
WSMan operation CreateShell failed, error code 2150859250
At the time of writing, this lovely error code gives precisely zero results when put into Google, making it rather difficult to know what it means.
Background and common solutions which I have already checked
As documented here and explaned in this video by the same author, most WinRM issues boil down to either connection or authentication problems. In my case, if I deliberately enter incorrect user credentials, I get an authentication error, so I know that my program is connecting and authenticating fine when the correct username and password are supplied. Also:
From the command line, I can connect to my local machine and pretend it's a remote server, for example the following command works fine:
winrs -r:http://localhost:5985 -u:COMPUTERNAME\Jeremy "dir"
winrm quickconfig shows the service is working (which we already know otherwise the winrs command wouldn't work)
winrm get winrm/config shows TrustedHosts = localhost, AllowUnencrypted = true, and all authentication methods are set to true
Following this advice, I have set the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\LocalAccountTokenFilterPolicy = 1
Working in Windows 10
Thank you in advance!
I wasn't aware of this so can't comment on whether it's common knowledge but Microsoft have a nifty error lookup tool where you can enter an error code (after converting it from a normal number to hexadecimal) and it tells you what it means.
In this case, 2150859250 (803381F2 in hex) corresponds to:
ERROR_WINRS_IDLETIMEOUT_OUTOFBOUNDS wsmerror.h
# The WS-Management service cannot process the request. The
# requested IdleTimeout is outside the allowed range.
When setting up the WinRM shell, I was doing the following:
WSMAN_SHELL_STARTUP_INFO startupInfo;
ZeroMemory(&startupInfo, sizeof(startupInfo));
startupInfo.idleTimeoutMs = 1000;//not large enough!
startupInfo.workingDirectory = L"C:\\";
//other parameters of startupInfo set here
WSManCreateShell(session, 0, shellUri, &startupInfo, NULL, NULL, &createShellAsync, &shellHandle);
Changing idleTimeoutMs from 1000 to a much larger number like 100000 solved the error and my program now works fine.
Since the official docs for this parameter say anything between 0 and 0xFFFFFFFF are valid, it remains a mystery why a value of 1000 is throwing this error. I leave this for somebody more knowledgable than myself to answer, on the off chance that they come across this question.

Python Selenium: XPath changes the encoding of my variables

I has this code that searches through text by XPath. The problem is that the searched text may contain Latin characters like ñor í.
I encoded it and when I print it, it shows perfectly, but when I use the XPath the encoding changes, and obviously it can't be found.
The decoded var prints well:
nombre_act = "HOTEL DIEGO DE ALMAGRO SAN PEDRO DE ATACAMA"
nombre_act = nombre_act.decode("utf8")
nombre_contrato = "Campaña Cyber Day, Desayuno Incluído"
nombre_contrato = nombre_contrato.decode("utf8")
print nombre_contrato
xpath = "//select[#name='"+nombre_act+"']/option[text()='"+nombre_contrato+"']"
print xpath
hotel_sel = driver.find_element_by_xpath(xpath).click()
Your code trials were near perfect. However I feel you don't need to change through encoding/decoding unless you want to print the characters to the console as follows:
nombre_act_actual = "HOTEL DIEGO DE ALMAGRO SAN PEDRO DE ATACAMA"
#nombre_act = nombre_act_actual.encode("utf-8")
nombre_contrato_actual = "Campaña Cyber Day, Desayuno Incluído"
nombre_contrato = nombre_contrato_actual.encode("utf-8") #required as you need to print to the console
print nombre_contrato
xpath = "//select[#name='"+nombre_act_actual+"']/option[text()='"+nombre_contrato_actual+"']"
hotel_sel = driver.find_element_by_xpath(xpath).click()
However, your another issue is the incompatibility between the version of the binaries you are using as follows:
You are using chromedriver=2.41
Release Notes of chromedriver=2.41 clearly mentions the following :
Supports Chrome v67-69
You are using chrome=70.0
Release Notes of ChromeDriver v2.44 clearly mentions the following :
Supports Chrome v69-71
So there is a clear mismatch between ChromeDriver v2.41 and the Chrome Browser v70.0
Solution
Upgrade ChromeDriver to current ChromeDriver v2.44 level.
Keep Chrome version between Chrome v69-71 levels. (as per ChromeDriver v2.44 release notes)
Clean your Project Workspace through your IDE and Rebuild your project with required dependencies only.
If your base Web Client version is too old, then uninstall it through Revo Uninstaller and install a recent GA and released version of Web Client.
Execute your #Test.

How to enumerate the installed StoreApps and their ID in Windows 8 and 10

What I want to get is the AppUserModelId of all installed StoreApp applications, so that I can pass it to IApplicationActivationManager->ActivateApplication.
In Windows 8 it was stored in the Registry, but in Windows 10 it is not anymore.
There are a lot of questions about this in internet but even after days of searching I could not find a satisfying solution.
What I have so far is the following:
I create an instance of IPackageManager,
I call FindPackagesByUserSecurityId() with the SID of the current user,
I iterate through the returned collection
I get an IPackage interface
From that I get an IPackageId interface,
Then I call IPackageId->get_FamilyName()
With that I have for example on Windows 10 for the Windows Calculator the string "Microsoft.WindowsCalculator_8wekyb3d8bbwe".
When I append to this string an "!App" I have the complete AppUserModelId to start the Windows Calculator: "Microsoft.WindowsCalculator_8wekyb3d8bbwe!App"
But not all applications use an "!App" behind the FamilyName.
For example Spartan uses the AppUserModelId
"Microsoft.Windows.Spartan_cw5n1h2txyewy!Microsoft.Spartan.Spartan" which does not end with "!App". And when I replace "!Microsoft.Spartan.Spartan" with "!App" it will not start -> "This app does not support the contract specified".
So my question is where do I get the last missing part from?
I found a PowerShell code in internet (http://poshcode.org/5702) that seems to do something very similar:
Get-AppXPackage $PackageName -pv Package |
Get-AppxPackageManifest | % {
foreach($Application in $_.Package.Applications.Application) {
if($Application.Id -like $AppId) {
if($Protocol -and !($Application.Extensions.Extension.Protocol.Name | ? { ($_ + "://") -match (($Protocol -replace '\*','.*') + "(://)?") })) {
continue
}
[PSCustomObject]#{
# Notice the secret magic property:
PSTypeName = "Microsoft.Windows.Appx.Application"
AppUserModelId = $Package.PackageFamilyName + "!" + $Application.Id
}
}
}
}
I really don't understand this cryptic PowerShell stuff, but one line seems interesting to me:
foreach($Application in $_.Package.Applications.Application)
This seems to enumerate Applications in a Package.
A comment in the same PowerShell code says:
# The full AppUserModelId is composed of the package name,
the publisher id, and the app id, such as
Microsoft.ZuneMusic_8wekyb3d8bbwe!Microsoft.ZuneMusic
so what is missing is the $Application.Id.
If I could get an IAppInfo interface anyhow I could call IAppInfo->get_Id() and I would be ready.
But I don't know how to get this from an IPackage in C++.
Incredible that nobody has an idea!
This shows how Microsoft makes us life hard.
Such a universal task like enumerating the installed StoreApps with their AppUserModelId requires a cientific research department.
I finally came to a solution that works perfectly on Windows 8 and Windows 10. But a lot of code is required.
It seems that Windows does not hold the Application ID's in memory and there is no API to determine them directly. I studied all header files in the Windows 10 SDK and could not find a corresponding interface useful for that task.
But I found out how to get them. I continue after the 6 steps in my question:
call IPackage->get_InstalledLocation() which returns an IStorageFolder.
QueryInterface for IStorageItem
call IStorageItem->get_Path()
Now you have the path were the App is installed. Windows 10 uses two base folders:
C:\Program Files\WindowsApps
C:\Windows\SystemApps
and several others like
C:\Windows\vpnplugins
C:\Windows\devicesflow
C:\Windows\MicracastView
C:\Windows\PrintDialog
C:\Windows\PrintDialog3D
C:\Windows\WinStore
In the returned folder path you will find a file "AppxManifest.xml".
This file looks like:
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns=".....">
......
......
<Applications>
<Application Id="microsoft.windowslive.mail" Executable="HxMail.exe" EntryPoint="Executable">
......
......
</Application>
<Application Id="microsoft.windowslive.calendar" Executable="HxCalendarAppImm.exe" EntryPoint="Executable">
......
......
</Application>
</Applications>
</Package>
And voilà, there they are. This package has two application ID's: "microsoft.windowslive.mail" and "microsoft.windowslive.calendar".
Then you take the package's FamilyName from step 6 append an "!" and append this ID and you are done.
This package can be started with IApplicationActivationManager->ActivateApplication() using one of the AppUserModelId's:
"microsoft.windowscommunicationsapps_8wekyb3d8bbwe!microsoft.windowslive.calendar"
"microsoft.windowscommunicationsapps_8wekyb3d8bbwe!microsoft.windowslive.mail"
Use PackageManager APIs to enumerate packages and GetPackageApplicationIds to enumerate applications in a package e.g. pseudo-code
FOREACH p IN PackageManager.FindPackagesForUserWithPackageTypes(null,
PackageType_Main|PackageType_Optional)
{
PACKAGE_INFO_REFERENCE pir
OpenPackageInfoByFullName(p.Id.FullName, 0, &pir)
UINT32 n=0
GetPackageApplicationIds(pir, &n, null, null)
BYTE* buffer = new BYTE[n]
UINT32 count=0
GetPackageApplicationIds(pir, &n, buffer, &count)
ClosePackageInfo(pir)
PCWSTR * applicationUserModelIds = reinterpret_cast<PCWSTR*>(buffer);
FOR (i=0; i<count; ++i)
{
PCWSTR applicationUserModelId = applicationUserModelIds[i]
}
delete [] buffer
}
See GetPackageApplicationIds() on MSDN for more details including working sample code
https://msdn.microsoft.com/en-us/library/windows/desktop/dn270603(v=vs.85).aspx

Detect BIOS from WinPE: Legacy or UEFI, using vbs // Outputting results from a .exe to .txt

Here is my scenario:
I have a server with 2 possible configurations: 2-TB HDD which require no special treatment or 3-TB HDD that require a UEFI BIOS and a GPT partition to boot the OS.
I am trying to create a single installation USB key that is able to detect whether the BIOS is 'legacy' or 'UEFI' and execute a deployment script accordingly.
I looked hard for a WMI that can make the distinction but to no avail.
The closest that I came to a solution is this post:
http://social.technet.microsoft.com/Forums/en-US/winserverManagement/thread/6cbb488d-3062-4aad-b712-7a9e4d045b13
detectefi.exe works perfectly in detecting the BIOS type, but I can't output its result so I don't know how to use it.
I have 2 questions:
is there any WMI that I can use to distinguich between my 2 set-ups.
(if the answer for question 1 is no) is there a way to output the results from a C++ compiled .exe file to .txt or any other form and make use of the result (I have no C++ skills at all)
If anyone is interested how I fixed the problem. I just created a vbs linking to the .exe
Set objShell = CreateObject("WScript.Shell")
Set objWshScriptExec = objShell.Exec("detectefi.exe")
Set objStdOut = objWshScriptExec.StdOut
dim isLegacy
dim isUefi
isLegacy = false
isUefi = false
While Not objStdOut.AtEndOfStream
strLine = objStdOut.ReadLine
if strLine = "Legacy" then
isLegacy = true
end if
if strLine = "UEFI" then
isUefi = true
end if
Wend
if isLegacy then
wscript.echo "this is legacy"
set objShell = Wscript.CreateObject("WScript.Shell")
objShell.Run "2TBdeploy.cmd",1,True
set objShell = Nothing
end if
if isUefi then
wscript.echo "this is UEFI"
set objShell = Wscript.CreateObject("WScript.Shell")
objShell.Run "3TBdeploy.cmd",1,True
set objShell = Nothing
end if
This is real easy to detect without using any special utilities and using command line native to Windows OS.
BCDEDIT /ENUM will provide you the default bootloader. This is what can be used to distinguish UEFI and BIOS machines, like so:
path \EFI\Microsoft\Boot\bootmgfw.efi
You can then process the output using oShell.Exec as described above.
import os
if os.path.exists("/sys/firmware/efi"):
print "uefi"
else:
print "bios"

Why is a Remote WMI call to Win32_Printer Coming Back With An Empty Set For Some Machines?

I am using WMI (prototyping everything in VBScript first, as examples are more plentiful and it removes VBScript/Python impedence) to connect remotely to a fresh PC (we will call this PC2). Most Win32_* classes can be remotely read, yet Win32_Printer returns an empty set when queried, but only when I query remotely. The resulting SWbemObjectSet always has a .Count of zero. No error. I can connect to PC1 and receive a SWbemObjectSet with a non-zero .Count, can iterate through it, etc. If I run the script locally (after removing the superuser username and password from the .ConnectServer method, naturally), I get a non-zero .Count back and can iterate through it. Even if I foolishly use my own Domain Administrator account, the problem persists. The Script:
strComputer = "nnn.nnn.nnn.nnn"
username = "DOMAIN\superuser"
password = "thisisaverygoodpassword"
Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
objSWbemLocator.Security_.ImpersonationLevel = 3
objSWbemLocator.Security_.AuthenticationLevel = 6
Set objSWbemServices = objSWbemLocator.ConnectServer(strComputer, "root\cimv2", username, password)
Set colSWBemObjectSet = objSWbemServices.ExecQuery("Select * From Win32_Printer")
WScript.Echo colSWBemObjectSet.Count & " Found."
For Each objPrinter in colSWBemObjectSet
For Each Property in objPrinter.Properties_
If TypeName(Property.Value) = "Variant()" Then
Wscript.Echo """" & Property.Name & """, """ & TypeName(Property.Value) & """, ""Skipping ..."""
Else
Wscript.Echo """" & Property.Name & """, """ & TypeName(Property.Value) & """, """ & Property.Value & """"
End If
Next
Next
Commenting and error checking have been omitted for brevity.
It does not appear to be a firewall problem.
Reason 1: Where a firewall blockage does exist, I receive an error
back from SWbemLocator, "The RPC server is unavailable."
Reason 2: I can access and run through the WMI class Win32_ComputerSystem
with ease.
It does not appear to be a username/password problem.
Reason 1: I can retrieve information from Win32_ComputerSystem.
Reason 2: I ought to get an error.
It does not appear to be an OS version problem:
Reason: PC2 and PC1 are both running Windows 7 Professional. PC1 is running the 64-bit version, PC2 the 32-bit.
Although I started trying to reach a 32-bit machine from a 64-bit server, it does not appear to be a 32-bit vs. 64-bit problem.
Reason 1: I added a value of 32 for __ProviderArchitecture in a SWbemNamedValueSet prior to my .ConnectServer attempt (with that SWbemNamedValueSet in the arguments to no avail), although I was unable to later add that same context to the .ExecQuery method of the connected server without a type mismatch operator.
Reason 2: I later ran the script from a 32-bit server with the same result.
It does not appear to be a corrupted WMI problem.
Reason: Once I stop using credentials, I can run the script from the target machine itself and receive a result set with more than zero items and can iterate through it.
It does not appear to be a credential/namespace mistake within my script.
Reason: Using WBemTest.exe from the same source machine and using identical username, password, authentication level, impersonation level, namespace, and so forth, I receive the same null set for an answer.
It does not appear to be an issue of WMI Namespace security on the target machine.
Reason 1: Logging in to the target machine with the same credentials as the script uses generates results.
Reason 2: Win32_Printer is in the same namespace as Win32_ComputerSystem. Win32_ComputerSystem works.
Reason 3: After using the Wmimgmt.msc Microsoft Management Console (MMC) to give the superuser full permissions, starting in the root namespace, propagating to "This namespace and subnamespaces," rebooting, and checking again, I still receive the same empty set.
It does not appear to be the respective OUs of PC2 and PC1 that are the problem.
Reason: I swapped the OUs each machine was in and rebooted. No change.
It does not appear to be the Local Computer Groups:
Reason: I made the membership of groups in PC2 look like PC1 and rebooted. No change.
It does not appear to be something magical about Win32_Printer in that remote access does not work.
Reason: I can read PC1's Win32_Printer class.
It does not appear that my WQL is unusual.
Reason: "SELECT * FROM Win32_Printer" is my test case.
It does not appear that my DCOM settings are off.
Reason: They appear identical when I go through PC1 and PC2.
I have even gone so far as to hit the Trace logs in WMI-Activity, print them out for both PC1 and PC2, then sort by GroupOperationID, OperationID (the TimeCreated SystemTime is not granular enough and EventID seems ... out of order. I can see events from the following actions:
IWbemServices::Connect
Start IWbemServices::ExecQuery - Select * from __ClassProviderRegistration
Start IWbemServices::GetObject - __Win32Provider.Name="WmiPerfClass"
Start IWbemServices::ExecQuery - references of {__Win32Provider.Name="WmiPerfClass"}
Start IWbemServices::GetObject - Win32_Printer
Start IWbemServices::ExecQuery - Select * From Win32_Printer
Provider::CreateInstanceEnum - Win32_Printer
in both sets of logs, and if I sort by GroupOperationID, OperationID they appear to happen in identical order. Sorting by EventID shows a somewhat different order. That's the closest I can see to a difference. I'm stumped at this point.
I know this verges perilously close to a system administration issue.
Found this link in the win32_printer spec page referring to this problem http://www.lansweeper.com/forum/yaf_postsm18178_WMI-Security-PowershellLansweeper.aspx#post18178 It appears only printers installes for this user are returned, not all printers on the system. So if you've never logged on to the remote system under the credentials of the user you are using to enumerate the printers then you get an empty result.
Looks like you've had a good shot at it. ServerFault might yield something more...
It's a long shot, but I once heard terminal services being disabled aparently caused issues when issuing WMI queries...
Edit:
This may not apply, but could be worth a look: AD Delegation