将远程计算机上 Invoke-Command 中的 cmdlet 运行 的输出文件保存到本地文件
Save an output-file from a cmdlet run in Invoke-Command on a remote machine to a local file
我正在尝试 运行 在 LAN(而非域)上的多台计算机上执行以下命令。当我 运行 在本地机器上没有 Invoke-Command 时,它工作得很好。当我尝试调用时,它无法再在我正在 运行 命令的机器上找到文件路径,因为它正在查看远程目录。为此,我无法使用共享驱动器。我有一个类似的问题,建议并成功实施了散列 table。我不知道如何用下面的方法做到这一点。
Invoke-Command -Computername $computers -Credential {
Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName,DisplayVersion,Publisher,InstallDate,InstallLocation | Format-Table -Property DisplayName,DisplayVersion,Publisher,InstallDate,InstallLocation -AutoSize | Out-File -Width 2048 "c:\scripts\ComputerInformation\SoftwareInformation$env:COMPUTERNAME.software.txt"
$applications = Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*
foreach ($application in $applications) {
$hostname = $env:COMPUTERNAME
$DisplayName = $application.DisplayName
$displayVersion = $application.DisplayVersion
$HelpLink = $application.HelpLink
$IdentifyingNumber = $application.PSChildName
$InstallDate = $application.InstallDate
$RegOwner = $null
$vendor = $application.Publisher
if ($DisplayName -ne $null -or $DisplayVersion -ne $null -or $HelpLink -ne $null -or $IdentifyingNumber -ne $null -or $InstallDate -ne $null -or $vendor -ne $null ) {
Add-Content -Path 'c:\scripts\Inventories\SoftwareInventory.csv' "$hostname,$DisplayName,$DisplayVersion,$HelpLink,$IdentifyingNumber,$InstallDate,$RegOwner,$Vendor"
}
Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName,DisplayVersion,Publisher,InstallDate,InstallLocation | Format-Table -Property DisplayName,DisplayVersion,Publisher,InstallDate,InstallLocation -AutoSize | Out-File -Append -Width 2048 "c:\scripts\ComputerInformation\SoftwareInformation$env:COMPUTERNAME.software.txt"
$applications = Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*
foreach ($application in $applications) {
$hostname = $env:COMPUTERNAME
$DisplayName = $application.DisplayName
$displayVersion = $application.DisplayVersion
$HelpLink = $application.HelpLink
$IdentifyingNumber = $application.PSChildName
$InstallDate = $application.InstallDate
$RegOwner = $null
$vendor = $application.Publisher
if ($DisplayName -ne $null -or $DisplayVersion -ne $null -or $HelpLink -ne $null -or $IdentifyingNumber -ne $null -or $InstallDate -ne $null -or $vendor -ne $null ) {
Add-Content -Path 'c:\scripts\Inventories\SoftwareInventory.csv' "$hostname,$DisplayName,$DisplayVersion,$HelpLink,$IdentifyingNumber,$InstallDate,$RegOwner,$Vendor"
}
}
瑞秋,
这样试试。
#--- Set the path for location of NetComps.txt ---
$NetPath = "\MYBOOKLIVE\CMShared\Misc"
[Array]$Computer = Get-Content "$NetPath\NetComps.txt"
$OutPath = '\DellXPS8920\BEKDocs-DellXPS8920\Test.txt'
ForEach ($Comp in $Computer) {
$TCArgs = @{ComputerName = "$Comp"
Quiet = $True
Count = 1}
If (Test-Connection @TCArgs) {
Try {
$ICArgs = @{ComputerName = "$Comp"
ScriptBlock = {gci -Path "G:\BEKDocs\Transfer\*.*"}
ErrorAction = "Stop"
}
$x = Invoke-Command @ICArgs | Out-String
If ($x -eq "") {
Add-Content -Path "$OutPath" "Computer: $Comp - Directory Found but EMPTY"
}
Else {Add-Content -Path "$OutPath" "$x"}
}
Catch {Add-Content -Path "$OutPath" "Computer: $Comp - Directory Not Found"}
} #End If (Test...
} #End ForEach...
HTH
解决此问题的一种方法是在数据 returned 之后在本地处理数据,而不是在处理/收集数据的时间和地点。
有几件事让我感到困惑。您正在收集一些字符串数据并尝试将其放入文件中,然后尝试将有些冗余的其他数据放入第二个逗号分隔文件中。您还缺少凭证参数。
无论如何,对于我的示例/演示,我假设我们只需要 CSV 数据。
$ScriptBlock =
{
$Properties =
@(
'DisplayName'
'DisplayVersion'
'HelpLink'
'IdentifyingNumber'
'InstallDate'
'vendor'
)
Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* |
ForEach-Object{
:Inner ForEach( $Property in $Properties )
{
If( $_.$Property )
{
[PSCustomObject][Ordered]@{
hostname = $env:COMPUTERNAME
DisplayName = $_.DisplayName
DisplayVersion = $_.DisplayVersion
HelpLink = $_.HelpLink
IdentifyingNumber = $_.PSChildName
InstallDate = $_.InstallDate
RegOwner = $null
Vendor = $_.Publisher
}
Break Inner
}
}
}
}
Invoke-Command -Computername $computers -ScriptBlock $ScriptBlock |
Export-Csv -Append 'c:\scripts\Inventories\SoftwareInventory.csv' -NoTypeInformation
Note: I'm in a domain environment so I left -Credential
off.
所以我正在 returning 适合直接输出到 CSV 的自定义对象。但关键是在脚本块中远程发出你想要的东西,让 PowerShell return 将它发送到本地会话,然后你可以在本地使用它。如果你有本地数据然后本地文件,没问题。
其他一些笔记主要是糖:
- 我把脚本块放在了一个变量中。这只是我的一个偏好,我发现它更容易使用。
- 我没有使用 1 long if 条件,而是将属性存储在数组中。然后我循环数组测试每个 属性。如果有任何 属性 命中,我会发出该对象,然后中断内部循环,这样我们就不会得到重复项。我不知道你为什么首先需要 if 条件,但这似乎是一种更 eloquent 的方式。
更新
为了回应您的评论,这里有一个生成文件集的示例:
$CsvProps =
@(
'hostname'
'DisplayName'
'DisplayVersion'
'HelpLink'
'IdentifyingNumber'
'InstallDate'
'vendor'
)
$TxtProps =
@(
'DisplayName'
'DisplayVersion'
'Publisher'
'InstallDate'
'InstallLocation'
)
$ScriptBlock =
{
Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* |
ForEach-Object{
[PSCustomObject][Ordered]@{
hostname = $env:COMPUTERNAME
DisplayName = $_.DisplayName
DisplayVersion = $_.DisplayVersion
HelpLink = $_.HelpLink
IdentifyingNumber = $_.PSChildName
InstallDate = $_.InstallDate
RegOwner = $null
Vendor = $_.Publisher
Publisher = $_.Publisher
InstallLocation = $_.InstallLocation
}
}
}
$ReturnObjects = Invoke-Command -Computername $computers -ScriptBlock $ScriptBlock
# Create Textfiles for each host:
$ReturnObjects |
Group-Object -Property hostname |
ForEach-Object{
$FileName = $_.Name # This'll be the hostname, it was the group property.
$_.Group |
Format-Table $TxtProps |
Out-File -Width 2048 "c:\scripts\ComputerInformation\SoftwareInformation$FileName.software.txt"
}
# Create CSV file:
$ReturnObjects |
ForEach-Object{
:Inner ForEach( $Property in $_.PSObject.Properties.Name )
{ # Write $_ to the pipeline if any property is valid
If( $Property -eq 'hostname' ) { Continue Inner } # They will all have hostname.
ElseIf( $_.$Property )
{
$_ # Write $_ down the pipeline
Break Inner
}
}
} |
Select-Object $CsvProps |
Export-Csv 'c:\scripts\Inventories\SoftwareInventory.csv' -NoTypeInformation -Append
所以这和以前的版本有点不同:
- 脚本块中的对象具有两个所需输出所需的所有属性。
- 这与我之前提到的方法不同。我认为最好将结果存储在一个变量中,而不是尝试在 1
ForEach-Object
循环中提取两个目标。
- 脚本块中没有if逻辑。这样我们就可以取回所有对象并在本地使用它们,这样我们就可以对文本和 csv 文件进行正确的过滤。同样,为了能够在本地写入文件,我们需要本地数据。
- 由于文本文件与 CSV 文件的属性不同,因此每个文件都有不同的集合。
- 我为CSV文件过滤数据的方式不同,但原理是一样的。
我意识到我的演示与您的示例有所不同。但是,我希望它能说明要点并帮助您解决问题。
仅供参考:如果您因为环境是工作组而遇到麻烦,check out Secrets of PowerShell Remoting。我相信在工作组中有一个关于远程处理的部分。
告诉我。谢谢。
我正在尝试 运行 在 LAN(而非域)上的多台计算机上执行以下命令。当我 运行 在本地机器上没有 Invoke-Command 时,它工作得很好。当我尝试调用时,它无法再在我正在 运行 命令的机器上找到文件路径,因为它正在查看远程目录。为此,我无法使用共享驱动器。我有一个类似的问题,建议并成功实施了散列 table。我不知道如何用下面的方法做到这一点。
Invoke-Command -Computername $computers -Credential {
Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName,DisplayVersion,Publisher,InstallDate,InstallLocation | Format-Table -Property DisplayName,DisplayVersion,Publisher,InstallDate,InstallLocation -AutoSize | Out-File -Width 2048 "c:\scripts\ComputerInformation\SoftwareInformation$env:COMPUTERNAME.software.txt"
$applications = Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*
foreach ($application in $applications) {
$hostname = $env:COMPUTERNAME
$DisplayName = $application.DisplayName
$displayVersion = $application.DisplayVersion
$HelpLink = $application.HelpLink
$IdentifyingNumber = $application.PSChildName
$InstallDate = $application.InstallDate
$RegOwner = $null
$vendor = $application.Publisher
if ($DisplayName -ne $null -or $DisplayVersion -ne $null -or $HelpLink -ne $null -or $IdentifyingNumber -ne $null -or $InstallDate -ne $null -or $vendor -ne $null ) {
Add-Content -Path 'c:\scripts\Inventories\SoftwareInventory.csv' "$hostname,$DisplayName,$DisplayVersion,$HelpLink,$IdentifyingNumber,$InstallDate,$RegOwner,$Vendor"
}
Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName,DisplayVersion,Publisher,InstallDate,InstallLocation | Format-Table -Property DisplayName,DisplayVersion,Publisher,InstallDate,InstallLocation -AutoSize | Out-File -Append -Width 2048 "c:\scripts\ComputerInformation\SoftwareInformation$env:COMPUTERNAME.software.txt"
$applications = Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*
foreach ($application in $applications) {
$hostname = $env:COMPUTERNAME
$DisplayName = $application.DisplayName
$displayVersion = $application.DisplayVersion
$HelpLink = $application.HelpLink
$IdentifyingNumber = $application.PSChildName
$InstallDate = $application.InstallDate
$RegOwner = $null
$vendor = $application.Publisher
if ($DisplayName -ne $null -or $DisplayVersion -ne $null -or $HelpLink -ne $null -or $IdentifyingNumber -ne $null -or $InstallDate -ne $null -or $vendor -ne $null ) {
Add-Content -Path 'c:\scripts\Inventories\SoftwareInventory.csv' "$hostname,$DisplayName,$DisplayVersion,$HelpLink,$IdentifyingNumber,$InstallDate,$RegOwner,$Vendor"
}
}
瑞秋,
这样试试。
#--- Set the path for location of NetComps.txt ---
$NetPath = "\MYBOOKLIVE\CMShared\Misc"
[Array]$Computer = Get-Content "$NetPath\NetComps.txt"
$OutPath = '\DellXPS8920\BEKDocs-DellXPS8920\Test.txt'
ForEach ($Comp in $Computer) {
$TCArgs = @{ComputerName = "$Comp"
Quiet = $True
Count = 1}
If (Test-Connection @TCArgs) {
Try {
$ICArgs = @{ComputerName = "$Comp"
ScriptBlock = {gci -Path "G:\BEKDocs\Transfer\*.*"}
ErrorAction = "Stop"
}
$x = Invoke-Command @ICArgs | Out-String
If ($x -eq "") {
Add-Content -Path "$OutPath" "Computer: $Comp - Directory Found but EMPTY"
}
Else {Add-Content -Path "$OutPath" "$x"}
}
Catch {Add-Content -Path "$OutPath" "Computer: $Comp - Directory Not Found"}
} #End If (Test...
} #End ForEach...
HTH
解决此问题的一种方法是在数据 returned 之后在本地处理数据,而不是在处理/收集数据的时间和地点。
有几件事让我感到困惑。您正在收集一些字符串数据并尝试将其放入文件中,然后尝试将有些冗余的其他数据放入第二个逗号分隔文件中。您还缺少凭证参数。
无论如何,对于我的示例/演示,我假设我们只需要 CSV 数据。
$ScriptBlock =
{
$Properties =
@(
'DisplayName'
'DisplayVersion'
'HelpLink'
'IdentifyingNumber'
'InstallDate'
'vendor'
)
Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* |
ForEach-Object{
:Inner ForEach( $Property in $Properties )
{
If( $_.$Property )
{
[PSCustomObject][Ordered]@{
hostname = $env:COMPUTERNAME
DisplayName = $_.DisplayName
DisplayVersion = $_.DisplayVersion
HelpLink = $_.HelpLink
IdentifyingNumber = $_.PSChildName
InstallDate = $_.InstallDate
RegOwner = $null
Vendor = $_.Publisher
}
Break Inner
}
}
}
}
Invoke-Command -Computername $computers -ScriptBlock $ScriptBlock |
Export-Csv -Append 'c:\scripts\Inventories\SoftwareInventory.csv' -NoTypeInformation
Note: I'm in a domain environment so I left
-Credential
off.
所以我正在 returning 适合直接输出到 CSV 的自定义对象。但关键是在脚本块中远程发出你想要的东西,让 PowerShell return 将它发送到本地会话,然后你可以在本地使用它。如果你有本地数据然后本地文件,没问题。
其他一些笔记主要是糖:
- 我把脚本块放在了一个变量中。这只是我的一个偏好,我发现它更容易使用。
- 我没有使用 1 long if 条件,而是将属性存储在数组中。然后我循环数组测试每个 属性。如果有任何 属性 命中,我会发出该对象,然后中断内部循环,这样我们就不会得到重复项。我不知道你为什么首先需要 if 条件,但这似乎是一种更 eloquent 的方式。
更新
为了回应您的评论,这里有一个生成文件集的示例:
$CsvProps =
@(
'hostname'
'DisplayName'
'DisplayVersion'
'HelpLink'
'IdentifyingNumber'
'InstallDate'
'vendor'
)
$TxtProps =
@(
'DisplayName'
'DisplayVersion'
'Publisher'
'InstallDate'
'InstallLocation'
)
$ScriptBlock =
{
Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* |
ForEach-Object{
[PSCustomObject][Ordered]@{
hostname = $env:COMPUTERNAME
DisplayName = $_.DisplayName
DisplayVersion = $_.DisplayVersion
HelpLink = $_.HelpLink
IdentifyingNumber = $_.PSChildName
InstallDate = $_.InstallDate
RegOwner = $null
Vendor = $_.Publisher
Publisher = $_.Publisher
InstallLocation = $_.InstallLocation
}
}
}
$ReturnObjects = Invoke-Command -Computername $computers -ScriptBlock $ScriptBlock
# Create Textfiles for each host:
$ReturnObjects |
Group-Object -Property hostname |
ForEach-Object{
$FileName = $_.Name # This'll be the hostname, it was the group property.
$_.Group |
Format-Table $TxtProps |
Out-File -Width 2048 "c:\scripts\ComputerInformation\SoftwareInformation$FileName.software.txt"
}
# Create CSV file:
$ReturnObjects |
ForEach-Object{
:Inner ForEach( $Property in $_.PSObject.Properties.Name )
{ # Write $_ to the pipeline if any property is valid
If( $Property -eq 'hostname' ) { Continue Inner } # They will all have hostname.
ElseIf( $_.$Property )
{
$_ # Write $_ down the pipeline
Break Inner
}
}
} |
Select-Object $CsvProps |
Export-Csv 'c:\scripts\Inventories\SoftwareInventory.csv' -NoTypeInformation -Append
所以这和以前的版本有点不同:
- 脚本块中的对象具有两个所需输出所需的所有属性。
- 这与我之前提到的方法不同。我认为最好将结果存储在一个变量中,而不是尝试在 1
ForEach-Object
循环中提取两个目标。 - 脚本块中没有if逻辑。这样我们就可以取回所有对象并在本地使用它们,这样我们就可以对文本和 csv 文件进行正确的过滤。同样,为了能够在本地写入文件,我们需要本地数据。
- 由于文本文件与 CSV 文件的属性不同,因此每个文件都有不同的集合。
- 我为CSV文件过滤数据的方式不同,但原理是一样的。
我意识到我的演示与您的示例有所不同。但是,我希望它能说明要点并帮助您解决问题。
仅供参考:如果您因为环境是工作组而遇到麻烦,check out Secrets of PowerShell Remoting。我相信在工作组中有一个关于远程处理的部分。
告诉我。谢谢。