Out-File unnecessary characters - powershell

I have the script below which pings a list of machines, outputs the result to CSV and gets the lastlogontimestamp of the machine.
It works fine, except the lastlogontimestamp comes out like this:
CCC-APP01,172.22.100.15,#{lastLogonDate=07/25/2018 13:24:54}
How can I get rid of the extra characters: #{lastlogondate=...}?
$OutputCSV = "C:\TEMP\OUPingResults.csv"
$SearchLocation = "OU=AA,OU=Servers,DC=LocA,DC=XYZ,DC=com"
$Computers = Get-ADComputer -Filter * -SearchBase $SearchLocation |
Select Name |
Sort-Object Name
$Computers = $Computers.Name
$Headers = "ComputerName,IP Address,LastLogonTimeStamp"
$Headers | Out-File -FilePath $OutputCSV -Encoding UTF8
foreach ($computer in $Computers) {
Write-host "Pinging $Computer"
$Test = Test-Connection -ComputerName $computer -Count 1 -ErrorAction SilentlyContinue -ErrorVariable Err
if ($test -ne $null) {
$IP = $Test.IPV4Address.IPAddressToString
$LastLogonTimeStamp = Get-ADComputer $Computer -Prop CN,lastLogonTimestamp |
Select #{n="lastLogonDate";e={[datetime]::FromFileTime($_.lastLogonTimestamp)}}
$Output = "$Computer,$IP,$LastLogonTimeStamp"
$Output | Out-File -FilePath $OutputCSV -Encoding UTF8 -Append
} else {
$Output = "$Computer,$Err"
$Output | Out-File -FilePath $OutputCSV -Encoding UTF8 -Append
}
}

The expression ... |Select-Object #{N='SomeName';E={"SomeValue"}} will produce an object that has a property named SomeName with the value "SomeValue".
What you see in the output is a string representation of this object.
If you want only the value, change the $LastLogonTimeStamp assignment to:
$LastLogonTimeStamp = [datetime]::FromFiletime((Get-ADComputer $Computer -Prop lastLogonTimestamp).lastLogonTimestamp)

Related

powershell returning Get-ADComputer : The object name has bad syntax

I want to get all of the computers in a specific OU and ping them, but Im having trouble with Get-ADComputer.
code:
# Enter CSV file location
$csv = "filepath.csv"
# Add the target OU in the SearchBase parameter
$Computers = Get-ADComputer -Filter * -SearchBase "OU=Servers,DC=mydomain,DC=com" | Select Name | Sort-Object Name
$Computers = $Computers.Name
$Headers = "ComputerName,IP Address"
$Headers | Out-File -FilePath $csv -Encoding UTF8
foreach ($computer in $Computers)
{
Write-host "Pinging $Computer"
$Test = Test-Connection -ComputerName $computer -Count 1 -ErrorAction SilentlyContinue -ErrorVariable Err
if ($test -ne $null)
{
$IP = $Test.IPV4Address.IPAddressToString
$Output = "$Computer,$IP"
$Output | Out-File -FilePath $csv -Encoding UTF8 -Append
}
Else
{
$Output = "$Computer,$Err"
$output | Out-File -FilePath $csv -Encoding UTF8 -Append
}
cls
}
and im getting:
Get-ADComputer : The object name has bad syntax
At script.ps1:2 char 14
+ ... omputers = Get-ADComputer -Filter * -SearchBase "OU=Servers, ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+CategoryInfo : NotSpecified: (:) [Get-ADComputer], ADException
+FullyQualifiedErrorId : ActiveDirectoryServer:8335,Microsoft,ActiveDirectory,Management,Command.GetADComputer
ps. this code is taken from here. yes I know Im not supposed to do that but after getting this error
time after time I wanted to try a code that works.
Double check that the OU you're using as the search base is correct. This error occurs when it's off.
Apart from that, I recommend using the System.Net.NetworkInformation.Ping class. It's a lot faster than Test-Connection because you have more control over the ping timeout.
$ping = New-Object System.Net.NetworkInformation.Ping
$pingTimeutMS = 200
$computers = Get-ADComputer -Filter * -SearchBase "OU=Servers,DC=mydomain,DC=com"
$results = $computers | Sort-Object Name | ForEach-Object {
$ComputerName = $_.Name
Write-Host "Pinging $ComputerName..."
$test = $ping.Send($ComputerName, $pingTimeutMS)
[pscustomobject]#{
"Computer" = $ComputerName
"IP Address" = if ($test.Status -eq "Success") { $test.Address } else { $test.Status }
}
}
$results | Export-Csv "filepath.csv" -Delimiter ',' -NoTypeInformation -Encoding UTF8
Not appending the lines to the CSV piecemeal feels a bit less clunky, too.

Why does this outputting numbers in the file not the machine name?

The file that I'm outputting doesnt contain the $machine and if its valid or not, it contains numbers. How do I get this to output the machine name and if its valid or not?
Import-Module ActiveDirectory
$enddate = Get-Date
$machines=(Get-ADComputer -filter * -SearchBase 'OU=this,OU=is,OU=my,DC=domain,DC=com' -Properties * | Select Name, lastlogondate |Where-Object {$_.LastLogonDate -lt ($enddate).AddMonths(-2)} |Sort lastlogondate).name
foreach ($machine in $machines)
{
if (test-Connection -ComputerName $machine -count 1 -ErrorAction SilentlyContinue)
{
Write-Output "$machine is valid"
}
Write-Output "$machine is not valid" | Export-Csv
c:\machine_not_valid.csv -Append -NoClobber -NoTypeInformation
}
Export-Csv expects an object, not a string. It then uses the properties of this object as headers for the CSV.
It is outputting numbers because it is receiving string as input, which has the single property Length
You also have an error in your code where the "$machine is not valid" part is outside of the if statement and not in an else statement.
If you have multiple values, Export-Csv is the way to go. If you only have one, use Out-Fileas you will not need to create an object:
Import-Module ActiveDirectory
$enddate = Get-Date
$machines=(Get-ADComputer -filter * -SearchBase 'OU=this,OU=is,OU=my,DC=domain,DC=com' -Properties * | Select Name, lastlogondate |Where-Object {$_.LastLogonDate -lt ($enddate).AddMonths(-2)} |Sort lastlogondate).name
foreach ($machine in $machines)
{
if (test-Connection -ComputerName $machine -count 1 -ErrorAction SilentlyContinue)
{
Write-Output "$machine is valid"
}else{
Write-Output "$machine is not valid" | Export-Csv c:\machine_not_valid.csv -Append -NoClobber
}
}

Add line breaks to Out-File cmdlet

I am trying to get the list of computers that has no antivirus but the out file is with computer names in one single line, can anyone help?
ForEach ($COMPUTER in (Get-ADComputer -Filter {OperatingSystem -notLike '*windows xp*' } | Select-Object -ExpandProperty Name))
{if(!(Test-Connection -Cn $computer -BufferSize 16 -Count 1 -ea 0 -quiet))
{write-host "cannot reach $computer" -f red}
else {
try
{
$AntiVirusProduct = Get-WmiObject -Namespace "root\SecurityCenter2" -Class AntiVirusProduct -ComputerName $computer -ErrorAction Stop
}
catch
{
Write-Warning "[ERROR] invalid namespace [$($computer)] : $_"
$noantivirus+=$computer
}
$noantivirus | out-file -Encoding Ascii -append c:\noantivirus.txt}}
You can try to join them by a NewLine:
$noantivirus -join [System.Environment]::NewLine | out-file -Encoding Ascii -append c:\noantivirus.txt
If this doesn't work, try with rn:
$noantivirus -join "`r`n" | out-file -Encoding Ascii -append c:\noantivirus.txt
I found it
$noantivirus = Add-Content c:\noantivirus.txt "`n$computer"

Cannot bind argument to parameter "FilePath" because it is null

Every time I run the script below I get
Cannot bind argument to parameter 'FilePath' because it is null.
It was working last night. No changes have been made and this morning it just fails. the funny thing is if i save the script and then run it, it works. However if I clear console then run it again it fails.
Am I missing something obvious?
New-Item -ItemType Directory -Force -Path C:\NonStandard_Services
set-location C:\NonStandard_Services
$Computers= Get-Content C:\computers.txt
$Report= $file
$file= $Computer
ForEach ($Computer in $Computers)
{
Get-WmiObject -ComputerName $Computer -class Win32_Service -ErrorAction SilentlyContinue |
Where-Object -FilterScript {$_.StartName -ne "LocalSystem"}|
Where-Object -FilterScript {$_.StartName -ne "NT AUTHORITY\NetworkService"} |
Where-Object -FilterScript {$_.StartName -ne "NT AUTHORITY\LocalService"} |
Select-Object -Property StartName,Name,DisplayName|
ConvertTo-Html -Property StartName,Name,DisplayName -head $HTML -body "<H2>Non- Standard Service Accounts on $Computer</H2>"| Out-File $Report -Append}
#Rename-Item c:\GP_Services\Report.htm $file
Get-ChildItem | Where-Object {$_.extension -ne ".htm"} | Rename-Item -newname { $_.name + '.htm' }
$Report= $file
$file= $Computer
ForEach ($Computer in $Computers)
{
...
}
You assign variables to other variables before they were assigned a value themselves. Change the above to this:
ForEach ($Computer in $Computers) {
$file = $Computer
$Report = $file
...
}
Or directly use $Computer in Out-File:
... | Out-File "$Computer.txt" -Append

powershell workflow and parallel not giving output

I'm using the following script and it creates the out file correctly, but it's empty. I'm not sure what it's missing exactly. This is my first attempt with using workflows.
workflow DisableIISParallel
{
$ScriptPath = "C:\Scripts\Server_Lists"
$OLD = "Legacy-Servers"
$OldList = Get-Content "$ScriptPath\$OLD.txt"
$objHost=$Records.Length
function DisableIIS ($appName) {
$objHostStr = [System.Net.Dns]::GetHostEntry([string]$objHost).HostName
Invoke-Command -ComputerName $objHostStr { iisreset /stop }
Set-Service -Name W3SVC -StartupType Disabled -Status Stopped -ComputerName $objHostStr
Get-WmiObject -Class win32_service -ComputerName $objHostStr |
where { $_.name -eq "W3SVC" } |
Format-Table -Property #{Expression={$_.PSComputerName};Label="Server";width=18},
#{Expression={$_.Name};Label="Service";width=45},
#{Expression={$_.StartMode};Label="Mode";width=10},
#{Expression={$_.State};Label="State";width=10},
#{Expression={$_.Status};Label="Status";width=10} |
Format-List | out-string -s | ? {$_} | Out-File C:\Scripts\Output\$appName.log -Append
Write-Output "" | Out-File C:\Scripts\Output\$appName.log -Append
}
foreach -parallel($objHost in $OldList)
{
$appName = $OLD
DisableIIS $appName
}
}
DisableIISParallel
This bit is not right:
Get-WmiObject -Class win32_service -ComputerName $objHostStr |
where { $_.name -eq "W3SVC" } |
Format-Table -Property #{Expression={$_.PSComputerName};Label="Server";width=18},
#{Expression={$_.Name};Label="Service";width=45},
#{Expression={$_.StartMode};Label="Mode";width=10},
#{Expression={$_.State};Label="State";width=10},
#{Expression={$_.Status};Label="Status";width=10} |
Format-List | out-string -s | ? {$_} | Out-File C:\Scripts\Output\$appName.log -Append
You should not run the output of one format command (Format-Table) into another format command (Format-List).
Try this (assuming you want tabular format - if not, change the Format-Table to Format-List):
Get-WmiObject -Class win32_service -ComputerName $objHostStr |
where { $_.name -eq "W3SVC" } |
Format-Table #{Expression={$_.PSComputerName};Label="Server";width=18},
#{Expression={$_.Name};Label="Service";width=45},
#{Expression={$_.StartMode};Label="Mode";width=10},
#{Expression={$_.State};Label="State";width=10},
#{Expression={$_.Status};Label="Status";width=10} >> C:\Scripts\Output\$appName.log
And pass in all the variables required to the function e.g.:
function DisableIIS ($appName, $objHost) {
...
}
foreach -parallel($objHost in $OldList)
{
$appName = $OLD
DisableIIS $appName $objHost
}