Start-Job scriptblock passing of variable - powershell

I got a PowerShell script that starts another script and passes parameters to it.
I do this with Start-Job as I do not want to wait until the second script is finished:
ScriptA:
start-job -name EnableAutoUnlock -scriptblock {Invoke-Command -script { C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe "\\Path\To\Script\EnableAutoUnlock.ps1" $VolumeDriveLetter }}
ScriptB:
[CmdletBinding()]
Param (
[Parameter(Position=0)]
[string]$drive
)
<do stuff with $drive here>
$VolumeDriveLetter is just a Drive Letter that gets processed i.e. "C:"
Unfortunately the passing of the Parameter by variable does not work although $VolumeDriveLetter has the expected Value but typing it does work correctly.
Works:
start-job -name EnableAutoUnlock -scriptblock {Invoke-Command -script { C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe "\\Path\To\Script\EnableAutoUnlock.ps1" C: }}
Does not Work
$VolumeDriveLetter = "C:"
start-job -name EnableAutoUnlock -scriptblock {Invoke-Command -script { C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe "\\Path\To\Script\EnableAutoUnlock.ps1" $VolumeDriveLetter }}
EDIT: ScriptB Outputs the passed Variable as empty
What am I missing to get passing of the Variable to work?

You can use the using prefix to access the value within a scriptblock:
$VolumeDriveLetter = "C:"
start-job -name EnableAutoUnlock -scriptblock {Invoke-Command -script { C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe "\\Path\To\Script\EnableAutoUnlock.ps1" $using:VolumeDriveLetter }}
Or you use the -ArgumentList parameter and pass the parameter to the scriptblock:
start-job -name EnableAutoUnlock -scriptblock {
Param($VolumeDriveLetter)
Write-Host $VolumeDriveLetter
} -ArgumentList $VolumeDriveLetter

Related

Passing parameter using variable While generating DSC configuration

I am executing Powershell DSC script from Powershell. Below is the code snippet
Invoke-Command -ComputerName $public_ip_address -Credential $UserCredential -ScriptBlock {
param ($driveformat)
cd c:/provisioning
Install-PackageProvider -Name NuGet -Force -Scope CurrentUser
Install-Module -Name PSDscResources -Force
Install-Module -Name xStorage -Force
. .\DiskSetup.ps1
disksconfig -outputpath C:\DataDiskSetting -driveFormat $driveFormat
Start-DscConfiguration -Path C:\DataDiskSetting -Wait -Force -Verbose
} -ArgumentList ($driveformat)
While generating configuration I want to pass driveformat as variable "$driveFormat" instead of hardcoding like "NTFS". Somehow its not getting value of $driveformat any idea how we can solve this.
You can add a named Parameter $driveformat in your script. See below example:
Param([String]$driveformat)
Invoke-Command -ComputerName $public_ip_address -Credential $UserCredential -ScriptBlock {
param ($driveformat)
...
} -ArgumentList ($driveformat)
Then in the powershell task from pipeline, add -driveformat "NTFS" in the argument field. See below screenshot: (I defined a pipeline variable driveformat to hold the value "NTFS")
Or, you can add an Argument (eg. $driveformat = $args[0]) in your scripts. See below:
$driveformat = $args[0]
Invoke-Command -ComputerName $public_ip_address -Credential $UserCredential -ScriptBlock {
param ($driveformat)
...
} -ArgumentList ($driveformat)
Then you can directly pass the variable ("NTFS") in the Arguments field of powershell task:

Set-Execution policy on remote computer using Variable

I have a problem reverting back powershell execution policy on remote computer using variable.
$RestrykcjaNowa = 'Bypass'
$RestrykcjaZastana = Invoke-Command -ComputerName $Komputer -ScriptBlock { Get-ExecutionPolicy }
$RestrykcjaZastana
Invoke-Command -ComputerName $Komputer -ScriptBlock { Set-ExecutionPolicy -ExecutionPolicy $RestrykcjaNowa -Scope LocalMachine -Force } | Out-Null
But I got an error
Cannot bind argument to parameter 'ExecutionPolicy' because it is null
When I replace variable $RestrykcjaNowa with value Bypass in last command it goes smoothly.
I noticed that variable $RestrykcjaZastana is not displayed on the screen when called in 2nd line of the code and is of type int but i can't assign value Bypass to integer variable manually.
What is wrong with my approach?
You have two issues to address:
Execution policies are not strings; they are a separate enumerated type, [Microsoft.PowerShell.ExecutionPolicy]. You will have to assign them as such to your variable:
$RestrykcjaNowa = [Microsoft.PowerShell.ExecutionPolicy]::Bypass
Variables outside of scriptblocks need to be referenced from within the script block with using::
Invoke-Command -ComputerName $Komputer -ScriptBlock { Set-ExecutionPolicy -ExecutionPolicy $using:RestrykcjaNowa -Scope LocalMachine -Force } | Out-Null
Variables are not evaluated when Scriptblock is defined.
However for your case, you may use below code with which you can pass variable to scriptblock as an argument:
$RestrykcjaNowa = 'Bypass'
$Komputer = '<Computername>'
$RestrykcjaZastana = Invoke-Command -ComputerName $Komputer -ScriptBlock { Get-ExecutionPolicy }
$RestrykcjaZastana
Invoke-Command -ComputerName $Komputer -ScriptBlock {param($RestrykcjaNowa) Set-ExecutionPolicy -ExecutionPolicy $RestrykcjaNowa -Scope LocalMachine -Force } -ArgumentList $RestrykcjaNowa | Out-Null

Importing Scriptblock from file

I've got a working Powershell script and I'd like to have the scriptblock pulled in from an external file.
Working:
$scriptblock = { ... }
invoke-command -ComputerName $server -ScriptBlock $Scriptblock -ArgumentList $server,$team -Credential $credential -asjob -JobName Dashboard_$server -SessionOption (New-PSSessionOption -NoMachineProfile)
Output of "get-job -id | receive-job" is fine
Not working:
# Generate scriptblock from file
$file = Get-Content E:\Dashboard\Windows\winrm_scriptblock.txt
$Scriptblock = $executioncontext.invokecommand.NewScriptBlock($file)
invoke-command -ComputerName $server -ScriptBlock $Scriptblock -ArgumentList $server,$team -Credential $credential -asjob -JobName Dashboard_$server -SessionOption (New-PSSessionOption -NoMachineProfile)
Output of "get-job -id | receive-job" is empty
The contents of winrm_scriptblock.txt is exactly what is included between the braces in the scriptblock variable defined in the working version.
Any assistance is appreciated.
I know you already have answers, but another way to get a scriptblock from a script file is to use the get-command cmdlet:
$sb=get-command C:\temp\add-numbers.ps1 | select -ExpandProperty ScriptBlock
$sb is now the scriptblock for the script.
Very related to the answer from How do I pass a scriptblock as one of the parameters in start-job
If you stored the string "Get-ChildItem C:\temp" in the file "E:\Dashboard\Windows\winrm_scriptblock.txt" then this code should output the contents of the folder "C:\temp" on your local machine.
Invoke-Command -ScriptBlock ([scriptblock]::Create((Get-Content "E:\Dashboard\Windows\winrm_scriptblock.txt")))
Parameters
As far as passing parameters goes Pass arguments to a scriptblock in powershell covers that answer as well. As Keith Hill states: a scriptblock is just an anonymous function
Consider the following file contents
param(
$number
)
$number..2 | ForEach-Object{
Write-Host "$_ lines of code in the file."
}
And the command
Invoke-Command -ScriptBlock ([scriptblock]::Create((Get-Content "E:\Dashboard\Windows\winrm_scriptblock.txt"))) -ArgumentList "99"
Would give you the annoying output of
99 lines of code in the file.
98 lines of code in the file.
97 lines of code in the file.
....
Any reason not to just use the -FilePath parameter of Invoke-Command?
you must extract {} from E:\Dashboard\Windows\winrm_scriptblock.txt

invoke-expression inside scriptblock of invoke-command not working

I've got the following script
$name = (Invoke-Command -ComputerName "STW111" -Credential $cred -ScriptBlock { Invoke-Expression "C:\PSS\User Tool\UserTool.exe"} -AsJob).Name
Wait-Job -Name $name
This not working, however, if I move the usertool to c:\pss\, it works fine.
$name = (Invoke-Command -ComputerName "STW111" -Credential $cred -ScriptBlock { Invoke-Expression "C:\PSS\UserTool.exe"} -AsJob).Name
Wait-Job -Name $name
I really need to get to grips with escaping in Powershell.
Any ideas?
TIA
try this:
Invoke-Expression "& 'C:\PSS\User Tool\UserTool.exe'"

Start-Job script block-- how to call cmdlets with arguments?

I'm new to the Start-Job cmdlet and am having trouble calling a script block with cmdlets in it that take arguments. Here's what I have so far:
Start-Job -ScriptBlock {
$ServiceObj = Get-Service -Name $ServiceName -ComputerName $Computer -ErrorAction Stop
Stop-Service -InputObj $ServiceObj -erroraction stop
}
I'm seeing errors when I run receive-job that the -ComputerName argument is null or empty, and the -InputObj argument is null or empty. In neither case is that so. The snippet above is being called from inside two foreach loops:
foreach($Computer in $ComputerNames) {
foreach($ServiceName in $ServiceNames) {
#..call snippet above
}
}
I've tried using the -ArgumentList when calling my script block but no luck there either. I'm sure I'm missing something?
You do need to use ArgumentList (unless you're on PowerShell V3) e.g.:
Start-Job -ScriptBlock {param($ComputerName)
$ServiceObj = Get-Service -Name $ServiceName -CN $ComputerName -ErrorAction Stop
Stop-Service -InputObj $ServiceObj -erroraction stop
} -ArgumentList $Computer
If you're using PowerShell V3, you can use the using variable qualifier e.g.:
Start-Job -ScriptBlock {
$ServiceObj = Get-Service -Name $ServiceName -CN $using:Computer -ErrorAction Stop
Stop-Service -InputObj $ServiceObj -erroraction stop
}