powershell catch export to csv not working - powershell

I'm writing a script that is fed a .csv and tries to make an operation and then catches into a seperate .csv but for some reason I cant seem to feed the catch info into the csv. I get the error, "Export-csv : Cannot process argument because the value of argument "name" is not valid. Change the value of the "name" argument and run the operation again."
I appreciate any input from the brains.
#imports a csv and does somthing with the data. The columns in the csv are specified by the $($_.'columnName')
Import-Csv -Path 'PathToMyCSV.csv' | ForEach-Object{
#Print associated User
Write-Host "$($_.ModifiedEmail)" -ForegroundColor Yellow -NoNewline;
Write-Host " is the user's email prefix, " -NoNewline
#Print PC name to be moved
Write-Host "SD-LT-$($_.PCName)" -ForegroundColor Yellow -NoNewline;
Write-Host " is the PC they use, and " -NoNewline
#Print The OU the computer is moving to
Write-Host "$($_.OU)" -ForegroundColor Yellow -NoNewline;
Write-Host "is the OU the computer needs to go in!"
$pcname = "SD-LT-$($_.PCName)"
Try {
Get-ADComputer SD-LT-$($_.PCName) | Move-ADObject -TargetPath $($_.OU)
}
Catch {
Write-Host $_ -ForegroundColor Magenta
$pcname | Export-csv -Path 'PathToAnotherCSV.csv' -Append -Force
}
}

Try creating a PSCustomObject.
[PSCustomObject]#{'pcname'=$pcname} | Export-csv -Path 'PathToAnotherCSV.csv' -Append -Force

Related

Script Working on Powershell console but not on Powershell ISE

This is error message i get when running code with Powershell ISE:
Exception calling "Substring" with "1" argument(s): "StartIndex cannot
be less than zero.
Parameter name: startIndex"
At C:\Users\3N16M4\Desktop\Untitled3.ps1:8 char:1
$Last=$Role.Substring($Role.IndexOf('FE'))
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentOutOfRangeException
$text ="`n"
$String= Read-Host -Prompt 'Please Enter Value '
$Role=Get-ChildItem -Path 'C:\Users\3N16M4\Desktop\New folder\*.txt' -Recurse |Select-string -Pattern $String -SimpleMatch -Context 9,0 | Out-String -Stream |Select-Object -Index 1
$Last=$Role.Substring($Role.IndexOf('FE'))
$text
Write-host ('The Answer is: {0}' -f $Last)
$text
Read-Host -Prompt 'Press Enter to exit'
However running this same code with VScode and powershell console gives no errors and runs just fine , so i was wondering what could be causing that.
$role = "you are the winner of a all expense paid trip to the beautiful beaches of Cancun. There are few exceptions that a such as this script must be completed before you read all of the details. The developer that is assisting in the writing of this script will require a new question if you more help. It was a joy and pleasure to see this issue resolved." ;
Write-host "This String is $(($Role).length) characters long.";
$MaxDisplayWidth = 120;
$role -split '(\w{$MaxDisplayWidth})' | Where-Object {$_};
First, do a proper check for your variables because:
$Role.IndexOf('FE')
Will return -1 when it cannot find the text 'FE' in $Role.
When it returns -1 the next statement:
$Role.Substring(-1)
Will fail with the above error.
This means that the issue lies in how $Role is filled. Output $Role to see if it is returning what you are expecting. Maybe $String is being set differently?
Post the output.
$text ="`n"
$String= Read-Host -Prompt 'Please Enter Value '
$Foundfiles = Get-ChildItem -Path 'C:\temp\*.txt' -Recurse
If ($Foundfiles) {
Write-host "Files have been found. The problem is not here" -ForegroundColor green}
Else { Write-host "Error No files Found" -ForegroundColor Red }
$FilesThatContaintheString = $Foundfiles | Select-string -Pattern $String -SimpleMatch -Context 9,0
If ($FilesThatContaintheString) {Write-host "Found value in a file" -ForegroundColor Green}
Else { write-host "Did not find the string in any of the files." -ForegroundColor red}
$convertingToStrings = $FilesThatContaintheString | Out-String -Stream
If ($convertingToStrings) {write-host "Out-string works" -ForegroundColor Green}
Else {Write-host "Out-string is not working" -ForegroundColor red }
$selectTheSecoundOutputedString = $convertingToStrings |Select-Object -Index 1
If ($selectTheSecoundOutputedString) {
Write-host "If you see this then the issue is somewhere else" -ForegroundColor Yellow}
Else {Write-host 'Did not find a second string try $index 0' -ForegroundColor Red}
$Role = $selectTheSecoundOutputedString
Write-host "The value of Role is $role"
Write-host "The Index of FE is $($Role.IndexOf('FE'))"
$Last=$Role.Substring($Role.IndexOf('FE'))
$text
Write-host ('The Answer is: {0}' -f $Last)
$text
Read-Host -Prompt 'Press Enter to exit'

Powershell outputting info into text file but not into output pane

got a script here which I require the results that export into the text file to also show in the output pane at the bottom. Can anyone help please?
The results I've currently got is that it only shows the Make and model of the machine but not the others from Domain all the way to memory left in GB. I want it all to show on the output pane at the bottom and also to save in a text file which saves and opens straight away.
Please note: The file opens with the data in but the main issue is that it doesn't show in the output pane. Here is the script:
Clear-Host
Write-Host "Setting Execution Policy to Remote Signed..." -ForegroundColor Yellow
Set-ExecutionPolicy RemoteSigned -Force
Write-Host "Your execution policy is set to:" -ForegroundColor Cyan
Get-ExecutionPolicy
Start-Sleep -s 3
Clear-Host
Write-Host "Generating computer statistics..." -ForegroundColor Yellow
Write-Host " "
Start-Sleep -s 2
function systemstats {
Write-Host "Manufacturer:" -ForegroundColor Cyan
Write-Host "$($m.Manufacturer)" -ForegroundColor Yellow
Write-Host "Model:" -ForegroundColor Cyan
Write-Host "$($m.Model)" -ForegroundColor Yellow
Write-Host "Domain:" -ForegroundColor Cyan
$env:USERDOMAIN
Write-Host "Computer Name:" -ForegroundColor Cyan
$env:COMPUTERNAME
Write-Host "Operating System & Location:" -ForegroundColor Cyan
(Get-WmiObject Win32_OperatingSystem).name
Write-Host "OS Architecture:" -ForegroundColor Cyan
if ((Get-WmiObject win32_operatingsystem | select osarchitecture).osarchitecture -eq "64-bit")
{
Write "64-bit OS"
}
else
{
Write "32-bit OS"
}
Write-Host "OS Build:" -ForegroundColor Cyan
(Get-CimInstance Win32_OperatingSystem).version
Write-Host "Version:" -ForegroundColor Cyan
(Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ReleaseID).ReleaseID
Write-Host "Current IP Address:" -ForegroundColor Cyan
Ipconfig | Select-String IPv4
Write-Host "Calculating RAM installed in MB:" -ForegroundColor Cyan
(systeminfo | Select-String 'Total Physical Memory:').ToString().Split(':')[1].Trim()
$m = (Get-WmiObject -Class Win32_ComputerSystem -Property * |
Select-Object -Property Manufacturer, Model)
Write-Host "Disk Space in GB:" -ForegroundColor Cyan
gwmi win32_logicaldisk | Format-Table DeviceId, MediaType, #{n="Size";e={[math]::Round($_.Size/1GB,2)}},#{n="FreeSpace";e={[math]::Round($_.FreeSpace/1GB,2)}}
}
$result=(systemstats)
$result | Out-File "C:\Users\brendan.hargate\Desktop\test.txt"
Invoke-Item "C:\Users\brendan.hargate\Desktop\test.txt"
Use Tee-Object instead of Out-File:
$result | Tee-Object -FilePath "C:\Users\brendan.hargate\Desktop\test.txt"
Tee-Object (inspired by tee), will duplicate the input stream - one copy is passed on down the pipeline (which in your case will end up in the command pane), the other is written to a variable or a file (like in the above example)
Your systemstats function in part uses Write-Host which operates outside of PowerShell's (success) output stream.
Write-Host output cannot be captured (PSv4) / is by default not captured (PSv5+) in variables or output files. As the name suggests, Write-Host writes to the host UI (the console), and is not meant to output data - that's what Write-Output and its alias, Write, as well as implicit output (e.g., $env:USERDOMAIN by itself) are for.
A variable assignment such as $result = ... only captures (success) output-stream output, i.e., the implicit output and the output from the Write (a.k.a. Write-Output) command. By contrast, your Write-Host commands printed straight to the console.
Given that you sent $result to a file - without also printing it to the console - the net effect was that only the Write-Host output appeared in the console.
The solution therefore has two components:
Modify your function to only use implicit output (Write-Output output) in order to produce data output.
Then use Tee-Object to print to both the console (via the success output stream) and a file, as suggested in Mathias R. Jessen's helpful answer.
As an aside, in PSv5+, you could get away with the following (although it is ill-advised), based on the ability to capture Write-Host output - now a virtual alias of Write-Information - via the newly introduced output stream number 6:
systemstats 6>&1 | # PSv5+: redirect the information stream to the (success) output stream.
Tee-Object -FilePath "$([Environment]::GetFolderPath('Desktop'))\text.txt"

Suppress Powershell Errors while adding to $Error Variable

I have a block of code executing that has been set up with a simple If/Else block to catch errors. I would normally use Try/Catch but the Exchange 2010 PS environment I'm working in doesn't allow me to use most of the Try/Catch features (and I can't update it or change it in any way because it's the customer's system and they're unwilling).
The issue is that while the code will function as expected when the Add-DistributionGroupMember cmdlet is set with -ErrorAction "Stop", it will output the error to the host each time, which annoys the customer (and me) because it's effectively just red noise since all the possible errors are being handled via a detailed output file.
If I set the cmdlet to -ErrorAction "SilentlyContinue" the error text is suppressed, but the Error is not added to the $Error[0] spot as I expected. The same is true of -ErrorAction "Ignore". The code requires that the Error be added to the $Error variable each time there is an error.
Here is the code:
$ListMembershipsIn | % {
$Alias = $_.Alias
$Member = $_.Member
Add-DistributionGroupMember -Identity $Alias -Member $Member -Confirm:$false -ErrorAction Stop
if($Error[0] -match "The recipient"){
Write-Host -ForegroundColor Yellow "Already a member"
Add-Content -Path $OutputPath -Value "$($Alias),$($Member),Group already contains Member"
}
elseif($Error[0] -match "couldn't be found"){
Write-Host -ForegroundColor Yellow "not found"
Add-Content -Path $OutputPath -Value "Group does not exist or cannot be found,$($Alias),N/A"
}
elseif($Error[0] -match "couldn't find"){
Write-Host -ForegroundColor Yellow "not found"
Add-Content -Path $OutputPath -Value "Member does not exist or cannot be found,$($Alias),$($Member)"
}
elseif($Error[0] -match "There are Multiple"){
Add-Content -Path $OuputPath -Value "Member name matches too many recipient - Add Member Manually,$($Alias),$($Member)"
}
else{
Add-Content -Path $OutputPath -Value "Member Successfully Added to Group,$($Alias),$($Member)"
Write-Host -ForegroundColor Green "Throw Flag here"
}
}
You have two options for recourse, you can utilize the -ErrorVariable common parameter, or a Try/Catch block to interact with the specific error.
ErrorVariable
When interacting with ErrorVariable, you can prepend the name with a + to append additional errors to it just like the $Error automatic variable, e.g.: -ErrorVariable '+MyError'
$ListMembershipsIn | ForEach-Object {
$Alias = $_.Alias
$Member = $_.Member
Add-DistributionGroupMember -Identity $Alias -Member $Member -ErrorVariable 'MyError'
## No error = good, continue the next iteration of the loop
If (-not $MyError)
{
Add-Content -Path $OutputPath -Value "Member Successfully Added to Group,$Alias,$Member"
Write-Host -ForegroundColor Green "Throw Flag here"
Continue
}
Switch -Regex ($MyError.Exception.Message)
{
'The recipient'
{
Write-Host -ForegroundColor Yellow "Already a member"
Add-Content -Path $OutputPath -Value "$Alias,$Member,Group already contains Member"
}
"couldn't be found"
{
Write-Host -ForegroundColor Yellow "not found"
Add-Content -Path $OutputPath -Value "Group does not exist or cannot be found,$Alias,N/A"
}
"couldn't find"
{
Write-Host -ForegroundColor Yellow "not found"
Add-Content -Path $OutputPath -Value "Member does not exist or cannot be found,$Alias,$Member"
}
'There are Multiple'
{
Add-Content -Path $OuputPath -Value "Member name matches too many recipient - Add Member Manually,$Alias,$Member"
}
}
}
Try/Catch
$ListMembershipsIn | ForEach-Object {
$Alias = $_.Alias
$Member = $_.Member
Try
{
Add-DistributionGroupMember -Identity $Alias -Member $Member -ErrorAction 'Stop'
## No error thrown = successful processing
Add-Content -Path $OutputPath -Value "Member Successfully Added to Group,$Alias,$Member"
Write-Host -ForegroundColor Green "Throw Flag here"
}
Catch
{
Switch -Regex ($_.Exception.Message)
{
'The recipient'
{
Write-Host -ForegroundColor Yellow "Already a member"
Add-Content -Path $OutputPath -Value "$Alias,$Member,Group already contains Member"
}
"couldn't be found"
{
Write-Host -ForegroundColor Yellow "not found"
Add-Content -Path $OutputPath -Value "Group does not exist or cannot be found,$Alias,N/A"
}
"couldn't find"
{
Write-Host -ForegroundColor Yellow "not found"
Add-Content -Path $OutputPath -Value "Member does not exist or cannot be found,$Alias,$Member"
}
'There are Multiple'
{
Add-Content -Path $OuputPath -Value "Member name matches too many recipient - Add Member Manually,$Alias,$Member"
}
}
}
}
It appears that Add-DistributionGroupMember command doesn't fill ErrorVariable when specified.
I found no way to avoid the unwanted output, so I handled the error with Tristan's trick rather than by exception handling (which is absolutely fine, but not fitting my own dev):
$Error.clear()
Add-DistributionGroupMember -Identity $mySite.MailingList -Member $emailAddress
if ($Error.count -eq 0) {
$script:logger["ldissue"] += "<li>Liste de diffusion $($mySite.MailingList) : La ressource <b>$($ADRecord.Name)</b> ($($ADRecord.SamAccountName) - $($BoondRecord.flags)) a été ajoutée à la liste</li>"
} else {
$script:logger["ldissue"] += "<li>Liste de diffusion $($mySite.MailingList) : La ressource <b>$($ADRecord.Name)</b> ($($ADRecord.SamAccountName) - $($BoondRecord.flags)) n'a pas pu être ajoutée à la liste (<i>$($Error[0])</i>)</li>"
}
Use the "-ErrorAction Continue" this won't suppress the error but it will ensure the script continues and it places the error in the $Error variable.
You can also use the $Error.clear() command to remove any stored errors in the session.

Export-Csv multiple forloop results

I have multiple forloops running with different variables pulling from .txt files. I want to export this all into a single csv file while having it look just like it does in powershell. Attached is what I get for powershell output and I would like to see the first write-host as a header in excel, followed by server name in column 1 and UP or DOWN in column 2 beneath it.
Powershell
Write-Host "Starting SVR2000MS" -ForegroundColor Yellow
$servers = Get-Content C:\Users\username\Desktop\subfolder\SVR2000.txt
foreach($server in $servers){
if (Test-Connection -ComputerName $server -Count 1 -ErrorAction SilentlyContinue) {
Write-Host "$server, UP" -ForegroundColor Green
}
else{
Write-Host "$server, DOWN" -ForegroundColor Red
}
}
Write-Host "Starting SVR2003DC" -ForegroundColor Yellow
$servers = Get-Content C:\Users\username\Desktop\subfolder\SVR2003.txt
foreach($server in $servers){
if (Test-Connection -ComputerName $server -Count 1 -ErrorAction SilentlyContinue) {
Write-Host "$server, UP" -ForegroundColor Green
}
else{
Write-Host "$server, DOWN" -ForegroundColor Red
}
}
Simple way:
You just print it and put it in a file
Instead of Write-Host ..., do:
"$server,UP" | Out-File test.csv -append
You can have more elaborate options by using objects, but it may be overkill for your needs.
If you want a clean file, you need to delete it at the beginning, because of -append.
BTW, no space after comma in a CSV :)
Edit:
Write-Host writes specifically ... to the host, i.e. the console, so you cannot redirect it elsewhere.

Powershell: Fix My Loop Logic

I am trying to get the logic straightened out for a loop that I need to continue to prompt a user to enter a valid UNC path. I have it set to test the path and output to the console that the path is invalid. But, after that, it moves back to my prompt for choice. I want it to instead, ask the user to enter another valid path before moving on to the next step. Here is my loop:
do{
Write-Host ""
$pathPrompt = Write-Host "Please enter path to file/folder:" -ForegroundColor Cyan;
$path = Read-Host;
$test = Test-Path $path
if($test -eq $false){
Write-Host "ERROR! Invalid Path!" -ForegroundColor Red
}
}until($test -eq $true){
Write-Host ""
Write-Host "Getting ACL on"$path -ForegroundColor Green
Get-NTFSAccess -Path $path
}
What am I missing or not doing right here?
Sounds like you want to reuse your validation test. You could put it in a function for reuse:
Function Get-ValidPath {
do {
Write-Host "`r`nPlease enter path to file/folder:" -ForegroundColor Cyan
$path = Read-Host
$test = Test-Path $path
if ($test -eq $false) {
Write-Host "ERROR! Invalid Path!" -ForegroundColor Red
}
} until ($test -eq $true)
$path
}
$validatedpath1 = Get-ValidPath
Write-Host "`r`nGetting ACL on $validatedpath1" -ForegroundColor Green
Get-NTFSAccess -Path $validatedpath1
$validatedpath2 = Get-ValidPath