起初我对 PowerShell ScriptBlock 很兴奋,但最近我对它在块内的执行顺序感到困惑。例如:
$test_block = {
write-host "show 1"
ps
write-host "show 2"
Get-Date
}
Run Code Online (Sandbox Code Playgroud)
调用 $test_block.Invoke() 的输出:
show 1
show 2
<result of command 'ps'>
<result of command 'get-date'>
Run Code Online (Sandbox Code Playgroud)
输出内容的命令会先运行吗?
什么有效 -
假设我有一个scriptblock与Select-Objectcmdlet 一起使用的。
$jobTypeSelector = `
{
if ($_.Type -eq "Foo")
{
"Bar"
}
elseif ($_.Data -match "-Action ([a-zA-Z]+)")
{
$_.Type + " [" + $Matches[1] + "]"
}
else
{
$_.Type
}
}
$projectedData = $AllJobs | Select-Object -Property State, @{Name="Type"; Expression=$jobTypeSelector}
Run Code Online (Sandbox Code Playgroud)
这工作正常,并且我得到了预期的结果。
我正在尝试做的事情 -
但是,在稍后的代码中,我想重用scriptblock定义为$jobTypeSelector.
例如,我期望下面的代码采用$fooJob(注意它是单个对象)作为下面的参数传递,并用于$_中的自动变量scriptblock并返回相同的结果,因为它在Select-Objectcmdlet 上下文中执行时返回。
$fooType = $jobTypeSelector.Invoke($fooJob)
Run Code Online (Sandbox Code Playgroud)
什么不起作用-
它没有按我的预期工作,我得到了空值。
我已经尝试过的 -
我检查了一下,属性都设置正确,并不是因为相关属性本身为空或$null.
我在互联网上查找,似乎很难找到有关该主题的任何相关页面,但我最终找到了一个在稍微不同的上下文中接近解释问题的页面 - …
我无法理解ScriptBlocks中的范围.我指望某种类似闭包的系统,但我似乎无法让它工作.
我有一个ScriptBlock拿a param并返回另一个ScriptBlock:
$sb1 = {
Param($Message1);
Write-Host $Message1;
{
Param($Message2);
Write-Host ($Message1 + " " + $Message2);
}
}
Run Code Online (Sandbox Code Playgroud)
为了得到内ScriptBlock我可以调用$sb1用$sb2 = & $sb1 -Message1 "Message1".这回应Message1所以我们知道它param是受约束的.
现在,我可以调用$sb2用& $sb2 -Message2 "Message2".我原以为Message1 Message2,但它只是写作而已Message2.
有没有办法访问$Message1变量?我不能使用本地或脚本变量,因为内部scriptblock的多个实例具有不同的$Message1s.
这是实际shell的实际输出:
PS C:\> $h1 = { Param($Message1); Write-Host $Message1; { Param($Message2); Write-Host ($Message1 + " " + $Message2); } …Run Code Online (Sandbox Code Playgroud) $var =@( @{id="1"; name="abc"; age="1"; },
@{id="2"; name="def"; age="2"; } );
$properties = @("ID","Name","Age") ;
$format = @();
foreach ($p in $properties)
{
$format += @{label=$p ; Expression = {$_.$p}} #$_.$p is not working!
}
$var |% { [PSCustomObject]$_ } | ft $format
Run Code Online (Sandbox Code Playgroud)
在上面的例子中,我想通过一个变量名访问每个对象的属性。但它不能按预期工作。所以就我而言,如何制作
Expression = {$_.$p}
Run Code Online (Sandbox Code Playgroud)
在职的?
我们来看一下经典的一阶函数示例:
function Get-MyName { "George" }
function Say-Hi([scriptblock]$to) {
Write-Host ("Hi "+(& $to))
}
Run Code Online (Sandbox Code Playgroud)
这很好用:
Say-Hi { "Fred Flintstone" }
Run Code Online (Sandbox Code Playgroud)
这不是:
Say-Hi Get-MyName
Run Code Online (Sandbox Code Playgroud)
因为Get-MyName被评估,而不是作为值本身传递.如何将Get-MyName作为值传递?
我正在尝试从Powershell使用一个类。此类具有一种称为的方法,该方法Execute()具有两个重载:一个重载了Func<T>,一个重载了Action<T>。我可以调用Action<T>以scriptblock为委托的重载,但是我不知道如何调用以a为代表的重载Func<T>:
add-type -TypeDefinition @'
using System;
public class DelegTest
{
public R Execute<R>(Func<R> method)
{
return method();
}
public void Execute(Action method)
{
Execute(() => { method(); return true; });
}
}
'@
$t = new-object DelegTest
$t.Execute({ 1 + 1 }) # returns nothing
Run Code Online (Sandbox Code Playgroud)
我怎么称呼需要一个的过载Func<T>?我认为这将需要创建一个具有返回类型的ScriptBlock,但是我不知道该怎么做。Powershell解析器显然不够智能,无法自动执行此操作。
我试图通过在文件中添加基于递增计数器的前缀来重命名文件,例如:
$directory = 'C:\Temp'
[int] $count=71;
gci $directory | sort -Property LastWriteTime | `
rename-item -newname {"{0}_{1}" -f $count++, $_.Name} -whatif
Run Code Online (Sandbox Code Playgroud)
然而,所有的文件处理是71_和$count在$count++从不增量和文件名前缀相同?为什么?
为什么Start-Process powershell.exe { Read-Host }有效,但Start-Process pwsh.exe { Read-Host }不起作用?
我知道 的-ArgumentList切换Start-Process,但是当涉及转义引号时,它使事情变得更加复杂:
PowerShell 7.0.3 和 7.2.0-preview.3:
Start-Process pwsh.exe -ArgumentList '-Command "& {
''Hello World.''
Read-Host
}"' -Verb RunAs
Run Code Online (Sandbox Code Playgroud)
PowerShell 5.1:
Start-Process powershell.exe {
'Hello World.'
Read-Host
} -Verb RunAs
Run Code Online (Sandbox Code Playgroud)
另一方面,当创建新的 PowerShell 会话(不带Start-Process)时,仍然可以使用脚本块:
pwsh.exe {
'Hello World.'
Read-Host
}
Run Code Online (Sandbox Code Playgroud)
我在这里遗漏了一些东西还是有更好/不同的方法允许脚本块与脚本的其余部分并行执行?
powershell start-process scriptblock powershell-core powershell-7.0
我有一个很长的剧本。我有一个记录功能:
function Log ([string]$Content){
$Date = Get-Date
Add-Content -Path $LogPath -Value ("$Date : $Content")
}
Run Code Online (Sandbox Code Playgroud)
在脚本的某些时候,我需要并行运行作业。我有一个计算机名称列表,我需要对每个计算机名称使用 psexec。这应该作为并行运行的作业来完成
Start-Job -ScriptBlock {
Log "$line Has called"
$Program_List = gc $USERS_DB_PATH\$line.txt | select -Skip 1
if (Test-Connection $line -Quiet) {
ForEach ($program in $Program_List){
Log "$line $program"
#"line $line bot is $bot pwd is $pwd"
psexec \\"$line" -u bla.local\"$bot" -p $pwd cmd bla
}
}
else{
Log "Cannot Connect to $line"
}
}
#Remove-Item "$USERS_DB_PATH\$line.txt"
}
Run Code Online (Sandbox Code Playgroud)
我知道这与范围有关,但是如何使这个脚本块看到函数 Log 和所有必要的变量?他们都空了
我的 powershell 脚本有一个 GUI。如果 C: 中的文件夹“Temp”不存在 - 创建文件夹并记录条目“Path C:\Temp 不存在 - 创建文件夹”。
这是我的代码的摘录:
$infofolder=$global:dText.AppendText("Path C:\Temp does not exist - create folder`n")
###create C:\Temp if does not exist
Invoke-Command -Session $session -ScriptBlock {
$temp= "C:\Temp"
if (!(Test-Path $temp)) {
$Using:infofolder
New-Item -Path $temp -ItemType Directory}
}
Run Code Online (Sandbox Code Playgroud)
我必须使用在 ScriptBlock 外部定义的变量,因此我使用“$Using”。但变量 $infofolder 只能在脚本块中执行。不幸的是,它之前已经执行过,这没有意义,因为当文件夹存在时也会创建日志记录条目。
我无法使用 $using:global:dText.AppendText("Path C:\Temp does not Exist - createfolder`n")。
谢谢你!!