[玩转系统] PowerShell远程功能框架
作者:精品下载站 日期:2024-12-14 07:58:25 浏览:18 分类:玩电脑
PowerShell远程功能框架
前几天,我分享了一个 PowerShell 函数,用于查询远程计算机上的注册表以查找已安装的 PowerShell 版本。该函数利用 PowerShell 远程处理,灵活地使用具有可选凭据或现有 PSSession 的计算机名称。我想得越多,我就越意识到该结构可以重新用于我想在远程计算机上运行的任何命令。我认为这是使用 PowerShell 的绝佳方式。经过一些修改,我想出了所谓的远程函数框架。
该函数的大部分参数都基于您用于创建 PSSession 的参数。该函数使用会话远程运行脚本块。因为我想支持可以使用 SSH 进行远程处理的 PowerShell 7,所以我想添加必要的参数,例如主机名。这些参数仅在 PowerShell 7 上可用,因此我将它们定义为具有自己的参数集的动态参数。不过,您可以轻松地在 Param 块中定义参数。
该函数根据需要一次创建一个临时会话。我这样做是为了更好地处理异常。代码还必须考虑参数传递的值或来自管道的值。为了简化操作,我删除了 $Computername 的默认值并将其设为强制值。
要从我的框架创建您自己的命令,您真正需要做的就是定义脚本块以及您可能需要的任何可选参数。
框架功能在Github上。
RemoteFunctionFramework.ps1:
#requires -version 5.1
#TODO: DEFINE A VALID COMMAND NAME
Function Verb-Noun {
#TODO: Create help documentation for your command
[cmdletbinding(DefaultParameterSetName = "computer")]
#TODO: Add and modify parameters as necessary
Param(
[Parameter(
ParameterSetName = "computer",
Mandatory,
Position = 0,
ValueFromPipeline,
ValueFromPipelineByPropertyName,
HelpMessage = "Enter the name of a computer to query. The default is the local host."
)]
[ValidateNotNullOrEmpty()]
[Alias("cn")]
[string[]]$ComputerName,
[Parameter(
ParameterSetName = "computer",
HelpMessage = "Enter a credential object or username."
)]
[Alias("RunAs")]
[PSCredential]$Credential,
[Parameter(ParameterSetName = "computer")]
[switch]$UseSSL,
[Parameter(ParameterSetName = "computer")]
[ValidateSet("Default", "Basic", "Credssp", "Digest", "Kerberos", "Negotiate", "NegotiateWithImplicitCredentialqhel")]
[string]$Authentication = "Default",
[Parameter(
ParameterSetName = "session",
ValueFromPipeline
)]
[ValidateNotNullOrEmpty()]
[System.Management.Automation.Runspaces.PSSession[]]$Session,
[ValidateScript( {$_ -ge 0})]
[int32]$ThrottleLimit = 32
)
DynamicParam {
#Add an SSH dynamic parameter if in PowerShell 7
if ($isCoreCLR) {
$paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
#a CSV file with dynamic parameters to create
#this approach doesn't take any type of parameter validation into account
$data = @"
Name,Type,Mandatory,Default,Help
HostName,string[],1,,"Enter the remote host name."
UserName,string,0,,"Enter the remote user name."
Subsystem,string,0,"powershell","The name of the ssh subsystem. The default is powershell."
Port,int32,0,,"Enter an alternate SSH port"
KeyFilePath,string,0,,"Specify a key file path used by SSH to authenticate the user"
SSHTransport,switch,0,,"Use SSH to connect."
"@
$data | ConvertFrom-Csv | ForEach-Object -begin { } -process {
$attributes = New-Object System.Management.Automation.ParameterAttribute
$attributes.Mandatory = ([int]$_.mandatory) -as [bool]
$attributes.HelpMessage = $_.Help
$attributes.ParameterSetName = "SSH"
$attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
$attributeCollection.Add($attributes)
$dynParam = New-Object -Type System.Management.Automation.RuntimeDefinedParameter($_.name, $($_.type -as [type]), $attributeCollection)
$dynParam.Value = $_.Default
$paramDictionary.Add($_.name, $dynParam)
} -end {
return $paramDictionary
}
}
} #dynamic param
Begin {
#capture the start time. The Verbose messages can display a timespan.
$start = Get-Date
#the first verbose message uses a pseudo timespan to reflect the idea we're just starting
Write-Verbose "[00:00:00.0000000 BEGIN ] Starting $($myinvocation.mycommand)"
#a script block to be run remotely
Write-Verbose "[$(New-TimeSpan -start $start) BEGIN ] Defining the scriptblock to be run remotely."
#TODO: define the scriptblock to be run remotely
$sb = {
param([string]$VerbPref = "SilentlyContinue", [bool]$WhatPref)
$VerbosePreference = $VerbPref
$WhatIfPreference = $WhatPref
#TODO: add verbose messaging
#the timespan assumes an accurate clock on the remote computer
Write-Verbose "[$(New-TimeSpan -start $using:start) REMOTE ] Doing something remotely on $([System.Environment]::MachineName)."
"[$([System.Environment]::MachineName)] Hello, World"
} #scriptblock
#parameters to splat to Invoke-Command
Write-Verbose "[$(New-TimeSpan -start $start) BEGIN ] Defining parameters for Invoke-Command."
#TODO: Update arguments as needed. This framework assumes any arguments are NOT coming through the pipeline and will be the same for all remote computers
#TODO: You will need to handle parameters like -WhatIf that you want to pass remotely
$icmParams = @{
Scriptblock = $sb
Argumentlist = $VerbosePreference, $WhatIfPreference
HideComputerName = $False
ThrottleLimit = $ThrottleLimit
ErrorAction = "Stop"
Session = $null
}
#initialize an array to hold session objects
[System.Management.Automation.Runspaces.PSSession[]]$All = @()
If ($Credential.username) {
Write-Verbose "[$(New-TimeSpan -start $start) BEGIN ] Using alternate credential for $($credential.username)."
}
} #begin
Process {
Write-Verbose "[$(New-TimeSpan -start $start) PROCESS] Detected parameter set $($pscmdlet.ParameterSetName)."
Write-Verbose "[$(New-TimeSpan -start $start) PROCESS] Detected PSBoundParameters:`n$($PSBoundParameters | Out-String)"
$remotes = @()
if ($PSCmdlet.ParameterSetName -match "computer|ssh") {
if ($pscmdlet.ParameterSetName -eq 'ssh') {
$remotes += $PSBoundParameters.HostName
$param = "HostName"
}
else {
$remotes += $PSBoundParameters.ComputerName
$param = "ComputerName"
}
foreach ($remote in $remotes) {
$PSBoundParameters[$param] = $remote
$PSBoundParameters["ErrorAction"] = "Stop"
Try {
#create a session one at a time to better handle errors
Write-Verbose "[$(New-TimeSpan -start $start) PROCESS] Creating a temporary PSSession to $remote."
#save each created session to $tmp so it can be removed at the end
#TODO: If your function will add parameters they will need to be removed from $PSBoundParamters or you will need to adjust the the command to create the New-PSSession
$all += New-PSSession @PSBoundParameters -OutVariable +tmp
} #Try
Catch {
#TODO: Decide what you want to do when the new session fails
Write-Warning "Failed to create session to $remote. $($_.Exception.Message)."
#Write-Error $_
} #catch
} #foreach remote
}
Else {
#only add open sessions
foreach ($sess in $session) {
if ($sess.state -eq 'opened') {
Write-Verbose "[$(New-TimeSpan -start $start) PROCESS] Using session for $($sess.ComputerName.toUpper())."
$all += $sess
} #if open
} #foreach session
} #else sessions
} #process
End {
$icmParams["session"] = $all
Try {
Write-Verbose "[$(New-TimeSpan -start $start) END ] Querying $($all.count) computers."
Invoke-Command @icmParams | ForEach-Object {
#TODO: PROCESS RESULTS FROM EACH REMOTE CONNECTION IF NECESSARY
$_
} #foreach result
} #try
Catch {
Write-Error $_
} #catch
if ($tmp) {
Write-Verbose "[$(New-TimeSpan -start $start) END ] Removing $($tmp.count) temporary PSSessions."
$tmp | Remove-PSSession
}
Write-Verbose "[$(New-TimeSpan -start $start) END ] Ending $($myinvocation.mycommand)"
} #end
} #close function
我留下了一些#TODO 评论来指导您需要进行的更改。作为概念证明,这里有一个终止远程计算机上进程的函数。
Stop-RemoteProcess.ps1:
#requires -version 5.1
Function Stop-RemoteProcess {
#TODO: Create help documentation
[cmdletbinding(DefaultParameterSetName = "computer")]
Param(
[Parameter(
ParameterSetName = "computer",
Mandatory,
Position = 0,
ValueFromPipeline,
ValueFromPipelineByPropertyName,
HelpMessage = "Enter the name of a computer to query. The default is the local host."
)]
[ValidateNotNullOrEmpty()]
[Alias("cn")]
[string[]]$ComputerName,
[Parameter(
ParameterSetName = "computer",
HelpMessage = "Enter a credential object or username."
)]
[Alias("RunAs")]
[PSCredential]$Credential,
[Parameter(ParameterSetName = "computer")]
[switch]$UseSSL,
[Parameter(
ParameterSetName = "session",
ValueFromPipeline
)]
[ValidateNotNullOrEmpty()]
[System.Management.Automation.Runspaces.PSSession[]]$Session,
[ValidateScript( {$_ -ge 0})]
[int32]$ThrottleLimit = 32,
[Parameter(Mandatory,HelpMessage = "Specify the process to stop.")]
[ValidateNotNullOrEmpty()]
[string]$ProcessName,
[Parameter(HelpMessage = "Write the stopped process to the pipeline")]
[switch]$Passthru,
[Parameter(HelpMessage = "Run the remote command with -WhatIf")]
[switch]$WhatIfRemote
)
DynamicParam {
#Add an SSH dynamic parameter if in PowerShell 7
if ($isCoreCLR) {
$paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
#a CSV file with dynamic parameters to create
#this approach doesn't take any type of parameter validation into account
$data = @"
Name,Type,Mandatory,Default,Help
HostName,string[],1,,"Enter the remote host name."
UserName,string,0,,"Enter the remote user name."
Subsystem,string,0,"powershell","The name of the ssh subsystem. The default is powershell."
Port,int32,0,,"Enter an alternate SSH port"
KeyFilePath,string,0,,"Specify a key file path used by SSH to authenticate the user"
SSHTransport,switch,0,,"Use SSH to connect."
"@
$data | ConvertFrom-Csv | ForEach-Object -begin { } -process {
$attributes = New-Object System.Management.Automation.ParameterAttribute
$attributes.Mandatory = ([int]$_.mandatory) -as [bool]
$attributes.HelpMessage = $_.Help
$attributes.ParameterSetName = "SSH"
$attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
$attributeCollection.Add($attributes)
$dynParam = New-Object -Type System.Management.Automation.RuntimeDefinedParameter($_.name, $($_.type -as [type]), $attributeCollection)
$dynParam.Value = $_.Default
$paramDictionary.Add($_.name, $dynParam)
} -end {
return $paramDictionary
}
}
} #dynamic param
Begin {
#capture the start time. The Verbose messages can display a timespan.
$start = Get-Date
#the first verbose message uses a pseudo timespan to reflect the idea we're just starting
Write-Verbose "[00:00:00.0000000 BEGIN ] Starting $($myinvocation.mycommand)"
#a script block to be run remotely
Write-Verbose "[$(New-TimeSpan -start $start) BEGIN ] Defining the scriptblock to be run remotely"
$sb = {
param([string]$ProcessName,[bool]$Passthru,[string]$VerbPref = "SilentlyContinue", [bool]$WhatPref)
$VerbosePreference = $VerbPref
$WhatIfPreference = $WhatPref
Try {
Write-Verbose "[$(New-TimeSpan -start $using:start) REMOTE ] Getting Process $ProcessName on $([System.Environment]::MachineName)"
$procs = Get-Process -Name $ProcessName -ErrorAction stop
Try {
Write-Verbose "[$(New-TimeSpan -start $using:start) REMOTE ] Stopping $($procs.count) Processes on $([System.Environment]::MachineName)"
$procs | Stop-Process -ErrorAction Stop -PassThru:$Passthru
}
Catch {
Write-Warning "[$(New-TimeSpan -start $using:start) REMOTE ] Failed to stop Process $ProcessName on $([System.Environment]::MachineName). $($_.Exception.message)."
}
}
Catch {
Write-Verbose "[$(New-TimeSpan -start $using:start) REMOTE ] Process $ProcessName not found on $([System.Environment]::MachineName)"
}
} #scriptblock
#parameters to splat to Invoke-Command
Write-Verbose "[$(New-TimeSpan -start $start) BEGIN ] Defining parameters for Invoke-Command"
#remove my parameters from PSBoundparameters because they can't be used with New-PSSession
$myparams = "ProcessName","WhatIfRemote","passthru"
foreach ($my in $myparams) {
if ($PSBoundParameters.ContainsKey($my)) {
[void]($PSBoundParameters.remove($my))
}
}
$icmParams = @{
Scriptblock = $sb
#I added the relevant parameters from the function
Argumentlist = @($ProcessName,$Passthru,$VerbosePreference,$WhatIfRemote)
HideComputerName = $False
ThrottleLimit = $ThrottleLimit
ErrorAction = "Stop"
Session = $null
}
#initialize an array to hold session objects
[System.Management.Automation.Runspaces.PSSession[]]$All = @()
If ($Credential.username) {
Write-Verbose "[$(New-TimeSpan -start $start) BEGIN ] Using alternate credential for $($credential.username)"
}
} #begin
Process {
Write-Verbose "[$(New-TimeSpan -start $start) PROCESS] Detected parameter set $($pscmdlet.ParameterSetName)."
#Write-Verbose "[$(New-TimeSpan -start $start) PROCESS] Detected PSBoundParameters:`n$($PSBoundParameters | Out-String)"
$remotes = @()
if ($PSCmdlet.ParameterSetName -match "computer|ssh") {
if ($pscmdlet.ParameterSetName -eq 'ssh') {
$remotes += $PSBoundParameters.HostName
$param = "HostName"
}
else {
$remotes += $PSBoundParameters.ComputerName
$param = "ComputerName"
}
foreach ($remote in $remotes) {
$PSBoundParameters[$param] = $remote
$PSBoundParameters["ErrorAction"] = "Stop"
Try {
#create a session one at a time to better handle errors
Write-Verbose "[$(New-TimeSpan -start $start) PROCESS] Creating a temporary PSSession to $remote"
#save each created session to $tmp so it can be removed at the end
#TODO: If your function will add parameters they will need to be removed from $PSBoundParamters or you will need to adjust the the command to create the New-PSSession
$all += New-PSSession @PSBoundParameters -OutVariable +tmp
} #Try
Catch {
#TODO: Decide what you want to do when the new session fails
Write-Warning "Failed to create session to $remote. $($_.Exception.Message)."
#Write-Error $_
} #catch
} #foreach remote
}
Else {
#only add open sessions
foreach ($sess in $session) {
if ($sess.state -eq 'opened') {
Write-Verbose "[$(New-TimeSpan -start $start) PROCESS] Using session for $($sess.ComputerName.toUpper())"
$all += $sess
} #if open
} #foreach session
} #else sessions
} #process
End {
$icmParams["session"] = $all
Try {
Write-Verbose "[$(New-TimeSpan -start $start) END ] Querying $($all.count) computers"
Invoke-Command @icmParams | ForEach-Object {
#TODO: PROCESS RESULTS FROM EACH REMOTE CONNECTION IF NECESSARY
$_
} #foreach result
} #try
Catch {
Write-Error $_
} #catch
if ($tmp) {
Write-Verbose "[$(New-TimeSpan -start $start) END ] Removing $($tmp.count) temporary PSSessions"
$tmp | Remove-PSSession
}
Write-Verbose "[$(New-TimeSpan -start $start) END ] Ending $($myinvocation.mycommand)"
} #end
} #close function
当您查看代码时,您可以看到我如何处理远程脚本块所需的参数。包括对 -WhatIf 的支持。按照我写的方式,$PSBoundParameters 会被分配到 New-PSSession,因此您需要删除已添加的任何不属于的内容。您可以在代码中看到我是如何做到这一点的。
几分钟之内我就得到了一个功能齐全的命令。
它也是这样工作的。
我很期待看到我还能用这个框架做些什么。我很想听听你如何使用它。享受。
猜你还喜欢
- 03-30 [玩转系统] 如何用批处理实现关机,注销,重启和锁定计算机
- 02-14 [系统故障] Win10下报错:该文件没有与之关联的应用来执行该操作
- 01-07 [系统问题] Win10--解决锁屏后会断网的问题
- 01-02 [系统技巧] Windows系统如何关闭防火墙保姆式教程,超详细
- 12-15 [玩转系统] 如何在 Windows 10 和 11 上允许多个 RDP 会话
- 12-15 [玩转系统] 查找 Exchange/Microsoft 365 中不活动(未使用)的通讯组列表
- 12-15 [玩转系统] 如何在 Windows 上安装远程服务器管理工具 (RSAT)
- 12-15 [玩转系统] 如何在 Windows 上重置组策略设置
- 12-15 [玩转系统] 如何获取计算机上的本地管理员列表?
- 12-15 [玩转系统] 在 Visual Studio Code 中连接到 MS SQL Server 数据库
- 12-15 [玩转系统] 如何降级 Windows Server 版本或许可证
- 12-15 [玩转系统] 如何允许非管理员用户在 Windows 中启动/停止服务
取消回复欢迎 你 发表评论:
- 精品推荐!
-
- 最新文章
- 热门文章
- 热评文章
[影视] 黑道中人 Alto Knights(2025)剧情 犯罪 历史 电影
[古装剧] [七侠五义][全75集][WEB-MP4/76G][国语无字][1080P][焦恩俊经典]
[实用软件] 虚拟手机号 电话 验证码 注册
[电视剧] 安眠书店/你 第五季 You Season 5 (2025) 【全10集】
[电视剧] 棋士(2025) 4K 1080P【全22集】悬疑 犯罪 王宝强 陈明昊
[软件合集] 25年6月5日 精选软件22个
[软件合集] 25年6月4日 精选软件36个
[短剧] 2025年06月04日 精选+付费短剧推荐33部
[短剧] 2025年06月03日 精选+付费短剧推荐25部
[软件合集] 25年6月3日 精选软件44个
[剧集] [央视][笑傲江湖][2001][DVD-RMVB][高清][40集全]李亚鹏、许晴、苗乙乙
[电视剧] 欢乐颂.5部全 (2016-2024)
[电视剧] [突围] [45集全] [WEB-MP4/每集1.5GB] [国语/内嵌中文字幕] [4K-2160P] [无水印]
[影视] 【稀有资源】香港老片 艺坛照妖镜之96应召名册 (1996)
[剧集] 神经风云(2023)(完结).4K
[剧集] [BT] [TVB] [黑夜彩虹(2003)] [全21集] [粤语中字] [TV-RMVB]
[实用软件] 虚拟手机号 电话 验证码 注册
[资源] B站充电视频合集,包含多位重量级up主,全是大佬真金白银买来的~【99GB】
[影视] 内地绝版高清录像带 [mpg]
[书籍] 古今奇书禁书三教九流资料大合集 猎奇必备珍藏资源PDF版 1.14G
[电视剧] [突围] [45集全] [WEB-MP4/每集1.5GB] [国语/内嵌中文字幕] [4K-2160P] [无水印]
[剧集] [央视][笑傲江湖][2001][DVD-RMVB][高清][40集全]李亚鹏、许晴、苗乙乙
[电影] 美国队长4 4K原盘REMUX 杜比视界 内封简繁英双语字幕 49G
[电影] 死神来了(1-6)大合集!
[软件合集] 25年05月13日 精选软件16个
[精品软件] 25年05月15日 精选软件18个
[绝版资源] 南与北 第1-2季 合集 North and South (1985) /美国/豆瓣: 8.8[1080P][中文字幕]
[软件] 25年05月14日 精选软件57个
[短剧] 2025年05月14日 精选+付费短剧推荐39部
[短剧] 2025年05月15日 精选+付费短剧推荐36部
- 最新评论
-
- 热门tag