Windows 来自 Perl 的任务计划程序 Win32::OLE - 无效查询
Windows Task Scheduler from Perl with Win32::OLE - Invalid Query
我正在尝试使用 Win32::OLE 在 Windows 10 系统上创建一个类似于 SetDefaultPrinterFromSSD.ps1 的任务。我尝试通过在任务计划程序 GUI 中手动创建相同的任务来手动验证查询,这似乎有效。
这是我的测试代码:
use File::Basename;
use Win32;
use Win32::OLE;
$Win32::OLE::Warn = 3;
use Data::Dumper;
my ($me, $dirpath, $suffix) = fileparse([=12=], qr/\.[^.]*/);
my ($system, $login, $domain, $sidbin, $sidtype, $sidtxt) = "";
$login = Win32::LoginName();
Win32::LookupAccountName($system, $login, $domain, $sidbin, $sidtype);
my($Revision, $SubAuthorityCount,@IdentifierAuthorities) = unpack("CCnnn", $sidbin);
unless (($IdentifierAuthorities[0] || $IdentifierAuthorities[1])) {
my($temp, $temp2, @SubAuthorities) = unpack("VVV$SubAuthorityCount",$sidbin);
$sidtxt = "S-$Revision-$IdentifierAuthorities[2]-".join("-",@SubAuthorities);
}
die Win32::OLE->LastError() unless (my $service = Win32::OLE->CreateObject('Schedule.Service'));
$service->Connect;
my $RootFolder = $service->GetFolder('\');
die Win32::OLE->LastError() unless (my $TaskDefinition = $service->NewTask(0));
die Win32::OLE->LastError() unless (my $regInfo = $TaskDefinition->RegistrationInfo);
$regInfo->{Description} = "Register a perl task as an event $me";
$regInfo->{Author} = "$domain\$login";
$regInfo->{URI} = "$sidtxt\$me";
die Win32::OLE->LastError() unless (my $settings = $TaskDefinition->Settings);
$settings->{Enabled} = 1;
$settings->{AllowDemandStart} = 1;
$settings->{DisallowStartIfOnBatteries} = 0;
$settings->{StopIfGoingOnBatteries} = 0;
$settings->{Hidden} = 0;
my @Triggers;
my $TriggerSet;
die Win32::OLE->LastError() unless ($TriggerSet = $TaskDefinition->Triggers);
for (10000..10001) {
die Win32::OLE->LastError() unless (push @Triggers, $TriggerSet->Create(0));
$Triggers[$#Triggers]->{Id} = $_;
$Triggers[$#Triggers]->{Subscription} =
"<QueryList>
<Query Id=\"event$_\" Path=\"Microsoft-Windows-NetworkProfile/Operational\">
<Select Path=\"Microsoft-Windows-NetworkProfile/Operational\">*[System[(EventID=\"$_\")]]</Select>
</Query>
</QueryList>";
die Win32::OLE->LastError()
unless (my $values = $Triggers[$#Triggers]->ValueQueries->Create("eventId", "Event/System/EventID"));
$Triggers[$#Triggers]->{Enabled} = 1;
}
die Win32::OLE->LastError() unless (my $Action = $TaskDefinition->Actions()->Create(0));
$Action->{Path} = 'C:\Perl64\Bin\Perl.exe';
$Action->{Arguments} = "[=12=] -f event${eventID}";
$RootFolder->RegisterTaskDefinition("OLE-Test",$TaskDefinition,6,undef,undef,3);
print Dumper $TaskDefinition->{XmlText};
如果我 运行 带有 RegisterTaskDefinition 的代码设置了 TASK_VALIDATE_ONLY 标志(第三个参数 = 1),我会得到一个很好的 XML 转储。到目前为止,一切都很好。
当我 运行 使用 RegisterTaskDefinition 和 TASK_CREATE_OR_UPDATE (第三个参数 = 6)的代码时,我收到此错误:
OLE exception from "<Unknown Source>":
(11,263):Subscription:<QueryList><Query Id="event10000"
Path="Microsoft-Windows-NetworkProfile/Operational"><Select
Path="Microsoft-Windows-NetworkProfile/Operational">*
[System[(EventID="10000")]]</Select></Query></QueryList>
Win32::OLE(0.1712) error 0x80073a99: "The specified query is invalid"
in METHOD/PROPERTYGET "RegisterTaskDefinition" at OLE-test.pl line 63.
有谁足够熟悉 Win32::OLE 和 Windows 任务调度器 XML 来解释我做错了什么?
查询 ID 属性必须是数字。我得到以下工作:
for (10000..10001) {
die Win32::OLE->LastError() unless (push @Triggers, $TriggerSet->Create(0));
$Triggers[$#Triggers]->{Id} = $_;
$Triggers[$#Triggers]->{Subscription} =
qq{<QueryList>
<Query Id="$_" Path="Microsoft-Windows-NetworkProfile/Operational">
<Select Path="Microsoft-Windows-NetworkProfile/Operational">*[System[(EventID="$_")]]</Select>
</Query>
</QueryList>};
die Win32::OLE->LastError()
unless (my $values = $Triggers[$#Triggers]->ValueQueries->Create("eventId", "Event/System/EventID"));
$Triggers[$#Triggers]->{Enabled} = 1;
}
相关的,神奇的变化正在匹配
$Triggers[$#Triggers]->{Id} = $_;
和
<Query Id="$_" Path="Microsoft-Windows-NetworkProfile/Operational">
也许您可以将两者都更改为非数字,但通过这种更改,我创建了之后可以查看的任务。
考虑在您的代码中使用 $^X
以使 Perl 的路径更加动态,而不是将其硬编码为 C:\Perl64
。
我正在尝试使用 Win32::OLE 在 Windows 10 系统上创建一个类似于 SetDefaultPrinterFromSSD.ps1 的任务。我尝试通过在任务计划程序 GUI 中手动创建相同的任务来手动验证查询,这似乎有效。
这是我的测试代码:
use File::Basename;
use Win32;
use Win32::OLE;
$Win32::OLE::Warn = 3;
use Data::Dumper;
my ($me, $dirpath, $suffix) = fileparse([=12=], qr/\.[^.]*/);
my ($system, $login, $domain, $sidbin, $sidtype, $sidtxt) = "";
$login = Win32::LoginName();
Win32::LookupAccountName($system, $login, $domain, $sidbin, $sidtype);
my($Revision, $SubAuthorityCount,@IdentifierAuthorities) = unpack("CCnnn", $sidbin);
unless (($IdentifierAuthorities[0] || $IdentifierAuthorities[1])) {
my($temp, $temp2, @SubAuthorities) = unpack("VVV$SubAuthorityCount",$sidbin);
$sidtxt = "S-$Revision-$IdentifierAuthorities[2]-".join("-",@SubAuthorities);
}
die Win32::OLE->LastError() unless (my $service = Win32::OLE->CreateObject('Schedule.Service'));
$service->Connect;
my $RootFolder = $service->GetFolder('\');
die Win32::OLE->LastError() unless (my $TaskDefinition = $service->NewTask(0));
die Win32::OLE->LastError() unless (my $regInfo = $TaskDefinition->RegistrationInfo);
$regInfo->{Description} = "Register a perl task as an event $me";
$regInfo->{Author} = "$domain\$login";
$regInfo->{URI} = "$sidtxt\$me";
die Win32::OLE->LastError() unless (my $settings = $TaskDefinition->Settings);
$settings->{Enabled} = 1;
$settings->{AllowDemandStart} = 1;
$settings->{DisallowStartIfOnBatteries} = 0;
$settings->{StopIfGoingOnBatteries} = 0;
$settings->{Hidden} = 0;
my @Triggers;
my $TriggerSet;
die Win32::OLE->LastError() unless ($TriggerSet = $TaskDefinition->Triggers);
for (10000..10001) {
die Win32::OLE->LastError() unless (push @Triggers, $TriggerSet->Create(0));
$Triggers[$#Triggers]->{Id} = $_;
$Triggers[$#Triggers]->{Subscription} =
"<QueryList>
<Query Id=\"event$_\" Path=\"Microsoft-Windows-NetworkProfile/Operational\">
<Select Path=\"Microsoft-Windows-NetworkProfile/Operational\">*[System[(EventID=\"$_\")]]</Select>
</Query>
</QueryList>";
die Win32::OLE->LastError()
unless (my $values = $Triggers[$#Triggers]->ValueQueries->Create("eventId", "Event/System/EventID"));
$Triggers[$#Triggers]->{Enabled} = 1;
}
die Win32::OLE->LastError() unless (my $Action = $TaskDefinition->Actions()->Create(0));
$Action->{Path} = 'C:\Perl64\Bin\Perl.exe';
$Action->{Arguments} = "[=12=] -f event${eventID}";
$RootFolder->RegisterTaskDefinition("OLE-Test",$TaskDefinition,6,undef,undef,3);
print Dumper $TaskDefinition->{XmlText};
如果我 运行 带有 RegisterTaskDefinition 的代码设置了 TASK_VALIDATE_ONLY 标志(第三个参数 = 1),我会得到一个很好的 XML 转储。到目前为止,一切都很好。 当我 运行 使用 RegisterTaskDefinition 和 TASK_CREATE_OR_UPDATE (第三个参数 = 6)的代码时,我收到此错误:
OLE exception from "<Unknown Source>":
(11,263):Subscription:<QueryList><Query Id="event10000"
Path="Microsoft-Windows-NetworkProfile/Operational"><Select
Path="Microsoft-Windows-NetworkProfile/Operational">*
[System[(EventID="10000")]]</Select></Query></QueryList>
Win32::OLE(0.1712) error 0x80073a99: "The specified query is invalid"
in METHOD/PROPERTYGET "RegisterTaskDefinition" at OLE-test.pl line 63.
有谁足够熟悉 Win32::OLE 和 Windows 任务调度器 XML 来解释我做错了什么?
查询 ID 属性必须是数字。我得到以下工作:
for (10000..10001) {
die Win32::OLE->LastError() unless (push @Triggers, $TriggerSet->Create(0));
$Triggers[$#Triggers]->{Id} = $_;
$Triggers[$#Triggers]->{Subscription} =
qq{<QueryList>
<Query Id="$_" Path="Microsoft-Windows-NetworkProfile/Operational">
<Select Path="Microsoft-Windows-NetworkProfile/Operational">*[System[(EventID="$_")]]</Select>
</Query>
</QueryList>};
die Win32::OLE->LastError()
unless (my $values = $Triggers[$#Triggers]->ValueQueries->Create("eventId", "Event/System/EventID"));
$Triggers[$#Triggers]->{Enabled} = 1;
}
相关的,神奇的变化正在匹配
$Triggers[$#Triggers]->{Id} = $_;
和
<Query Id="$_" Path="Microsoft-Windows-NetworkProfile/Operational">
也许您可以将两者都更改为非数字,但通过这种更改,我创建了之后可以查看的任务。
考虑在您的代码中使用 $^X
以使 Perl 的路径更加动态,而不是将其硬编码为 C:\Perl64
。