Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
900 views
in Technique[技术] by (71.8m points)

powershell - How to use a text file as input for a scriptblock - working directory in background jobs

I have been given the task to write a PS script that will, from a list of machines in a text file:

  1. Output the IP address of the machine
  2. Get the version of the SCCM client on the machine
  3. Produce a GPResult HTMl file OR
  4. Indicate that the machine is offline

With a final stipulation of running the script in the background (Job)

I have the scriptblock that will do all of these things, and even have the output formatted like I want. What I cannot seem to do, is get the scriptblock to call the source file from within the same directory as the script. I realize that I could simply hard-code the directories, but I want to be able to run this on any machine, in any directory, as I will need to use the script in multiple locations.

Any suggestions?

Code is as follows (Note: I am in the middle of trying stuff I gathered from other articles, so it has a fragment or two in it [most recent attempt was to specify working directory], but the core code is still there. I also had the idea to declare the scriptblock first, like you do with variables in other programming languages, but more for readability than anything else):

 # List of commands to process in job
$ScrptBlk = {
param($wrkngdir)

Get-Content Hostnames.txt | ForEach-Object {
 # Check to see if Host is online
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 RootCCM -Class Sms_Client).ClientVersion
 # Generate GPResult HTML file 
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}}}
 # Create (or clear) output file
Echo "" > OnlineCheckResults.txt
 # Create subdirectory, if it does not exist
IF (-Not (Get-Item .GPRes)) { New-Item -ItemType dir ".GPRes" }
 # Get current working directory
$wrkngdir = $PSScriptRoot
 # Execute script
Start-Job -name "OnlineCheck" -ScriptBlock $ScrptBlk -ArgumentList $wrkngdir
 # 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

I appreciate any help you may have to offer.

Cheers.

~DavidM~

EDIT

Thanks for all the help. Setting the working directory works, but I am now getting a new error. It has no line reference, so I am not sure where the problem might be. New code below. I have moved the sriptblock to the bottom, so it is separate from the rest of the code. I thought that might be a bit tidier. I do apologize for my earlier code formatting. I will attempt to do better with the new example.

     # 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 RootCCM -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}}}

Error text: Cannot validate argument on parameter 'ComputerName'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again. + CategoryInfo : InvalidData: (:) [Test-Connection], ParameterBindingValidationException + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.TestConnectionCommand + PSComputerName : localhost

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

If I understand correctly, I think that the issue you are having is because the working directory path is different inside the execution of the Script Block. This commonly happens when you execute scripts from Scheduled tasks or pass scripts to powershell.exe

To prove this, let's do a simple PowerShell code:

#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:UsersHAL9256Documents

As you can see the current path inside the execution of the script block is different than where you executed it. I have also seen inside of Scheduled tasks, paths like C:WindowsSystem32 .

Since you are trying to reference everything by relative paths inside the script block, it won't find anything. One solution is to use the passed parameter to change your working directory to something known first.

Also, I would use $PWD.Path to get the current working directory instead of $PSScriptRoot as $PSScriptRoot is empty if you run the code from the console.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...