Reputation: 53
I am trying to run the following command on multiple machines on a LAN (not on a domain). When I run without the Invoke-Command on the local machine it works perfectly. When I try to invoke, it can no longer find the file path on the machine I am running the command to as it is looking at the remote directory. I cannot get a sharedrive to function for this purpose. I had a similar question for which a hash table was suggested and successfully implemented. I cannot figure out how I would do that with the below.
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"
}
}
Upvotes: 0
Views: 2544
Reputation: 7067
One way to fix this is to deal with the data locally after it's returned instead of when and where it's being processed / gathered.
There are a few things I'm confused about. You are gathering up some string data and trying to get it into a file, then trying to get somewhat redundant other data into a second comma delimited file. Also you are missing an argument for credential.
At any rate, for my example / demo I'm going to assume we only need the CSV data.
$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.
So I'm returning custom objects that are suitable for direct output to CSV. But the key point is to emit what you want inside the script block remotely, let PowerShell return it to the local session where you can then work with it locally. If you have the data local then local file, no problem.
A few other notes mostly sugar:
Update
Responding your comments, here's an example that generates sets of files:
$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
So this is a bit different than the previous version:
ForEach-Object
loop.I realize my demo is a departure from your sample. However, I hope it demonstrates the key points and helps you get past the issue.
FYI: If you have troubles because you're environment is a workgroup, check out Secrets of PowerShell Remoting. I believe there's a section on remoting in a workgroup.
Let me know. Thanks.
Upvotes: 1
Reputation: 3158
Rachel,
Try it this way.
#--- 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
Upvotes: 1