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

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

Related

Output running services to csv with computer name

I need to generate a csv containing running services to csv with the corresponding computer name
I know there is a simple way to do this and I have been tinkering with creating a new psobject, but I am not sure how to pipe the results to the new-object...
Here is what I am using:
$Input = "SomePath"
$Output = "SomeOtherPath"
$CompNames = Get-Content -Path "$Input"
ForEach ($CompName in $CompNames){
Get-Service -ComputerName $CompName | Where-Object {$_.Status -eq "Running"} | Export-csv -Path "$Output"
}
What I need in the CSV is:
ComputerName, ServiceName, DisplayName
basically, I need to add the computer name to the array.
If you want to be able to pipe the results, use a foreach-object.
$Output = "SomeOtherPath"
Get-Content -Path "SomePath" | ForEach-Object {
Get-Service -ComputerName $_ | Where-Object {$_.Status -eq "Running"} | Select-Object ComputerName, ServiceName, DisplayName
} | Export-csv -Path "$Output"
If you want to stick to a foreach statement, collect it all first then export it.
$Output = "SomeOtherPath"
$CompNames = Get-Content -Path "SomePath"
$results = ForEach ($CompName in $CompNames){
Get-Service -ComputerName $CompName | Where-Object {$_.Status -eq "Running"} | Select-Object ComputerName, ServiceName, DisplayName
}
$results | Export-csv -Path "$Output"
Try like this (Don't use $Input as variable name)
$InputX = "SomePath"
$Output = "SomeOtherPath"
$CompNames = Get-Content -Path "$Input"
ForEach ($CompName in $CompNames){
Get-Service -ComputerName $CompName | Where-Object {$_.Status -eq "Running"} | Select-Object ComputerName, ServiceName, DisplayName | Export-csv -Path "$Output"
}

Out-File unnecessary characters

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)

Outputing Data to CSV with use of expressions

I'm attempting to gather data via WMI and then output that to a CSV once I've setup the tables using expressions, but I'm not getting the output I'd expect.
$Ips = "192.168.1.1", "192.168.1.2"
foreach ($ip in $Ips) {
$Profiles = Get-WmiObject -Class Win32_UserProfile -Computer $ip -ea 0
Write-Host `n$ip
foreach ($profile in $Profiles) {
#{Expression={$ip};Label="IPAddress"}, #{Expression={"\\"+$ip+"\"+$profile.LocalPath};Label="SharePath"} |
Export-Csv -Path "$HOME\Desktop\Found.csv" -Append -NoTypeInformation
}
}
The feature you're trying to use here is called calculated properties, and you need Select-Object to use it:
Get-WmiObject -Class Win32_UserProfile -Computer $ip -EA 0 |
Select-Object #{Expression={$ip};Label="IPAddress"},
#{Expression={'\\{0}\{1}' -f $ip, $profile.LocalPath};Label="SharePath"} |
Export-Csv -Path "$HOME\Desktop\Found.csv" -Append -NoTypeInformation

Avoiding or replacing multiple Where-Object statements

I have a script containing a function Create-RebootData containing child functions such as Full and Full has a child function named Generate-RebootData where the output variable $Global:result is created.
Within Full there are multiple Where-Object two statements to filter the $Global:result into by date and time. Example below.
Is there an easier method to accomplish this instead of the multiple Where-Object statements?
The desired result are
Set-StrictMode -Version 1.0
Function Create-RebootData{
[CmdletBinding(SupportsShouldProcess=$true,DefaultParameterSetName="ViewOnly")]
Param(
[Parameter(ParameterSetName="ViewOnly")]
[Switch]$ViewOnly,
[Parameter(ParameterSetName="Full")]
[Switch]$Full,
)
Switch ($PSCmdlet.ParameterSetName){
"ViewOnly"
{
ViewOnly
}
"Full"
{
Full
}
}#end switch
Function Full{
Generate-RebootData
$Global:result | Where-Object {$_ -like '*fri?2:00*' -and $_.MaintenanceWindow `
-notmatch 'all.da.servers' -and $_.Server -match "^ITD"} | % {"{0}" -f $_.Server} | `
Out-File D:\Scripts\Full-Servers.txt -Append
$Global:result | Where-Object {$_ -like '*fri?2:00*' -and $_.MaintenanceWindow `
-notmatch 'all.da.servers' -and $_.Server -match "^ITD"} | `
% {"{0}" -f $_.MaintenanceWindow -replace `
"^NA.+", "$((get-date).AddDays(1).ToString('MM-dd-yy')) 01:50"} | `
Out-File D:\Scripts\Full-Times.txt -Append
}
Function Generate-RebootData{
IF(Get-Command Get-SCOMAlert -ErrorAction SilentlyContinue){}ELSE{Import-Module OperationsManager}
"Get Pend reboot servers from prod"
New-SCOMManagementGroupConnection -ComputerName Server01
$AlertData = Get-SCOMAlert -Criteria "MyString" | Select NetbiosComputerName
New-SCOMManagementGroupConnection -ComputerName Server02
$AlertData += Get-SCOMAlert -Criteria "MyString" | Select NetbiosComputerName
"Remove duplicates"
$AlertDataNoDupe = $AlertData | Sort NetbiosComputerName -Unique
"Create hash table"
$table = #{}
"Populate hash table"
$MaintenanceWindow = Import-Csv D:\Scripts\MaintenanceWindow2.csv
$MaintenanceWindow | ForEach-Object {$table[$_.Computername] = $_.'Collection Name'}
"Create final object"
$Global:result = #{}
"Begin Loop"
$Global:result = $AlertDataNoDupe | ForEach-Object { [PSCustomObject] #{
Server=$_.NetbiosComputerName
MaintenanceWindow= if($table.ContainsKey($_.NetbiosComputerName)){
$table[$_.NetbiosComputerName]
}Else { "Not Found!"}
PingCheck=IF(Test-Connection -Count 1 $_.NetbiosComputerName -Quiet -ErrorAction SilentlyContinue){"Alive"}
ELSE{"Dead"}
LastReboot=Try{$operatingSystem = Get-WmiObject Win32_OperatingSystem -ComputerName $_.NetbiosComputerName -ErrorAction Stop
[Management.ManagementDateTimeConverter]::ToDateTime($operatingSystem.LastBootUpTime)}
Catch{"Access Denied!"}
} }
}
You can do it like this:
$Global:result | Where-Object {
$_ -like '*fri?2:00*' -and
$_.MaintenanceWindow -notmatch 'all.da.servers' -and
$_.Server -match '^ITD'
} | ForEach-Object {
'{0}' -f $_.Server | Out-File D:\Scripts\Full-Servers.txt -Append
'{0}' -f $_.MaintenanceWindow -replace '^NA.+',
'{0} 01:50' -f (Get-Date).AddDays(1).ToString('MM-dd-yy') | Out-File D:\Scripts\Full-Times.txt -Append
}
But I agree with Mathias' comment, this function probably should be refactored.

Drive variable is not working in Powershell

I have the following script to list big files on list of servers. Unfortunately it is not listing anything. However, if I replace the $_.Name by the string D:\ it works fine.
$servers = Get-Content "servers1.txt" | Select-String -pattern `
"^[^#]"
foreach ($line in $servers) {
$svr = echo $line | %{$_.Line.split(':')[2]}
Get-WmiObject Win32_Volume -ComputerName $svr -ErrorAction SilentlyContinue |
Select-Object __SERVER,Name |
foreach {
Invoke-command {Get-ChildItem -path $_.Name -rec | Where-Object `
-FilterScript {($_.Length -ge 3GB) -and ($_.Name -notlike "*.mdf")}} -computername $svr
}
}
Thanks for any help.
This is scoping issue: in remote command $_.Name does not exist. Try this instead:
Invoke-command {
param ($Path)
Get-ChildItem -path $Path -rec | Where-Object {($_.Length -ge 3GB) -and ($_.Name -notlike "*.mdf")}
} -ComputerName $svr -ArgumentList $_.Name