Powershell 如何在后台作业中将文本文件用作scriptblock工作目录的输入
我的任务是编写一个PS脚本,该脚本将从文本文件中的机器列表中:Powershell 如何在后台作业中将文本文件用作scriptblock工作目录的输入,powershell,working-directory,start-job,Powershell,Working Directory,Start Job,我的任务是编写一个PS脚本,该脚本将从文本文件中的机器列表中: 输出机器的IP地址 获取计算机上SCCM客户端的版本 生成一个GPResult HTMl文件 或 指示机器处于脱机状态 最后规定在后台运行脚本(作业) 我有一个scriptblock可以完成所有这些事情,甚至可以按照我的要求格式化输出。我似乎做不到的是让scriptblock从与脚本相同的目录中调用源文件。我意识到我可以简单地对目录进行硬编码,但我希望能够在任何机器上、任何目录中运行该脚本,因为我需要在多个位置使用该脚本 有什么建议
代码如下:(注:我在尝试从其他文章中收集的东西中间,所以它有一个或两个片段[最近的尝试是指定工作目录),但核心代码仍然存在。我还想先声明scriptblock,就像您在其他编程语言中对变量所做的那样,但更多的是为了可读性):
我很感激你能提供的任何帮助 干杯 ~DavidM~ 编辑 谢谢你的帮助。设置工作目录是可行的,但我现在遇到了一个新错误。它没有行引用,因此我不确定问题可能在哪里。下面是新代码。我已经将sriptblock移到了底部,因此它与代码的其余部分是分开的。我想那可能会更整洁一点。对于我之前的代码格式设置,我深表歉意。我将尝试用新的例子做得更好 # Store working directory
$getwkdir = $PWD.Path
# Create (or clear) output file
Write-Output "" > OnlineCheckResults.txt
# Create subdirectory, if it does not exist. Delete and recreate if it does
IF (Get-Item .\GPRes) {
Remove-Item -ItemType dir "GPRes"
New-Item -ItemType dir "GPRes"}
ELSE{
New-Item -ItemType dir "GPRes"}
# Start the job
Start-Job -name "OnlineCheck" -ScriptBlock $ScrptBlk -ArgumentList $getwkdir
# Let job run
Wait-Job OnlineCheck
# Get results of job
$results = Receive-Job OnlineCheck
# Output results to file
$results >> OnlineCheckResults.txt | FT Computername,IPV4Address,SCCM_Version
$ScrptBlk = {
param($wrkngdir)
Set-Location $wrkngdir
Get-Content Hostnames.txt | ForEach-Object {
IF ( Test-Connection $_ -count 1 -Quiet) {
# Get IP address, extracting only IP value
$addr = (test-connection $_ -count 1).IPV4Address
# Get SCCM version
$sccm = (Get-WmiObject -NameSpace Root\CCM -Class Sms_Client).ClientVersion
Get-GPResultantSetOfPolicy -computer $_.name -reporttype HTML -path ".\GPRes\$_ GPResults.html"}
ELSE {
$addr = "Offline"
$sccm = " "}
$tbl = New-Object psobject -Property @{
Computername = $_
IPV4Address = $addr
SCCM_Version = $sccm}}}
错误文本:
无法验证参数“ComputerName”上的参数。参数为null或为空。提供一个论点
不为null或为空,然后重试该命令。
+CategoryInfo:InvalidData:(:)[Test Connection],ParameterBindingValidationException
+FullyQualifiedErrorId:ParameterArgumentValidationError,Microsoft.PowerShell.Commands.TestConnectionCommand
+PSComputerName:localhost如果我理解正确,我认为您遇到的问题是因为脚本块执行过程中的工作目录路径不同。这通常发生在从计划任务执行脚本或将脚本传递到powershell.exe时 为了证明这一点,让我们执行一个简单的PowerShell代码:
#Change current directory to the root of C: illustrate what's going on
cd C:\
Get-Location
Path
----
C:\
#Execute Script Block
$ScriptBlock = { Get-Location }
$Job = Start-Job -ScriptBlock $ScriptBlock
Receive-Job $Job
Path
----
C:\Users\HAL9256\Documents
正如您所看到的,脚本块执行中的当前路径与执行它的位置不同。我还看到了计划任务的内部路径,如C:\Windows\System32
因为您试图通过脚本块内的相对路径引用所有内容,所以它找不到任何内容。一种解决方案是使用传递的参数将工作目录更改为已知的目录
另外,我将使用$PWD.Path
来获取当前工作目录,而不是$PSScriptRoot
,因为如果从控制台运行代码,$PSScriptRoot
是空的。,您通过-ArgumentList$wrkngdir
将所需的工作目录传递给脚本块,这是正确的,但是您没有在脚本块中使用该参数
只需在脚本块的开头使用设置位置
,即可切换到传递的工作目录:
$ScrptBlk = {
param($wrkngdir)
# Change to the specified working dir.
Set-Location $wrkngdir
# ... Get-Content Hostnames.txt | ...
}
# Start the job and pass the directory in which this script is located as the working dir.
Start-Job -name "OnlineCheck" -ScriptBlock $ScrptBlk -ArgumentList $PSScriptRoot
在PSv3+中,您可以通过使用调用方作用域中的$using:
范围来简化解决方案,这允许您直接引用调用方作用域中的变量;下面是一个简化的示例,您可以直接从提示符运行(我使用$PWD
作为所需的工作目录,因为$PSScriptRoot
未在提示符处定义(在全局范围内)):
如果您从(比如)C:\tmp调用上述命令,那么输出也将反映该路径,从而证明后台作业与调用者运行在同一工作目录中
PowerShell后台作业中的工作目录:
$ScrptBlk = {
param($wrkngdir)
# Change to the specified working dir.
Set-Location $wrkngdir
# ... Get-Content Hostnames.txt | ...
}
# Start the job and pass the directory in which this script is located as the working dir.
Start-Job -name "OnlineCheck" -ScriptBlock $ScrptBlk -ArgumentList $PSScriptRoot
- 在PowerShell 7.0之前使用
返回的目录启动后台作业,作为初始工作目录[environment]:GetFolderPath('MyDocuments')
$HOME\Documents
,而在类似Unix的平台上则是$HOME
(在PowerShell核心中)
- 通过
的Start job
脚本块参数通过-InitializationScript
引用设置后台作业的工作目录-例如,$using:
应该可以工作,但在Windows PowerShell v5.1/PowerShell[Core]6.x中,由于(该错误仍然存在于PowerShell 7.0中,但您可以在那里使用Start job-InitializationScript{$using:PWD}{…}
)-WorkingDirectory
开始作业
现在明智地默认为调用者的工作目录-WorkingDirectory
参数以简化工作目录的指定
&
启动后台作业-与类似POSIX的shell(如bash
do)的方式相同-在这种情况下,调用方的工作目录将被继承;例如:
# PS Core only:
# Outputs the caller's working dir., proving that the background job
# inherited the caller's working dir.
(Get-Location &) | Receive-Job -Wait -AutoRemove
乍一看,您没有使用在
-ArgumentLIst
中发送的$wrkngdir
参数。如何获取内容(Join Path-Path$wrkngdir-ChildPath'Hostnames.txt')
。另外,如果我可以建议的话,请对代码缩进做些什么,因为现在它真的很难阅读..可能会有帮助
# PS Core only:
# Outputs the caller's working dir., proving that the background job
# inherited the caller's working dir.
(Get-Location &) | Receive-Job -Wait -AutoRemove