I am attempting to export the installed version of Chrome for workstations on our network. I have put together the following script but am running into an issue with an error exporting to CSV.
Any suggestions would be greatly appreciated.
Select-Object : Cannot convert System.Diagnostics.FileVersionInfo to one of the following types {System.String, System.Management.Automation.ScriptBlock}.
At line:22 char:14
Select-Object $computer, $Version | export-csv -Path c:\ ...
CategoryInfo : InvalidArgument: (:) [Select-Object], NotSupportedException
FullyQualifiedErrorId : DictionaryKeyUnknownType,Microsoft.PowerShell.Commands.SelectObjectCommand
$computerlist = get-content C:\temp\computerlist.txt
foreach ($computer in $computerlist){
$test = 1
Write-Host "Testing connection to $computer..." -ForegroundColor Magenta
Try{
Test-Connection -Count 1 -ComputerName $computer -ErrorAction Stop | out-null
Write-Host "Connected!" -ForegroundColor Green
}
Catch{
Write-Host "Could not connect to $computer" -BackgroundColor Red -ForegroundColor Black
$test = 0
$computer | out-file c:\temp\badlist.txt
}
If ($test -eq 1){
ForEach($computer in $computerlist){
$computer = $computer
$Version = (Get-Item (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\chrome.exe').'(Default)').VersionInfo
"$computer - $Version"
Out-String -InputObject $Version
Select-Object $computer, $Version | export-csv -Path c:\temp\Chromeversion$($date)-PS.csv -NoTypeInformation -Append
Select-Object $computer, $Version
doesn't work as intended, because Select-Object expects property names (or calculated properties) as the (positionally implied) -Property argument.
You're passing values, which are interpreted as names, and an instance of System.Diagnostics.FileVersionInfo (the type of the value stored in $Version) isn't accepted as a name, which is what the error message indicates.
To get what you want, construct a [pscustomobject] as follows:
[pscustomobject] #{ Computer = $computer; Version = $Version } |
Export-Csv -Path c:\temp\Chromeversion$($date)-PS.csv -NoTypeInformation -Append
Related
I am trying to get details of OS Name and .net framework details for multiple servers using PowerShell script below.
$servers = Get-Content -Path "C:\Users\vinay\Desktop\servers.txt"
Foreach ($s in $servers)
{
write-host $s
$s.PSDrive
$s.PSChildName
Add-Content C:\Users\vinay\Desktop\specs.txt "Specs:"
$OS = (Get-WmiObject Win32_OperatingSystem).CSName
Add-Content C:\Users\vinay\Desktop\specs.txt "`nOS:$OS"
$Bit = (Get-WMIObject win32_operatingsystem).name
Add-Content C:\Users\vinay\Desktop\specs.txt "`nOS Bit: $Bit"
$name = (Get-WmiObject Win32_OperatingSystem).OSArchitecture
Add-Content C:\Users\vinay\Desktop\specs.txt "`nServer Name: $name"
$dotnet = Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -Recurse | Get-ItemProperty -Name version -EA 0 | Where { $_.PSChildName -Match '^(?!S)\p{L}'} | Select PSChildName, version
Add-Content C:\Users\vinay\Desktop\specs.txt "`n.NET VERSION $dotnet"
$release = (Get-ItemProperty "HKLM:SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full").Release
Add-Content C:\Users\vinay\Desktop\specs.txt "`nRelease number: $release"
Add-Content C:\Users\vinay\Desktop\specs.txt "`n----------------------------"
}
But i am getting details of the server in which i am running the script but not for other servers in the text file.
however write-host $s reads all the servers in the text file. Please help where i am doing wrong.
Continuing from my comment, you need to perform your code looping over the servers in your list and have that code run on that server instead of your own machine you are running the script from.
Also, I would have the code output objects instead of trying to add lines to a text file, so that you ca save the results in a structured format like CSV.
Try
$servers = Get-Content -Path "C:\Users\vinay\Desktop\servers.txt"
$specs = foreach ($s in $servers) {
if (Test-Connection -ComputerName $s -Count 1 -Quiet) {
Write-Host "Probing server $s"
# you may need to add parameter -Credential and supply the credentials
# of someone with administrative permissions on the server
Invoke-Command -ComputerName $s -ScriptBlock {
$os = (Get-CimInstance -ClassName Win32_OperatingSystem)
Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -Recurse |
Get-ItemProperty -Name Version, Release -Erroraction SilentlyContinue |
Where-Object { $_.PSChildName -Match '^(?!S)\p{L}'} |
ForEach-Object {
[PsCustomObject]#{
'ComputerName' = $os.CSName
'Operating System' = $os.Caption
'Architecture' = $os.OSArchitecture
'Net Version' = [version]$_.Version
'Net Framework' = $_.PsChildName
'Net Release' = $_.Release
}
}
}
}
else {
Write-Warning "Computer '$s' cannot be reached.."
}
}
# remove extra properties PowerShell added
$specs = $specs | Select-Object * -ExcludeProperty PS*, RunspaceId
# output on screen
$specs | Format-Table -AutoSize
# output to CSV file you can open in Excel
$specs | Export-Csv -Path 'C:\Users\vinay\Desktop\specs.csv' -UseCulture -NoTypeInformation
Below is a script I'm working on to get all SQL-jobs into a CSV-file.
The script itself is working great but I have trouble with the error-handling.
I can't figure out how to get the Out-File inside the Catch-block to print to the file on my local machine instead of the remote machine I'm running the Invoke-Command to.
How do I accomplish this?
Thanks
PS. The script is written out fully as much as possible for non experienced co-workers convenience
$sqlServers = #("TEST1","TEST2")
$filePath = [Environment]::GetFolderPath("Desktop")
$dateToday = Get-Date -Format “yyMMdd HH:mm"
$dateTodayFile = Get-Date -Format “yyMMdd"
Write-Output "$dateToday $sqlServers" |
Out-File "$filePath\Log$dateTodayFile.txt" -Append
$output = Invoke-Command -ComputerName $sqlServers -ScriptBlock{
Try
{
Import-Module sqlserver -ErrorAction Stop
}
Catch
{
Write-Output "$dateToday ERROR $env:computername" |
Out-File "$filePath\Log$dateTodayFile.txt" -Append
Exit
}
$instances = $env:computername | Foreach-Object {Get-ChildItem -Path "SQLSERVER:\SQL\$_"}
ForEach ($instance in $instances){
Try
{
$instanceName = $instance.InstanceName
Get-SqlAgentJob -ServerInstance "$env:computername\$instanceName" -ErrorAction Stop |
Where-Object {$_.IsEnabled -eq "True" -and $_.LastRunDate -gt [DateTime]::Today.AddDays(-2) -and $_.OwnerLoginName -match "TEST"} |
Select-Object #{Name=‘Job name‘;Expression={$_.Name}},
#{Name=‘Description‘;Expression={$_.Description}},
#{Name=‘Instance‘;Expression={$_.Parent -Replace '[][]'}},
#{Name=‘Run outcome‘;Expression={$_.LastRunOutcome}},
#{Name=‘Run date‘;Expression={$_.LastRunDate}},
#{Name=‘Run duration‘;Expression={$_.LastRunDuration}},
#{Name=‘Job creator‘;Expression={$_.OwnerLoginName}},
#{Name=‘Runs on a schedule‘;Expression={$_.HasSchedule}},
#{Name='Schedule Type';Expression={$_.JobSchedules -join ','}}
}
Catch
{
Write-Output "$dateToday ERROR $env:computername\$instanceName" |
Out-File "$filePath\Log$dateTodayFile.txt" -Append
Exit
}
}
}
$output | Select-Object -Property * -ExcludeProperty PSComputerName,RunSpaceID,PSShowComputerName |
Sort-Object "Job name" |
Export-Csv $filePath\SQLJobInvent$dateTodayFile.csv -NoTypeInformation -Delimiter ";" -Encoding UTF8
Write-Output "$dateToday $filePath" |
Out-File "$filePath\Log$dateTodayFile.txt" -Append
Write-Output "----------------------------------------" |
Out-File "$filePath\Log$dateTodayFile.txt" -Append
Your primary issue is scope.
The $dateToday, $filePath and $dateTodayFile are all declared on the local machine, but you're trying to use them on the remote computer (script block) where they are undefined.
There are a few ways to get your variables passed to the remote computer, below are two:
# Add desired variable to ArgumentList and define it as a parameter
Invoke-Command -ComputerName $sqlServers -ArgumentList $dateToday,$filePath,$dateTodayFile -ScriptBlock {
param(
$folderPath,
$filePath,
$dateTodayFile
)
# Do something with our injected variables
Write-Output "$dateToday ERROR $env:computername" |
Out-File "$filePath\Log$dateTodayFile.txt" -Append
}
OR
# In PS ver >= 3.0 we can use 'using'
Invoke-Command -ComputerName $serverName -ScriptBlock {Write-Output $using:dateToday}
I'm trying to filter out computers that have already ran the script (that enables remote registry service) within AD from a list in a text file
$NamesFromFile = Get-Content
C:\scripts\Inventory\offlineRemoteRegStartupWorkstations.txt
$computers = get-adcomputer -Filter * | Where-Object {
$_.Name.SubString(1) -in $NamesFromFile }
foreach ($computer in $computers)
{
if (Test-Connection -count 1 -computer $computer.Name -quiet){
Write-Host "Updating system" $computer.Name "....." -ForegroundColor
Green
Set-Service –Name remoteregistry –Computer $computer.Name -StartupType
Automatic
Get-Service remoteregistry -ComputerName $computer.Name | start-service
}
else
{
Write-Host "System Offline " $computer.Name "....." -ForegroundColor Red
echo $computer.Name >> C:\scripts\Inventory\offlineRemoteRegStartup.txt}
}
no errors just blank
Below a re-write of your script.
Because you test if only the first character of the computer name is in the list of computers, your $computers variable will remain empty, so nothing happens.
Also, I think it would be wise to add a check if the startup type of the RemoteRegistry service is not already set to Automatic, because after all.. the computernames you read in from the file may not be accurate.
To avoid having to use $computer.Name all the time, I use a Select-Object -ExpandProperty Name, so we only have to run through a list of strings.
$NamesFromFile = Get-Content -Path 'C:\scripts\Inventory\offlineRemoteRegStartupWorkstations.txt' | Sort-Object -Unique
Get-ADComputer -Filter * |
Where-Object { $NamesFromFile -contains $_.Name } | # if the computer name is in the list
Select-Object -ExpandProperty Name | # we're only interested in the Name property
ForEach-Object {
# the automatic variable '$_' represents a single computername from the list
if (Test-Connection -Count 1 -ComputerName $_ -Quiet) {
# test if the RemoteRegistry service startup type is not already Automatic
# you can do the same with (Get-WmiObject -Class Win32_Service -Filter "Name='RemoteRegistry'" -ComputerName $_)
# only slower..
if ((Get-CimInstance -Class Win32_Service -Filter "Name='RemoteRegistry'" -ComputerName $_).StartMode -ne 'Auto') {
Write-Host "Updating system '$_'....." -ForegroundColor Green
Set-Service –Name RemoteRegistry –Computer $_ -StartupType Automatic
Get-Service -Name RemoteRegistry –Computer $_ | Start-Service
}
else {
Write-Host "RemoteRegistry service startup type already Automatic on computer '$_'....." -ForegroundColor Yellow
}
}
else {
Write-Host "System Offline '$_'....." -ForegroundColor Red
Add-Content -Path 'C:\scripts\Inventory\offlineRemoteRegStartup.txt' -Value $_
}
}
I'm on a Windows server 2008 R2 and I need an extract of the local profile list, so I use Powershell to look into the registry and get what I want :
$path = 'Registry::HKey_Local_Machine\Software\Microsoft\Windows NT\CurrentVersion\ProfileList\*'
$items = Get-ItemProperty -path $path
Foreach ($item in $items) {
$objUser = New-Object
System.Security.Principal.SecurityIdentifier($item.PSChildName)
$objName = $objUser.Translate([System.Security.Principal.NTAccount])
$item.PSChildName = $objName.value
}
echo $items | Select-Object -Property PSChildName | Export-Csv
C:\scripts\PSScripts\UserProfile.csv -Encoding UTF8
It worked with another machine using Windows Server 2012 R2 but here I got a lot of errors, but always the same one :
Exception calling "Translate" with "1" argument(s): "Some or all
identity references could not be translated." At
C:\scripts\PSScripts\users_profile.ps1:5 char:34
+ $objName = $objUser.Translate <<<< ([System.Security.Principal.NTAccount])
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
The .csv file is created but with issues, like a profile shown more than one time, like this :
DOMAIN\User1
DOMAIN\User2
DOMAIN\User3
DOMAIN\User3
DOMAIN\User4
DOMAIN\User5
DOMAIN\User5
DOMAIN\User5
DOMAIN\User6
Is there a difference between WS2008 and WS2012 which can cause this problem? Or is it something else?
I'd suggest using WMI to be consistent across platforms plus some error handling:
$path = 'C:\scripts\PSScripts\UserProfile.csv'
Get-CimInstance -ClassName Win32_UserProfile -Filter Special=FALSE -PipelineVariable user |
ForEach-Object -Begin {$ErrorActionPreference = 'Stop'} {
try
{
$id = [System.Security.Principal.SecurityIdentifier]::new($user.SID)
$id.Translate([System.Security.Principal.NTAccount]).Value
}
catch
{
Write-Warning -Message "Failed to translate $($user.SID)! $PSItem"
}
} |
Select-Object -Property #{Label='PSChildName'; Expression={$PSItem}} |
Export-Csv -Path $path -Encoding ascii -NoTypeInformation
PSv2 solution:
Get-WmiObject -Class Win32_UserProfile -Filter Special=FALSE |
ForEach-Object -Begin {$ErrorActionPreference = 'Stop'} {
try
{
$sid = $_.SID
$id = New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList $sid
$id.Translate([System.Security.Principal.NTAccount]).Value
}
catch
{
Write-Host "Failed to translate $sid! $_" -ForegroundColor Red
}
} |
Select-Object -Property #{Label='PSChildName'; Expression={$_}} |
Export-Csv -Path $path -Encoding ascii -NoTypeInformation
I have the following function that works correctly in 2012r2, when i run it in 2008R2 it throws the below error. The surprising thing is that if i execute it a second time, it works without any issue!!
# Function Reg-Stamp {
Param(
[Parameter(Mandatory=$True)]
[string]$Phase
)
$msg = "`nEntering: $((Get-Variable MyInvocation -Scope 0).Value.MyCommand.Name)" ; Write-Host -fore Gray $msg ; $msg | out-file -Append $log
$RegStampInfo = Build-Variable $RegStampCSV
$Version = ($ScriptVersionInfo | Where-Object {$_.Parameter -eq "Version" -and $_.Phase -eq $Phase }).Value
$DisplayName = ($ScriptVersionInfo | Where-Object {$_.Parameter -eq "DisplayName" -and $_.Phase -eq $Phase }).Value
$BuildDate = ($ScriptVersionInfo | Where-Object {$_.Parameter -eq "BuildDate" -and $_.Phase -eq $Phase }).Value
$RunDate = Get-Date
$Success = $(-not($CriticalError))
$msg = "`nUpdating registry with build information"; Write-Host -fore Gray $msg; $msg | out-file $log -Append;
$RegStampInfo | Where-Object {($_.Phase.ToLower()) -eq ($Phase.ToLower())} | foreach-Object {
$ValueData = $(get-variable -Name $($_.StampData) -ValueOnly -ErrorAction SilentlyContinue)
$msg = "Adding Key: $($_.StampKey) '$($_.StampValue)' '$ValueData'"; Write-Host -fore Green "$msg"; $msg | out-file $log -Append;
New-Item -Path $($_.StampKey) -ErrorAction SilentlyContinue
Set-ItemProperty -Path $_.StampKey -name $_.StampValue -Value $ValueData
}
$msg = "`nExiting: $((Get-Variable MyInvocation -Scope 0).Value.MyCommand.Name)"; Write-Host -fore DarkGreen $msg ; $msg | out-file -Append $log
#}
I get the following error:
out-lineoutput : The object of type "Microsoft.PowerShell.Commands.Internal.For
mat.FormatStartData" is not valid or not in the correct sequence. This is likel
y caused by a user-specified "format-table" command which is conflicting with t
he default formatting.
+ CategoryInfo : InvalidData: (:) [out-lineoutput], InvalidOperat
ionException
+ FullyQualifiedErrorId : ConsoleLineOutputOutOfSequencePacket,Microsoft.P
owerShell.Commands.OutLineOutputCommand
I have seen similar error in powershell when using format-table however i am not using fr here atleast directly.
Not sure what is wrong!
EDIT:
no, but it turns out that the issue was not in the above script at all.
It appears that caller script had a line involving format-table which had nothing to do with this script, was causing the issue.
$SupportFilesInfo = Import-csv $SupportFilesCSV | select-object
$SupportFilesInfo | ft ; $SupportFilesInfo | Out-File -append $log
I changed it to:
$SupportFilesInfo | ft | out-default; $SupportFilesInfo | Out-File -append $log
which resolved the error!!
However i am still at loss at why the error occurs ONLY during the first run.
I had hit this issue earlier too, but it was very consistent.
Any idea why?