SMB 通常用于在网络中共享文件和打印机,但它也可以用于远程执行代码,尤其是利用命名管道(Named Pipes)来传递数据或命令。通过在远程系统上建立 SMB 会话,你可以在内存中加载、移动并执行文件或命令。

在 PowerShell 5.1 中,将脚本加载到内存中的方法有多种,涵盖了不同的需求和应用场景。以下是一些常见的方式:

1. 使用 Invoke-Expression (IEX) 执行脚本内容

Invoke-Expression 允许你从内存中执行一个字符串作为 PowerShell 命令或脚本。你可以将脚本的内容作为字符串传递给 IEX,它会将这个内容作为 PowerShell 脚本执行。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
Invoke-Expression $script

这种方法将脚本加载为字符串,并在内存中执行它。

2. 使用 Add-Content 和 Invoke-Command

通过将脚本的内容加载到内存并通过 Invoke-Command 执行,可以在远程会话或本地会话中执行脚本。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
Invoke-Command -ScriptBlock {
    $using:script
}

这里,$using: 语法允许在远程会话中引用本地变量。

3. 使用 [ScriptBlock]::Create()

PowerShell 允许使用 [ScriptBlock]::Create() 方法将脚本字符串解析为一个可执行的 ScriptBlock 对象,并将其保存在内存中。ScriptBlock 是一种可以执行的代码块对象,可以在后续通过 Invoke() 方法来执行。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
$scriptBlock = [ScriptBlock]::Create($script)
$scriptBlock.Invoke()

4. 使用 & (Call Operator)

&(Call Operator)用于执行位于变量中的脚本块。你可以将脚本块加载到内存中并通过 & 调用它。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
& { $script }

这种方法将脚本加载到内存并在当前作用域执行。

5. 通过 Add-Type 加载脚本内容

虽然 Add-Type 主要用于加载和编译 .NET 类型,但你也可以通过它加载包含 PowerShell 脚本内容的字符串,并将其转换为对象,尤其是在你需要将脚本与自定义 .NET 类型结合时。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
Add-Type -TypeDefinition $script -Language CSharp

6. 通过 System.Management.Automation.PSMethod

你可以使用 PSMethod 类将 PowerShell 脚本作为方法动态地加载到对象中。这适用于希望将脚本集成到对象的场景中。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
$psMethod = New-Object System.Management.Automation.PSMethod('ExecuteScript', [ScriptBlock]::Create($script))
$psMethod.Invoke()

7. 通过 System.Management.Automation.Runspaces 创建并执行脚本

Runspaces 是 PowerShell 中管理会话的关键对象。你可以通过创建一个 Runspace 来加载并执行脚本,这通常用于复杂的远程管理任务或多线程操作。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
$runspace = [runspacefactory]::CreateRunspace()
$runspace.Open()
$runspace.SessionStateProxy.SetVariable("script", $script)
$runspace.ExecuteCommand($script)
$runspace.Close()

8. 通过 .ps1 文件方式加载(保持内存中的内容)

尽管通常使用 .ps1 文件直接调用脚本,加载脚本并执行它时,它仍然是通过内存加载的。通过 .ps1 的引用,它会自动加载脚本到 PowerShell 会话的内存中:

powershellCopy Code
. C:\path\to\script.ps1

这是一个经典的加载和执行脚本的方式,它会将脚本内容加载到当前会话中。

9. 使用 Get-Command 与 -ScriptBlock 结合

Get-Command 用于获取脚本块的元数据,但你也可以利用它来加载脚本并在内存中运行。

powershellCopy Code
$scriptBlock = Get-Command -Name "script.ps1" | Select-Object -ExpandProperty Definition
Invoke-Expression $scriptBlock

10. 使用 -ArgumentList 参数传递脚本内容

Invoke-Command 支持通过 -ArgumentList 传递参数,你可以利用这个参数将脚本内容传递给一个本地或远程脚本块。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
Invoke-Command -ScriptBlock { & $args[0] } -ArgumentList $script

这种方法将脚本作为参数传递给脚本块执行。

PowerShell 提供了多种方法将脚本加载到内存中,每种方法根据需求不同,有不同的应用场景。你可以选择 Invoke-ExpressionScriptBlock& 调用操作符等方式来实现内存中的脚本加载和执行。具体使用哪种方法取决于任务的需求,例如是否需要动态解析、是否需要在本地或远程执行、是否要实现并行或线程处理等。

更多的方式和场景,帮助你在 PowerShell 中将脚本加载到内存并执行:

11. 使用 Runspace 来并行执行脚本

PowerShell 的 Runspace 对象允许你在并行线程中执行脚本。你可以通过 Runspace 创建新的执行环境来将脚本加载到内存中,并在多个线程中执行它。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
$runspace = [runspacefactory]::CreateRunspace()
$runspace.Open()
$runspace.SessionStateProxy.SetVariable('script', $script)

$runspace.ExecuteCommand($script)
$runspace.Close()

这种方法适用于需要在多个会话或线程中运行相同脚本的场景。

12. 通过 PowerShell 对象执行脚本

另一种方式是通过 PowerShell 对象来加载和执行脚本。可以创建一个 PowerShell 对象实例,将脚本加载进去,并通过 Invoke() 方法执行它。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
$ps = [PowerShell]::Create()
$ps.AddScript($script)
$ps.Invoke()

这种方法适用于需要通过 PowerShell 对象进行脚本执行,尤其是在调用远程计算机或跨多个 PowerShell 会话时非常有用。

13. 通过 Get-Content 和 ForEach-Object 加载并执行

你可以通过 ForEach-ObjectGet-Content 读取的脚本内容进行逐行执行,从而逐步加载并执行脚本。

powershellCopy Code
Get-Content "C:\path\to\script.ps1" | ForEach-Object { Invoke-Expression $_ }

这种方式适用于需要逐步执行脚本或处理每行脚本的特殊场景,尽管这种方式的执行效率较低,通常用于调试或逐行执行脚本时。

14. 通过 Add-Type 加载 .NET 类型并结合 PowerShell 脚本

如果你的 PowerShell 脚本需要与 .NET 类型结合,或者你想要通过 .NET 类型调用脚本,那么你可以将 PowerShell 脚本嵌入到 .NET 类型的定义中,然后执行。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
Add-Type -TypeDefinition @"
using System;
public class MyScriptClass {
    public static void Execute() {
        $script
    }
}
"@
[MyScriptClass]::Execute()

这种方式适用于需要通过 .NET 类型执行 PowerShell 脚本的复杂应用场景,例如将 PowerShell 与现有的 .NET 应用程序集成。

15. 通过 Start-Job 在后台执行脚本

Start-Job 可以在后台运行 PowerShell 脚本,而不阻塞当前会话。这种方法适用于需要在后台执行脚本的场景,例如自动化任务或异步执行脚本。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
Start-Job -ScriptBlock { Invoke-Expression $using:script }

通过这种方式,脚本在后台运行,主会话可以继续处理其他任务。

16. 通过 Run-Command 模式运行脚本

你可以通过 Run-Command 模式加载和执行脚本,尤其在与外部环境交互时。例如,如果你需要在 PowerShell 会话中直接运行某个特定命令,通常使用 Run-Command 模式。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
Run-Command -ScriptBlock { Invoke-Expression $script }

这种方法常用于需要调用系统命令或其他特定执行环境的场景。

17. 通过 New-PSSession 和 Invoke-Command 在远程主机上执行脚本

如果你需要将脚本加载到远程系统上执行,可以使用 New-PSSessionInvoke-Command 结合来执行远程脚本。首先创建一个远程会话,再使用 Invoke-Command 执行加载的脚本。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
$session = New-PSSession -ComputerName "RemoteHost"
Invoke-Command -Session $session -ScriptBlock { Invoke-Expression $using:script }
Remove-PSSession $session

这种方法适用于需要在远程计算机上执行脚本的场景。

18. 通过 Export-ModuleMember 导出模块中的脚本

如果你的脚本已经封装成 PowerShell 模块,并且你希望将脚本从模块加载到内存并执行,可以使用 Export-ModuleMember 导出脚本内容。你可以动态加载模块并执行其中的脚本。

powershellCopy Code
$modulePath = "C:\path\to\module.psm1"
Import-Module $modulePath
Export-ModuleMember -Function 'MyScriptFunction'

通过这种方式,你将模块内容加载到内存,并可以通过 Export-ModuleMember 动态调用其中的脚本。

19. 通过 Add-Command 动态注册脚本内容

你还可以通过 Add-Command 注册脚本内容为一个 PowerShell 命令,然后通过调用该命令来执行脚本。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
Add-Command -Name "MyScript" -Command { Invoke-Expression $script }
MyScript

这种方式将脚本内容作为命令动态注册并执行,适用于需要快速执行脚本的情况。

20. 通过 Start-ThreadJob 在线程中运行脚本

Start-ThreadJob 是一个并行处理的高级方法,用于在独立线程中运行脚本,这与 Start-Job 相似,但是 Start-ThreadJob 适用于较轻量级的任务,并能够利用多核 CPU 更高效地处理任务。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
Start-ThreadJob -ScriptBlock { Invoke-Expression $using:script }

这种方法非常适合需要在多个线程中并行处理任务的场景。

 

在 PowerShell 中将脚本加载到内存并执行的方法有很多。每种方法都具有不同的应用场景,选择合适的执行方式可以提升脚本执行的效率和灵活性。从简单的 Invoke-Expression 到复杂的并行执行,PowerShell 提供了丰富的工具来满足不同的需求。

更多 PowerShell 中加载和执行脚本的方法:

21. 通过 Invoke-Command 和 -ArgumentList 传递参数

如果你的脚本需要传递参数,Invoke-Command 支持使用 -ArgumentList 来将参数传递到脚本中。这样可以灵活地动态调用并执行带有参数的脚本。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
Invoke-Command -ScriptBlock { Invoke-Expression $args[0] } -ArgumentList $script

这种方法非常适用于需要将外部数据或环境变量传递给脚本的场景,特别是在自动化任务中使用。

22. 使用 Invoke-Expression 加载并执行本地或远程脚本

如果你需要在本地执行一个脚本,或者希望执行一个远程脚本,可以使用 Invoke-Expression 加载并执行脚本内容。这种方法适用于直接执行单行脚本或读取并执行文件中的脚本。

powershellCopy Code
Invoke-Expression -Command (Get-Content "C:\path\to\script.ps1" -Raw)

23. 通过 Register-ObjectEvent 监听脚本执行

Register-ObjectEvent 允许你为特定事件注册一个回调函数。在脚本中,你可以通过注册事件来响应某些动作,执行脚本时可以利用这种方式。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
$timer = New-Object System.Timers.Timer
Register-ObjectEvent -InputObject $timer -EventName Elapsed -Action { Invoke-Expression $using:script }
$timer.Start()

这种方法适用于需要基于时间或特定事件执行脚本的场景,例如定时任务或异步事件响应。

24. 通过 Invoke-WebRequest 加载远程脚本并执行

如果你需要从远程服务器下载并执行一个脚本,可以使用 Invoke-WebRequest 获取远程脚本的内容,并使用 Invoke-Expression 执行。

powershellCopy Code
$scriptUrl = "https://example.com/script.ps1"
$scriptContent = Invoke-WebRequest -Uri $scriptUrl
Invoke-Expression -Command $scriptContent.Content

这种方式适用于需要从网络上获取并执行脚本的场景,尤其是自动化部署或远程执行脚本。

25. 通过 Set-Content 保存和加载脚本

如果你希望将脚本保存到磁盘上,然后再加载和执行它,可以使用 Set-Content 保存脚本内容,再使用 Get-Content 读取并执行。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
Set-Content -Path "C:\path\to\temp_script.ps1" -Value $script
Invoke-Expression -Command (Get-Content "C:\path\to\temp_script.ps1" -Raw)

这种方法适用于需要暂存脚本文件并在稍后加载执行的场景。

26. 通过 Test-Path 检查脚本是否存在

在执行脚本之前,你可以使用 Test-Path 检查文件是否存在,以确保脚本的路径正确并避免错误。

powershellCopy Code
$scriptPath = "C:\path\to\script.ps1"
if (Test-Path $scriptPath) {
    $script = Get-Content $scriptPath -Raw
    Invoke-Expression -Command $script
} else {
    Write-Host "Script not found at $scriptPath"
}

这种方法帮助确保脚本在执行前存在,减少因文件路径问题导致的执行错误。

27. 通过 PSReadline 交互式执行脚本

如果你正在使用 PowerShell 的交互式会话,并希望通过命令行直接执行某个脚本,可以利用 PSReadline 快速执行脚本。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
[Microsoft.PowerShell.PSConsoleReadLine]::InvokeCommand("Invoke-Expression -Command $script")

这种方法特别适用于 PowerShell 控制台中交互式执行脚本或命令时的场景。

28. 通过 New-Item 创建临时脚本文件并执行

如果你希望通过创建临时文件来执行脚本,可以使用 New-Item 创建一个临时文件,并将脚本内容写入其中,随后加载并执行。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
$tempScriptPath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), "temp_script.ps1")
New-Item -Path $tempScriptPath -ItemType File -Force
Set-Content -Path $tempScriptPath -Value $script
Invoke-Expression -Command (Get-Content $tempScriptPath -Raw)
Remove-Item $tempScriptPath

这种方法适用于需要临时存储脚本并执行的场景,执行完后可删除文件。

29. 通过 Write-Output 打印脚本内容并执行

有时,你可能希望将脚本的输出或调试信息通过 Write-Output 打印出来,以便调试或日志记录。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
Write-Output "Executing script..."
Invoke-Expression -Command $script

这种方法适用于需要调试或记录执行过程的场景。

30. 通过 Out-File 将脚本输出重定向到文件

你也可以将脚本执行的结果重定向到文件中,方便后续查看或记录输出。

powershellCopy Code
$script = Get-Content "C:\path\to\script.ps1" -Raw
Invoke-Expression -Command $script | Out-File "C:\path\to\output.log"

这种方法适用于需要将执行结果保存到日志文件中的场景,便于后期查看和分析。

这些方法展示了在 PowerShell 中将脚本加载到内存并执行的多种方式。从基础的脚本加载到高级的并行执行和远程调用,每种方式都能应对不同的需求。通过灵活地选择适合的执行方法,可以提升 PowerShell 脚本的效率与可扩展性,确保脚本在不同的应用场景中都能顺利执行。


在 PowerShell 中,有一些高级和特殊的技巧,可以帮助更高效、灵活地将脚本加载到内存并执行。这些方法不仅适用于一般的脚本执行,还可以处理复杂的自动化、异步任务和高级调试。以下是一些更高阶的方法:

1. 使用 Add-Type 动态加载 .NET 程序集并执行 PowerShell 脚本

通过 Add-Type,你可以动态加载 .NET 程序集并直接在 PowerShell 中调用这些程序集。这种方法允许你在 PowerShell 中嵌入更复杂的代码逻辑,比如通过 .NET API 执行脚本。

powershellCopy Code
Add-Type -TypeDefinition @"
using System;
public class MyScriptRunner {
    public static void RunScript(string script) {
        System.Management.Automation.PowerShell.Create().AddScript(script).Invoke();
    }
}
"@
[MyScriptRunner]::RunScript("Write-Host 'Hello from PowerShell script!'")

此方法可以将 PowerShell 脚本嵌入 .NET 程序集中,进而调用和执行 PowerShell 脚本,通常用于更高级的集成应用场景。

2. 利用 Add-Content 向运行中的 PowerShell 会话动态注入代码

你可以将脚本内容动态地写入文件,并且实时注入到当前 PowerShell 会话中,这种方法允许你通过修改外部文件来控制脚本执行。

powershellCopy Code
$scriptContent = 'Write-Host "Script executed at $(Get-Date)"'
$scriptPath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), "dynamic_script.ps1")
Add-Content -Path $scriptPath -Value $scriptContent
Invoke-Expression -Command (Get-Content $scriptPath -Raw)
Remove-Item $scriptPath

通过这种方式,你可以在不修改主脚本的情况下,动态注入和执行新的 PowerShell 代码。

3. 使用 Runspace 和 RunspacePool 执行并行脚本

Runspace 是 PowerShell 的一个非常强大的功能,它允许你在多个执行上下文中并行执行脚本。通过创建多个 Runspace 实例,你可以在不同线程上并行执行多个脚本,从而提高效率。

powershellCopy Code
$runspacePool = [runspacefactory]::CreateRunspacePool(1, [Environment]::ProcessorCount)
$runspacePool.Open()

$runspace = [powershell]::Create().AddScript('Write-Host "Executing script in parallel..."')
$runspace.RunspacePool = $runspacePool
$runspace.BeginInvoke()

# 等待所有运行的任务完成
$runspacePool.Close()
$runspacePool.Dispose()

这种方法适用于需要在多个线程中并行执行多个脚本的复杂任务。它非常适用于自动化部署和批量处理任务。

4. 利用 Thread 执行脚本并避免阻塞

Thread 类允许你将脚本放入一个新的线程中执行,这样可以在后台执行脚本而不阻塞主线程。与 Runspace 不同,Thread 提供了更低级别的控制。

powershellCopy Code
$script = 'Start-Sleep -Seconds 5; Write-Host "Task completed in background."'

$thread = [System.Threading.Thread]::new({
    param($s)
    Invoke-Expression $s
}, $script)
$thread.Start()
$thread.Join()

这种方法适用于需要在后台异步执行长时间运行的脚本任务,并且不影响主线程的执行。

5. 使用 ScriptBlock.Invoke() 动态执行脚本

你可以直接使用 ScriptBlock 对象动态创建、修改并执行脚本。通过 ScriptBlock.Invoke(),你可以将脚本直接传递给 PowerShell 引擎进行执行。这种方法允许你在脚本执行时动态注入和修改脚本内容。

powershellCopy Code
$scriptBlock = {
    param($param1, $param2)
    Write-Host "Executing script with params: $param1, $param2"
}

$scriptBlock.Invoke("Param1", "Param2")

通过这种方式,你可以在脚本执行时注入参数,动态修改执行内容,并确保代码的灵活性。

6. 通过 PowerShell.Create() 创建并运行独立的 PowerShell 实例

在某些场景下,你可能需要创建一个完全独立的 PowerShell 实例来执行脚本,避免影响当前会话。你可以使用 PowerShell.Create() 方法创建新的 PowerShell 实例,并通过 AddScript()AddCommand() 向其中添加命令或脚本。

powershellCopy Code
$ps = [System.Management.Automation.PowerShell]::Create()
$ps.AddScript("Write-Host 'Hello from independent PowerShell instance.'")
$ps.Invoke()

这种方式适用于隔离脚本执行环境的需求,尤其是当你不希望脚本执行影响当前的 PowerShell 会话时。

7. 通过 System.Management.Automation.PSObject 创建自定义对象并执行

你可以通过 PSObject 对象传递特定的数据或自定义对象,动态执行包含该对象的脚本。这种方法适用于需要在脚本执行期间传递复杂数据或上下文信息的场景。

powershellCopy Code
$customObject = New-Object PSObject -property @{
    Name = "PowerShell"
    Version = "7.2"
}

$scriptBlock = {
    param($obj)
    Write-Host "Executing script for $($obj.Name) version $($obj.Version)"
}

$scriptBlock.Invoke($customObject)

这种方法适用于需要传递自定义对象作为上下文信息来执行脚本的场景。

8. 通过 Environment.SetEnvironmentVariable 修改环境变量并执行脚本

如果你需要改变环境变量并在当前会话中执行脚本,可以通过 Environment.SetEnvironmentVariable() 修改环境变量,影响脚本的执行行为。

powershellCopy Code
[System.Environment]::SetEnvironmentVariable("MY_VAR", "HelloWorld", [System.EnvironmentVariableTarget]::Process)
$script = 'Write-Host "MY_VAR is: $env:MY_VAR"'
Invoke-Expression $script

这种方法适用于需要在脚本执行期间修改环境变量,以改变脚本行为的场景。

9. 通过 WMI 或 CIM 执行远程脚本

如果你需要在远程计算机上执行脚本,可以通过 Windows Management Instrumentation (WMI) 或 CIM 提供的功能实现。这样可以实现远程脚本执行,而无需直接连接到远程主机。

powershellCopy Code
$script = 'Write-Host "Running remote script..."'
Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{CommandLine="powershell.exe -Command $script"} -ComputerName "RemoteHost"

这种方法适用于需要通过 WMI 或 CIM 协议进行远程脚本执行的场景。

以上方法展示了 PowerShell 中更高阶的脚本加载和执行技巧。通过这些方法,你不仅可以在本地执行脚本,还能利用 PowerShell 提供的多线程、并行计算、远程执行等强大功能来满足各种复杂的自动化需求。这些高级技巧为开发人员和系统管理员提供了灵活的工具来应对复杂的任务和环境配置。

深入 PowerShell 中的高级技巧,以下是更多可帮助你在处理脚本执行、自动化和并行任务时提升效率的方法。

10. 使用 ScheduledTasks 管理和自动化定时任务

如果你需要定期或在特定时间点执行脚本,可以使用 PowerShell 与 Windows 计划任务(ScheduledTasks)结合。PowerShell 提供了内建的 cmdlet 来管理和执行计划任务,使得定时执行脚本变得更加简单。

powershellCopy Code
$taskAction = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-File C:\Scripts\MyScript.ps1"
$taskTrigger = New-ScheduledTaskTrigger -Daily -At "3:00AM"
$taskSettings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
Register-ScheduledTask -Action $taskAction -Trigger $taskTrigger -Settings $taskSettings -TaskName "MyScheduledTask" -Description "Runs script daily at 3 AM"

这种方法适用于你需要自动化定期执行任务,而无需手动干预的情况。通过计划任务,可以设置复杂的时间规则、重复频率等。

11. 使用 Job 执行后台任务

PowerShell 中的后台任务(Job)可以帮助你在后台异步执行脚本或命令,这样你就可以继续在当前会话中执行其他任务,而无需等待当前任务完成。

powershellCopy Code
$job = Start-Job -ScriptBlock { 
    Write-Host "Running background task..."
    Start-Sleep -Seconds 5
    Write-Host "Background task completed"
}

# 获取任务结果
$job | Wait-Job
$job | Receive-Job

# 移除任务
Remove-Job -Job $job

这种方法适用于当你需要执行多个任务并希望它们异步执行而不阻塞主会话时,尤其适合需要长时间运行的任务。

12. 通过 Invoke-WebRequest 执行网络请求并获取脚本内容

有时你可能需要从远程服务器获取脚本内容并直接在本地执行。Invoke-WebRequest 可以帮助你从URL下载脚本,并通过 Invoke-Expression 执行。

powershellCopy Code
$url = "https://example.com/myscript.ps1"
$scriptContent = Invoke-WebRequest -Uri $url
Invoke-Expression -Command $scriptContent.Content

这对于自动化部署和脚本管理非常有效,尤其是在需要通过网络分发和执行脚本时。

13. 通过 Start-Process 启动外部进程执行脚本

如果你需要通过外部程序来执行 PowerShell 脚本,可以使用 Start-Process 启动新进程。通过该方法,你可以以新的进程身份执行脚本,并且可以捕获输出。

powershellCopy Code
Start-Process "powershell.exe" -ArgumentList "-File C:\Scripts\MyScript.ps1" -Wait -PassThru

Start-Process 方法非常适合需要在独立进程中执行脚本而不干扰当前 PowerShell 会话的场景,同时你也可以使用它来执行其他脚本或命令。

14. 使用 WebRequest 和 StreamReader 下载并执行本地脚本

如果你想将从网络获取的脚本保存在本地并随后执行,可以使用 WebRequestStreamReader 下载脚本,保存到文件系统,然后执行。

powershellCopy Code
$url = "https://example.com/myscript.ps1"
$localPath = "C:\Temp\myscript.ps1"

$webClient = New-Object System.Net.WebClient
$webClient.DownloadFile($url, $localPath)

Invoke-Expression -Command (Get-Content $localPath -Raw)

这种方法适合需要将网络上的 PowerShell 脚本保存到本地并执行的情况,通常用于批量部署或更新脚本。

15. 通过 Environment.TickCount 跟踪脚本运行时长

在复杂的脚本中,跟踪运行时长可以帮助你优化性能。可以通过 Environment.TickCount 获取系统启动以来经过的毫秒数,从而计算脚本的执行时间。

powershellCopy Code
$startTime = [System.Environment]::TickCount
# 执行你的脚本或命令
Start-Sleep -Seconds 2
$endTime = [System.Environment]::TickCount
$executionTime = $endTime - $startTime
Write-Host "Script executed in $executionTime ms"

这种方法非常适合用于性能调优和脚本优化,你可以通过记录执行时间来发现性能瓶颈。

16. 使用 New-Object 创建和操作 COM 对象

通过 New-Object,你可以创建并操作 COM 对象,这对与旧版应用程序(如 Excel、Word)进行交互非常有用。下面是一个示例,展示如何用 PowerShell 自动化 Excel 操作:

powershellCopy Code
$excel = New-Object -ComObject Excel.Application
$workbook = $excel.Workbooks.Add()
$sheet = $workbook.Sheets.Item(1)
$sheet.Cells.Item(1,1).Value = "Hello, Excel!"
$excel.Visible = $true
$workbook.SaveAs("C:\Temp\example.xlsx")
$excel.Quit()

通过这种方法,你可以利用 PowerShell 来自动化与各种 COM 应用程序的交互,提升办公自动化和数据处理的效率。

17. 通过 System.Diagnostics.Process 执行外部程序并捕获输出

System.Diagnostics.Process 提供了更低级别的控制来启动和管理外部进程。你可以通过该方法精确控制进程的输入和输出,捕获进程的标准输出、错误输出等信息。

powershellCopy Code
$process = New-Object System.Diagnostics.Process
$process.StartInfo.FileName = "powershell.exe"
$process.StartInfo.Arguments = "-Command 'Write-Host Hello from external process'"
$process.StartInfo.RedirectStandardOutput = $true
$process.Start()

$output = $process.StandardOutput.ReadToEnd()
$process.WaitForExit()

Write-Host "Captured output: $output"

这种方法适用于需要对外部程序的执行进行严格控制并获取输出的场景,通常用于更为复杂的自动化任务。

18. 使用 PSModule 和模块化脚本结构

当你的脚本变得越来越复杂时,可以考虑将其拆分成多个模块,使用 PowerShell 模块化脚本结构。通过 Export-ModuleMember 可以导出模块中的函数或变量,使得脚本更具可维护性和重用性。

powershellCopy Code
# Module.psm1
function Get-Greeting {
    return "Hello from module!"
}

Export-ModuleMember -Function Get-Greeting

然后通过 Import-Module 导入模块并使用其中的函数:

powershellCopy Code
Import-Module "C:\Scripts\Module.psm1"
Get-Greeting

这种方法适用于需要将脚本分解为多个逻辑单元并在多个项目中复用的场景。

 

以上提供了多个高级技巧和方法,旨在帮助你更高效、更灵活地编写和执行 PowerShell 脚本。无论是在本地、远程、后台任务,还是与其他系统交互时,PowerShell 的强大功能都能够提供极大的便利。掌握这些技巧后,你将能够在自动化任务、系统管理、性能优化等方面做得更加高效和精细。


在 PowerShell 5.1 环境中,Invoke-SMBRemoting 并不是 PowerShell 的内置命令,可能是自定义脚本或者是来自某些第三方模块。

在基于 SMB(Server Message Block)命名管道的情况下,你可以通过一些技巧来加载、移动并执行代码。

SMB 通常用于在网络中共享文件和打印机,但它也可以用于远程执行代码,尤其是利用命名管道(Named Pipes)来传递数据或命令。通过在远程系统上建立 SMB 会话,你可以在内存中加载、移动并执行文件或命令。

假设你在一个网络环境下有足够的权限,并且目标计算机支持 SMB,以下是基于 SMB 命名管道执行命令的一些步骤和示例:

1. 启用远程 SMB 命名管道

首先,你需要确保远程计算机允许 SMB 命名管道的连接。如果目标计算机没有启用 SMB,你需要在其上启用 SMB。

在目标计算机上运行以下 PowerShell 命令:

powershellCopy Code
Set-Service -Name "LanmanServer" -StartupType Automatic
Start-Service -Name "LanmanServer"

2. 利用 PowerShell 通过 SMB 创建共享文件夹

你可以通过 SMB 协议将文件共享到远程计算机,然后执行代码。例如,可以通过 PowerShell 脚本将文件从本地计算机传输到远程计算机共享文件夹,然后执行。

powershellCopy Code
$remoteComputer = "RemotePC"
$shareName = "SharedFolder"
$localFile = "C:\path\to\your\file.exe"
$remotePath = "\\$remoteComputer\$shareName\file.exe"

# 创建共享文件夹
New-SMBShare -Name $shareName -Path "C:\path\to\shared" -FullAccess "Everyone"

# 将文件拷贝到远程机器
Copy-Item -Path $localFile -Destination $remotePath

# 远程执行
Invoke-Command -ComputerName $remoteComputer -ScriptBlock {
    Start-Process "C:\path\to\shared\file.exe"
}

3. 基于 SMB 命名管道的远程执行

如果目标机器允许通过 SMB 命名管道远程执行代码,类似于 Windows Management Instrumentation (WMI) 或 PsExec 工具,你可以通过某些工具来执行内存加载。以下是一个常见的工具组合示例:

  • PsExec: 它可以通过 SMB 或命名管道在目标计算机上执行命令。

例如,你可以使用 PsExec 来加载并执行内存中的文件:

bashCopy Code
psexec \\RemotePC -u username -p password -c file.exe

4. 利用 PowerShell 脚本加载和执行内存中的文件

在 PowerShell 中,你还可以使用 Invoke-Expression 来执行内存中加载的代码,或者使用 IEX 来加载脚本并执行。

powershellCopy Code
$script = Get-Content "C:\path\to\file.ps1" -Raw
Invoke-Expression $script

虽然 PowerShell 5.1 中没有内置 Invoke-SMBRemoting,但你可以利用 SMB 协议以及相应的工具(如 PsExec)实现基于命名管道的文件传输、加载和执行。确保你有足够的权限,并且远程计算机配置正确。


为了进一步详细探讨如何通过 SMB 和 PowerShell 执行代码,我们可以继续关注以下几个方面:如何配置 SMB 共享,如何通过网络执行代码,以及如何利用远程 PowerShell 会话来运行脚本。

5. 使用 PowerShell 远程会话 (PS Remoting)

PowerShell Remoting 是通过 Windows PowerShell 远程管理计算机的功能。它利用 WS-Management 或 DCOM 协议进行连接。

启用 PowerShell 远程

在目标计算机上,首先需要启用 PowerShell 远程功能。如果目标计算机没有启用 PowerShell 远程管理功能,你可以运行以下命令:

powershellCopy Code
Enable-PSRemoting -Force

这将启用远程 PowerShell 会话,并确保配置正确。

使用 PowerShell 执行远程命令

一旦 PowerShell 远程会话启用,你可以使用 Invoke-Command 在远程计算机上执行命令。

powershellCopy Code
$remoteComputer = "RemotePC"
$remoteCredential = Get-Credential  # 输入目标计算机的凭据

Invoke-Command -ComputerName $remoteComputer -Credential $remoteCredential -ScriptBlock {
    # 在远程计算机上执行的脚本
    Start-Process "C:\path\to\your\file.exe"
}

如果目标计算机启用了 WinRM,并且你有适当的权限,这将执行远程命令。

6. 使用 SMB 协议执行命令

通过 SMB,你可以通过以下方法将文件传输并在目标计算机上执行。最常见的方案是将文件拷贝到共享文件夹,然后远程调用该文件。假设你已经有一个共享文件夹和目标计算机权限,可以按以下步骤操作。

共享文件夹

在目标计算机上创建一个共享文件夹:

powershellCopy Code
New-SMBShare -Name "RemoteShare" -Path "C:\SharedFolder" -FullAccess "Everyone"

将文件传输到远程共享

你可以通过 PowerShell 或者文件传输工具(如 Copy-Item)将文件从本地传输到远程计算机上的共享文件夹:

powershellCopy Code
$localFile = "C:\path\to\your\file.exe"
$remoteComputer = "RemotePC"
$remotePath = "\\$remoteComputer\RemoteShare\file.exe"

# 将文件拷贝到远程计算机
Copy-Item -Path $localFile -Destination $remotePath

在远程计算机上执行文件

一旦文件传输完成,你可以使用 PowerShell 或远程工具(如 PsExec)来执行文件。以下是使用 PowerShell 远程会话执行该文件的示例:

powershellCopy Code
Invoke-Command -ComputerName $remoteComputer -ScriptBlock {
    Start-Process "\\$remoteComputer\RemoteShare\file.exe"
} -Credential (Get-Credential)

7. 使用 PsExec 远程执行

PsExec 是一款强大的工具,可以在远程计算机上执行命令或应用程序,而无需通过远程桌面连接。它通过命名管道、SMB 或 RPC 来实现远程执行。

安装 PsExec

如果你还没有安装 PsExec,你可以从 Sysinternals 网站 下载它。安装后,你可以使用以下命令远程执行文件。

使用 PsExec 远程执行代码

假设目标计算机已启用 SMB 和远程执行权限,你可以通过 PsExec 执行代码:

bashCopy Code
psexec \\RemotePC -u username -p password -c C:\path\to\file.exe

这将把 file.exe 拷贝到目标计算机的临时目录,并在远程计算机上执行它。-u-p 参数分别指定用户名和密码。

8. 远程 PowerShell 脚本执行

另一种常见的方法是使用 PowerShell 脚本来执行远程命令或加载脚本。

通过脚本远程执行命令

你可以将 PowerShell 脚本传输到目标计算机,并通过 PowerShell 执行脚本:

powershellCopy Code
$remoteScript = "C:\path\to\remote\script.ps1"

Invoke-Command -ComputerName $remoteComputer -ScriptBlock {
    & "C:\path\to\remote\script.ps1"
} -Credential (Get-Credential)

9. 利用文件映像和内存加载执行

在一些高级场景中,您可能会将文件映像加载到目标计算机的内存中,而不是将其写入磁盘。这种技术通常依赖于工具,如 Cobalt StrikeMeterpreterEmpire 等,或者通过 PowerShell 动态加载并执行脚本。

对于 PowerShell 来说,你可以通过以下代码在内存中加载并执行脚本:

powershellCopy Code
$scriptContent = Get-Content "C:\path\to\script.ps1" -Raw
Invoke-Expression $scriptContent

这将在 PowerShell 会话的内存中执行脚本,而不需要将其写入磁盘。

在 SMB 和 PowerShell 环境中,远程执行文件和命令依赖于正确的配置和权限。无论是通过 PowerShell Remoting、SMB 文件共享、PsExec,还是直接加载脚本,你都需要确保目标计算机的配置是允许远程执行的。同时,网络安全也应该考虑到,确保只有授权用户可以执行远程命令。


10. 防火墙和网络安全配置

为了确保你的远程执行操作成功,你需要确保目标计算机的防火墙和网络配置允许所需的网络流量。不同的工具和技术会需要不同的端口开放和协议支持。以下是一些常见的要求:

远程 PowerShell 会话 (PS Remoting)

PowerShell Remoting 使用 WinRM(Windows Remote Management),它依赖于 HTTP 或 HTTPS 协议。在默认情况下,WinRM 会使用以下端口:

  • HTTP: 5985
  • HTTPS: 5986

你需要确保目标计算机的防火墙允许这些端口的传入流量。如果你的网络存在防火墙设备或公司网络安全策略,你可能需要协调网络管理员开放这些端口。

SMB 共享和远程执行

SMB(Server Message Block)协议通常使用以下端口:

  • 端口 445:用于 SMB 文件共享协议

确保目标计算机的防火墙允许来自远程主机的端口 445 流量。如果目标计算机和发起计算机处于不同的子网或通过互联网连接,确保防火墙和路由器配置允许此端口的传输。

PsExec 和远程执行

PsExec 工具依赖于 RPC(远程过程调用)和 SMB,因此,默认情况下需要以下端口:

  • 端口 135:RPC 端口
  • 端口 445:SMB 文件共享端口
  • 动态端口(49152-65535):RPC 动态分配端口

确保网络配置允许这些端口的通信,尤其是在防火墙或网络分段较多的环境下。

11. 安全性考虑和防范措施

在执行远程操作时,安全性是一个非常重要的考量。特别是在 SMB 和 PowerShell Remoting 等工具被用来执行远程命令时,确保采取适当的安全措施,以避免潜在的漏洞被恶意利用。

强化凭据和身份验证

  • 使用强密码和多因素身份验证:确保使用强密码,并启用多因素身份验证(MFA),特别是在企业网络环境中。
  • 限制凭据的使用:使用具有最小权限的账户执行远程操作,只授予必需的权限,以减少风险。
  • Kerberos 身份验证:当使用 PowerShell Remoting 和 SMB 进行远程管理时,尽量选择 Kerberos 认证,这比 NTLM 更安全。确保在网络中部署 Kerberos。

加密通讯

  • 启用 HTTPS:如果你使用 PowerShell Remoting,建议启用 HTTPS(端口 5986),通过加密的通信通道进行数据传输,保护敏感数据。
  • 启用 SMB 加密:从 Windows Server 2012 版本开始,SMB 协议支持加密。启用 SMB 加密可以确保通过 SMB 协议传输的文件数据的安全性。

监控和日志

  • 审计和日志记录:确保启用了相关的审计策略,记录所有远程操作和网络访问行为。PowerShell 和 SMB 都可以生成详细的日志,监控这些日志可以帮助检测异常活动。
  • 使用 Windows Defender 或其他防病毒软件:确保目标计算机的防病毒软件处于启用状态,能够检测和阻止潜在的恶意软件或脚本。

12. 处理远程执行失败

在进行远程执行时,可能会遇到不同的失败原因。以下是一些常见问题和解决方法:

1. 权限问题

  • 确保你在远程计算机上拥有足够的权限来执行操作。管理员权限通常是执行远程操作的基本要求。
  • 使用 Get-Credential 获取正确的凭证,或者设置 PowerShell Remoting 配置以信任目标计算机上的证书。

2. 防火墙阻止连接

  • 检查防火墙是否配置正确,并确保相应端口已打开(如 WinRM 的 5985 和 5986,SMB 的 445,RPC 的 135 和动态端口等)。
  • 如果在企业环境中,你可能需要与网络管理员协作,确保网络策略允许远程操作。

3. 网络延迟或连接问题

  • 如果网络环境较差,可能会遇到连接超时或断开的问题。可以通过调整 PowerShell Remoting 的超时时间来改善连接稳定性:
powershellCopy Code
Set-PSSessionConfiguration -Name Microsoft.PowerShell -AllowRemoteShellAccess $true -SessionConfigurationName Microsoft.PowerShell -Timeout 300
  • 如果使用 SMB 进行文件共享或执行时出现问题,确保目标计算机的文件共享设置正确,且没有其他应用程序或服务占用了所需的端口。

4. 文件传输失败

  • 确保目标计算机上已正确配置共享文件夹,并且你有足够的权限来写入和读取该文件夹。
  • 在使用 PowerShell 或 PsExec 进行文件传输时,确保源文件路径和目标路径正确。

5. 安全限制或检测机制

  • 在一些环境中,使用 SMB 或远程执行脚本时可能会被防病毒软件或入侵检测系统(IDS)拦截。确保目标计算机的安全策略允许执行所需的操作。
  • 通过设置合适的安全策略和临时禁用某些检测机制来排除干扰(请注意,操作时要确保不违反公司安全策略)。

13. 进阶应用和自动化

在复杂的环境中,远程执行任务和代码可能需要更高层次的自动化和集成。以下是一些进阶应用:

自动化远程任务调度

你可以使用 Task Scheduler 在远程计算机上定期执行任务。通过 PowerShell,你可以创建并管理远程任务调度器条目:

powershellCopy Code
Invoke-Command -ComputerName $remoteComputer -ScriptBlock {
    $Action = New-ScheduledTaskAction -Execute "C:\path\to\your\script.ps1"
    $Trigger = New-ScheduledTaskTrigger -Daily -At "3:00AM"
    Register-ScheduledTask -Action $Action -Trigger $Trigger -TaskName "RemoteTask"
}

集成到 CI/CD 流程

如果你希望将远程执行任务集成到持续集成/持续部署(CI/CD)流程中,可以使用工具如 JenkinsGitLab CIAzure DevOps 来自动化远程脚本执行。

通过将这些工具与 PowerShell 脚本结合,您可以在开发周期中自动执行远程操作,简化部署和管理。

远程执行代码通过 SMB、PowerShell、PsExec 等工具可以提高系统管理员的工作效率,尤其是在需要跨多台机器执行命令或任务时。为了确保操作安全顺利,正确配置权限、防火墙、加密和监控是至关重要的。通过这些技术的结合,您可以实现高效的远程管理和自动化执行,同时确保系统安全性和合规性。

posted @ 2025-01-14 17:37  suv789  阅读(207)  评论(0)    收藏  举报