[英]Using powershell jobs to track powershell winRM remoting NO winRM timeout
我有一个 powershell 脚本在工作,该作业运行服务器列表,远程连接到服务器并运行一个简单的脚本以从服务器获取主机名。 问题是它在某些情况下确实会卡住。 我阅读了https://4sysops.com/archives/invoke-command-compensating-for-slow-responding-computers/ 。 我遇到了可以指定超时的作业的使用。
这是我的完整脚本,目前它挂在一些主机上。
workflow Connect-windows-Servers
{
param(
[string[]]
$server_list
)
foreach -parallel -throttlelimit 50 ($server_name in $server_list){
write-output "Inside Workflow but outside inline $server_name $(Get-Date)"
InLineScript {
$output_status = "" | Select-Object -Property server_name, isError, result
$in_server_name = $using:server_name
write-output "inline = $in_server_name"
$username = "my_usersname"
$password = "my_password"
$secstr = New-Object -TypeName System.Security.SecureString
$password.ToCharArray() | foreach-object {$secstr.AppendChar($_)}
$credentials = New-Object -typename System.Management.Automation.PSCredential -argumentlist $username,$secstr
$result = Invoke-Command -ComputerName $in_server_name -ScriptBlock { [System.Net.Dns]::GetHostName() } -ErrorVariable ErrVar -Credential $credentials
write-output "Error value is $ErrVar"
if ($ErrVar)
{
$output_status.server_name = $in_server_name
$output_status.isError = $true
$output_status.result = $ErrVar
$deployment_output += New-Object -TypeName psobject -Property @{server_name = $in_server_name; isError = $true ; result = $ErrVar }
$sql_query = "insert into my_table (servername,isfailed, result) select '$in_server_name','$true','$ErrVar'"
write-output $sql_query
Invoke-Sqlcmd -ServerInstance "db_server" -Query $sql_query -Database "db_name"
}
else
{
$output_status.server_name = $in_server_name
$output_status.isError = $false
$output_status.result = $result
$deployment_output += New-Object -TypeName psobject -Property @{server_name = $in_server_name; isError = $false ; result = $result }
$sql_query = "insert into my_table (servername,isfailed, result) select '$in_server_name','$false','$result'"
write-output $sql_query
Invoke-Sqlcmd -ServerInstance "db_server" -Query $sql_query -Database "db_name"
}
}
}
}
$list = @('server1',server2)
Connect-windows-Servers -server_list $list
什么问题。
这里的问题是上面的脚本挂在某些主机上,当发生这种情况时,整个过程就会卡住。 winRM 完全没有错误,这使得自动化非常困难,代码还需要能够并行运行,因为有超过 2,000 台主机。
我做了什么?
我介绍了 powershell 个工作,但是问题是我似乎无法获得 $results 的值,我想知道的是成功连接的主机,获取主机名的值并返回主机超时,我希望能够识别它们,最重要的是使用工作流或任何其他方式并行运行它,请注意我在 powershell v5.
如果以下部分更改为
$result = Invoke-Command -ComputerName $in_server_name -ScriptBlock { [System.Net.Dns]::GetHostName() } -ErrorVariable ErrVar -Credential $credentials
$result | wait-job timeout (1*60) | Remove-Job
然后发生的事情是我失去了对特定服务器状态的跟踪,因为 $result 不再包含主机名,而且我无法确定哪些作业超时。
另一个可以使用我的原始代码片段的解决方案是,如果我可以让 winrM 正常超时,并且我是否有办法知道这种情况何时发生,以便我可以为特定主机记录它。
请忽略硬编码的用户名/密码,这不是好的做法。 当我多次运行脚本时,这种方式比多次注意提示更容易。
我会使用带有Try / Catch
的New-PSSession
和一个列表来处理代码,您可以在其中存储可能的错误。
缺点是建立连接的循环是线性的,可能需要时间。
$servers = 'host1', 'host2', 'host3'
$failed = [Collections.Generic.List[object]]::new()
$session = foreach($server in $servers) {
try {
New-PSSession $server -Credential $cred -ErrorAction Stop
}
catch {
$failed.Add([pscustomobject]@{
Server = $server
Exception = $_.ToString()
})
}
}
# Highly unlikely this could fail if you could establish a PSSession
if($session) {
Invoke-Command -SessionName $session -ScriptBlock { [System.Net.Dns]::GetHostName() }
Remove-PSSession $session
}
if($failed) {
# Has all records of failed connections with the corresponding error messages
$failed
}
如果你想要更快但更脏的东西,你可以使用重定向:
$servers = 'host1', 'host2', 'host3'
$result = Invoke-Command -ComputerName $servers -ScriptBlock {
[System.Net.Dns]::GetHostName()
} -Credential $credential -ErrorAction Continue 2>&1
$failed, $success = $result.where({ $_ -is [System.Management.Automation.ErrorRecord]}, 'Split')
$failed # => has the possible errors
$success # => has the remote results
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.