Alternative to Append export-csv powershell - powershell

I add user logon and logout tracking script
I found that some computers do not export csv as they have powershell 2.0 because append is not supported is there any alternative?
$ErrorActionPreference = 'Continue'
####**** Tracking user logon *****#####
$username = $env:USERNAME
$computername = $env:COMPUTERNAME
$ipv4 = Test-Connection -ComputerName (hostname) -Count 1 | foreach { $_.ipv4address }
$ipv6 = Test-Connection -ComputerName (hostname) -Count 1 | foreach { $_.ipv6address }
$timeformat='MM-dd-yyyy hh:mm:ss tt'
$time = (Get-Date).ToString($timeformat)
$action = 'Logon'
$filedate = 'MM-dd-yyyy'
$filename = 'CompInfo' + ' ' + $(Get-Date).ToString($filedate)
#Creates custom table and sorts the information
$table= New-Object –TypeName PSObject -Property #{
'Date/Time' = $time
'Username' = $username
'ComputerName'= $computername
'IPv4 Address' = $ipv4
'IPv6 Address' = $ipv6
'Notes/Action' = $action
} | Select date/time, username, computername, 'IPv4 Address', 'IPv6 Address', notes/action
$table | Export-Csv "d:\$env:username.csv" -NoClobber -append -NoTypeInformation

Try this
#Thanks to Dmitry Sotnikov
#https://dmitrysotnikov.wordpress.com/2010/01/19/export-csv-append/
#### Append CSV Powershell 2.0
function Export-CSV {
[CmdletBinding(DefaultParameterSetName='Delimiter',
SupportsShouldProcess=$true, ConfirmImpact='Medium')]
param(
[Parameter(Mandatory=$true, ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[System.Management.Automation.PSObject]
${InputObject},
[Parameter(Mandatory=$true, Position=0)]
[Alias('PSPath')]
[System.String]
${Path},
#region -Append (added by Dmitry Sotnikov)
[Switch]
${Append},
#endregion
[Switch]
${Force},
[Switch]
${NoClobber},
[ValidateSet('Unicode','UTF7','UTF8','ASCII','UTF32',
'BigEndianUnicode','Default','OEM')]
[System.String]
${Encoding},
[Parameter(ParameterSetName='Delimiter', Position=1)]
[ValidateNotNull()]
[System.Char]
${Delimiter},
[Parameter(ParameterSetName='UseCulture')]
[Switch]
${UseCulture},
[Alias('NTI')]
[Switch]
${NoTypeInformation})
begin
{
# This variable will tell us whether we actually need to append
# to existing file
$AppendMode = $false
try {
$outBuffer = $null
if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
{
$PSBoundParameters['OutBuffer'] = 1
}
$wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Export-Csv',
[System.Management.Automation.CommandTypes]::Cmdlet)
#String variable to become the target command line
$scriptCmdPipeline = ''
# Add new parameter handling
#region Dmitry: Process and remove the Append parameter if it is present
if ($Append) {
$PSBoundParameters.Remove('Append') | Out-Null
if ($Path) {
if (Test-Path $Path) {
# Need to construct new command line
$AppendMode = $true
if ($Encoding.Length -eq 0) {
# ASCII is default encoding for Export-CSV
$Encoding = 'ASCII'
}
# For Append we use ConvertTo-CSV instead of Export
$scriptCmdPipeline += 'ConvertTo-Csv -NoTypeInformation '
# Inherit other CSV convertion parameters
if ( $UseCulture ) {
$scriptCmdPipeline += ' -UseCulture '
}
if ( $Delimiter ) {
$scriptCmdPipeline += " -Delimiter '$Delimiter' "
}
# Skip the first line (the one with the property names)
$scriptCmdPipeline += ' | Foreach-Object {$start=$true}'
$scriptCmdPipeline += '{if ($start) {$start=$false} else {$_}} '
# Add file output
$scriptCmdPipeline += " | Out-File -FilePath '$Path'"
$scriptCmdPipeline += " -Encoding '$Encoding' -Append "
if ($Force) {
$scriptCmdPipeline += ' -Force'
}
if ($NoClobber) {
$scriptCmdPipeline += ' -NoClobber'
}
}
}
}
$scriptCmd = {& $wrappedCmd #PSBoundParameters }
if ( $AppendMode ) {
# redefine command line
$scriptCmd = $ExecutionContext.InvokeCommand.NewScriptBlock(
$scriptCmdPipeline
)
} else {
# execute Export-CSV as we got it because
# either -Append is missing or file does not exist
$scriptCmd = $ExecutionContext.InvokeCommand.NewScriptBlock(
[string]$scriptCmd
)
}
# standard pipeline initialization
$steppablePipeline = $scriptCmd.GetSteppablePipeline(
$myInvocation.CommandOrigin)
$steppablePipeline.Begin($PSCmdlet)
} catch {
throw
}
}
process
{
try {
$steppablePipeline.Process($_)
} catch {
throw
}
}
end
{
try {
$steppablePipeline.End()
} catch {
throw
}
}
}
#### Append CSV Powershell 2.0
$ErrorActionPreference = 'Continue'
####**** Tracking user logon *****#####
$username = $env:USERNAME
$computername = $env:COMPUTERNAME
$ipv4 = Test-Connection -ComputerName (hostname) -Count 1 | foreach { $_.ipv4address }
$ipv6 = Test-Connection -ComputerName (hostname) -Count 1 | foreach { $_.ipv6address }
$timeformat='MM-dd-yyyy hh:mm:ss tt'
$time = (Get-Date).ToString($timeformat)
$action = 'Logon'
$filedate = 'MM-dd-yyyy'
$filename = 'CompInfo' + ' ' + $(Get-Date).ToString($filedate)
#Creates custom table and sorts the information
$table= New-Object –TypeName PSObject -Property #{
'Date/Time' = $time
'Username' = $username
'ComputerName'= $computername
'IPv4 Address' = $ipv4
'IPv6 Address' = $ipv6
'Notes/Action' = $action
} | Select date/time, username, computername, 'IPv4 Address', 'IPv6 Address', notes/action
$table | Export-Csv "D:\$env:username.csv" -NoClobber -Append -Delimiter ',' -NoTypeInformation

Related

Powershell - how to check logged users in specific Machines

I have a code to check on local machines logged sessions as below
Get-WmiObject win32_networkloginprofile | ? {$_.lastlogon -ne $null} | % {[PSCustomObject]#{User=$_.caption; LastLogon=[Management.ManagementDateTimeConverter]::ToDateTime($_.lastlogon)}}
Is it possible to check it for specific machines a logged sessions , even the one that have status "disconnected" ?
Obviously you need rights on the target computers:
Function Get-LoggedOnUser {
param(
[CmdletBinding()]
[Parameter(ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[string[]]$ComputerName = 'localhost'
)
begin {
$ErrorActionPreference = 'Stop'
}
process {
foreach ($Computer in $ComputerName) {
try {
quser /server:$Computer 2>&1 | Select-Object -Skip 1 | ForEach-Object {
$CurrentLine = $_.Trim() -Replace '\s+',' ' -Split '\s'
# If session is disconnected different fields will be selected
if ($CurrentLine[2] -eq 'Disc') {
[pscustomobject]#{
UserName = $CurrentLine[0];
ComputerName = $Computer;
SessionName = $null;
Id = $CurrentLine[1];
State = $CurrentLine[2];
IdleTime = $CurrentLine[3];
LogonTime = $CurrentLine[4..($CurrentLine.GetUpperBound(0))] -join ' '
}
# LogonTime = $CurrentLine[4..6] -join ' ';
}
else {
[pscustomobject]#{
UserName = $CurrentLine[0];
ComputerName = $Computer;
SessionName = $CurrentLine[1];
Id = $CurrentLine[2];
State = $CurrentLine[3];
IdleTime = $CurrentLine[4];
LogonTime = $CurrentLine[5..($CurrentLine.GetUpperBound(0))] -join ' '
}
}
}
}
catch {
New-Object -TypeName PSCustomObject -Property #{
ComputerName = $Computer
Error = $_.Exception.Message
} | Select-Object -Property UserName,ComputerName,SessionName,Id,State,IdleTime,LogonTime,Error
}
}
}
}

Exporting each variable value in loop

I am trying to capture the changing variable '$server' everytime the parameters go through a foreach loop. To summarize, the $sever value is always changing, and I want to capture it and add it into a collective csv file
Thank you!
Here is the code main part of the code that I have.
function Convert-QueryToObjects
{
[CmdletBinding()]
[Alias('QueryToObject')]
[OutputType([PSCustomObject])]
param
(
[Parameter(Mandatory = $false,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
Position = 0)]
[Alias('ComputerName', 'Computer')]
[string]
$Name = $env:COMPUTERNAME
)
Process
{
Write-Verbose "Running query.exe against $Name."
$Users = query user /server:$Name 2>&1
if ($Users -like "*No User exists*")
{
# Handle no user's found returned from query.
# Returned: 'No User exists for *'
Write-Error "There were no users found on $Name : $Users"
Write-Verbose "There were no users found on $Name."
}
elseif ($Users -like "*Error*")
{
# Handle errored returned by query.
# Returned: 'Error ...<message>...'
Write-Error "There was an error running query against $Name : $Users"
Write-Verbose "There was an error running query against $Name."
}
elseif ($Users -eq $null -and $ErrorActionPreference -eq 'SilentlyContinue')
{
# Handdle null output called by -ErrorAction.
Write-Verbose "Error action has supressed output from query.exe. Results were null."
}
else
{
Write-Verbose "Users found on $Name. Converting output from text."
# Conversion logic. Handles the fact that the sessionname column may be populated or not.
$Users = $Users | ForEach-Object {
(($_.trim() -replace ">" -replace "(?m)^([A-Za-z0-9]{3,})\s+(\d{1,2}\s+\w+)", '$1 none $2' -replace "\s{2,}", "," -replace "none", $null))
} | ConvertFrom-Csv
Write-Verbose "Generating output for $($Users.Count) users connected to $Name."
# Output objects.
foreach ($User in $Users)
{
Write-Verbose $User
if ($VerbosePreference -eq 'Continue')
{
# Add '| Out-Host' if -Verbose is tripped.
[PSCustomObject]#{
ComputerName = $Name
Username = $User.USERNAME
SessionState = $User.STATE.Replace("Disc", "Disconnected")
SessionType = $($User.SESSIONNAME -Replace '#', '' -Replace "[0-9]+", "")
} | Out-Host
}
else
{
# Standard output.
[PSCustomObject]#{
ComputerName = $Name
Username = $User.USERNAME
SessionState = $User.STATE.Replace("Disc", "Disconnected")
SessionType = $($User.SESSIONNAME -Replace '#', '' -Replace "[0-9]+", "")
}
}
}
}
}
}
$Servers = Get-Content 'H:\demo\computernames.txt'
foreach ($Server in $Servers)
{
if (-not( Test-Connection $Server -Count 1 -Quiet )) { continue }
if (-not( Convert-QueryToObjects $Server -ErrorAction SilentlyContinue)) {
$server | Out-File 'H:\demo\session\run1.csv' -Append
}
else
{
Convert-QueryToObjects -Name $Server | select ComputerName, Username, Sessionstate, IdleTime, ID | Export-Csv 'H:\demo\session\run.csv' -NoTypeInformation
}
}
Create an array outside of your foreach loop and add the $server variable value to the array during your foreach. At the end export the array to a csv.
Not tested, but are you wanting to do something like this?
Get-Content "H:\demo\computernames.txt" | ForEach-Object {
$computerName = $_
if ( Test-Connection $computerName -Count 1 -Quiet ) {
Convert-QueryToObjects $computerName -ErrorAction SilentlyContinue
}
else {
"$_ not pingable" | Out-File "H:\demo\session\notpingable.log" -Append
}
} | Export-Csv "H:\demo\session\run.csv" -NoTypeInformation

Is there any script to get logged in user info via email

Hi guys I am wondering if there is any script that will notify with email about logged in user information like username, computer name, client ip, client name, date and time etc.
Here is the script i get from technet but it displays computer name as local host, can it output a logged file and email as attachment?
Param(
[CmdletBinding()]
[Parameter(ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[string[]]$ComputerName = 'localhost'
)
Begin {
$ErrorActionPreference = 'Stop'
}
Process {
foreach ($Computer in $ComputerName) {
try {
quser /server:$Computer 2>&1 | Select-Object -Skip 1 | ForEach-Object {
$CurrentLine = $_.Trim() -Replace '\s+',' ' -Split '\s'
$HashProps = #{
UserName = $CurrentLine[0]
ComputerName = $Computer
}
# If session is disconnected different fields will be selected
if ($CurrentLine[2] -eq 'Disc') {
$HashProps.SessionName = $null
$HashProps.Id = $CurrentLine[1]
$HashProps.State = $CurrentLine[2]
$HashProps.IdleTime = $CurrentLine[3]
$HashProps.LogonTime = $CurrentLine[4..6] -join ' '
$HashProps.LogonTime = $CurrentLine[4..($CurrentLine.GetUpperBound(0))] -join ' '
} else {
$HashProps.SessionName = $CurrentLine[1]
$HashProps.Id = $CurrentLine[2]
$HashProps.State = $CurrentLine[3]
$HashProps.IdleTime = $CurrentLine[4]
$HashProps.LogonTime = $CurrentLine[5..($CurrentLine.GetUpperBound(0))] -join ' '
}
New-Object -TypeName PSCustomObject -Property $HashProps |
Select-Object -Property UserName,ComputerName,SessionName,Id,State,IdleTime,LogonTime,Error
}
} catch {
New-Object -TypeName PSCustomObject -Property #{
ComputerName = $Computer
Error = $_.Exception.Message
} | Select-Object -Property UserName,ComputerName,SessionName,Id,State,IdleTime,LogonTime,Error
}
}
}
I guess script usage should be:
save it in a .ps1 file
call it with a -ComputerName 'hostname' parameter, allowing you to choose the targeted computer
Here, 'localhost' is the default value for this parameter.
To send an email, check the Send-MailMessage cmdlet (PS 3.0 required).
If you need to run a script as a scheduled task, set the Action fields like this:
program = C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
arguments = -File "C:\path\to\script.ps1"

Using powershell to modify notes.ini

I have a powershell script that parses a lotus notes INI file and replaces text inside the file. But only the replaced text is showing up in the output file.
# Example of PowerShell -replace parameter
## Get-DistinguishedName -- look up a DN from a user's (login) name
function Get-DistinguishedName {
Param($UserName)
$ads = New-Object System.DirectoryServices.DirectorySearcher([ADSI]'')
$ads.filter = "(&(objectClass=Person)(samAccountName=$UserName))"
$s = $ads.FindOne()
return $s.GetDirectoryEntry().DistinguishedName
}
clear-Host
set-executionpolicy remotesigned
$original_file = '.\notes.ini'
$destination_file = '.\notes2.ini'
$OS = Get-WmiObject -Class win32_OperatingSystem -namespace "root\CIMV2" -ComputerName .
$username = [Environment]::UserName
$userprofile = $env:userprofile
$fullname = Get-DistinguishedName($username) | %{$data = $_.split(","); $data[0].Substring(3)}
write-Host "Creating $userprofile"
if (($OS.Version -eq "5.1.2600") -or ($OS.Version -eq "5.2.3790")) {
$lookupTable = #{
'^SU_FILE_CLEANUP=' = 'SU_FILE_CLEANUP=' + $userprofile + '\Local Settongs\Application Data\smkits'
'%username%' = $username
'%fullname%' = $fullname
'%userprofile%' = $userprofile
'^Directory=' = 'Directory=' + $userprofile + '\Local Settongs\Application Data\Lotus\Notes\Data'}
} else {
$lookupTable = #{
'SU_FILE_CLEANUP=' = 'SU_FILE_CLEANUP=' + $userprofile + '\AppData\Roaming\smkits'
'%username%' = $username
'%fullname%' = $fullname
'%userprofile%' = $userprofile
'Directory=' = 'Directory=' + $userprofile + '\AppData\Local\Lotus\Notes\Data'}
}
Get-Content -Path $original_file | ForEach-Object {
$line = $_
$lookupTable.GetEnumerator() | ForEach-Object {
if ($line -match $_.Key)
{
$line -replace $_.Key, $_.Value
#break
}
}
write-Host $line
} | Set-Content -Path $destination_file
What am I missing
On this line, you are writing he output of the replace operator onto the pipeline, this will then get picked up by Set-Content
$line -replace $_.Key, $_.Value
whereas on this line, you are writing the output to the host (i.e. the powershell console) it will not end up on the pipeline and will not get picked up up Set-Content:
write-Host $line
To fix this, just replace write-host with write-output:
Write-Output $line

Get Active Directory Attributes for Users on Legacy Exchange Servers

I would like to create a CSV file of the users on our Exchange 2003 servers, and include some attributes from their AD account. In particular, I would like to pull certain AD values for the users with RecipientTypeDetails = LegacyMailbox.
I have tried a few different methods for targeting and filtering (ldapfilter, filter, objectAttribute, etc.) these users, with little success. The Exchange 2003 PowerPack for PowerGUI was helpful, but permissions issues and using the Exchange_Mailbox class are not challenges I want to overcome.
I was finally able to create a working script, but it is very slow. The script I've created below is currently working, although it is on track to take about 4+ hours to complete. I'm am looking for suggestions for improving the efficiency of my script or otherwise obtaining this data in a quicker manner. Here is the script:
$ADproperties = 'City','Company','department','Description','DistinguishedName','DisplayName','FirstName','l','LastName','msExchHomeServerName','NTAccountName','ParentContainer','physicaldeliveryofficename','SamAccountName','useraccountcontrol','UserPrincipalName'
get-user -ResultSize Unlimited -ignoredefaultscope -RecipientTypeDetails LegacyMailbox | foreach {Get-QADUser $_.name -DontUseDefaultIncludedProperties -IncludedProperties $ADproperties} | select $ADproperties | epcsv C:\UserListBuilder\exchUsers.csv -notype
Any help you can provide will be greatly appreciated!
I solved this challenge using a script I already created which merges a CSV file with attributes from AD. Basically I used Get-Mailbox to generate a CSV list of all of the Exchange 2003 users, then use that list as input for Get-QADuser to pull the AD attributes I need, and couldn't pull with other cmdlets. The Merge-Object and Export-CSV functions were found from other users on the internet, both very handy functions. Below is a copy of the script:
Function Merge-Object($Base, $Additional)
{
ForEach ($Property in $($Additional | Get-Member -Type Property, NoteProperty))
{
$Base | Add-Member -MemberType NoteProperty -Name $Property.Name -Value $Additional.$($Property.Name) -ErrorAction SilentlyContinue
}
Return $Base
}
Function Export-CSV
{
[CmdletBinding(DefaultParameterSetName='Delimiter',
SupportsShouldProcess=$true, ConfirmImpact='Medium')]
param(
[Parameter(Mandatory=$true, ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[System.Management.Automation.PSObject]
${InputObject},
[Parameter(Mandatory=$true, Position=0)]
[Alias('PSPath')]
[System.String]
${Path},
#region -Append (added by Dmitry Sotnikov)
[Switch]
${Append},
#endregion
[Switch]
${Force},
[Switch]
${NoClobber},
[ValidateSet('Unicode','UTF7','UTF8','ASCII','UTF32','BigEndianUnicode','Default','OEM')]
[System.String]
${Encoding},
[Parameter(ParameterSetName='Delimiter', Position=1)]
[ValidateNotNull()]
[System.Char]
${Delimiter},
[Parameter(ParameterSetName='UseCulture')]
[Switch]
${UseCulture},
[Alias('NTI')]
[Switch]
${NoTypeInformation})
begin
{
# This variable will tell us whether we actually need to append
# to existing file
$AppendMode = $false
try {
$outBuffer = $null
if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
{
$PSBoundParameters['OutBuffer'] = 1
}
$wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Export-Csv',
[System.Management.Automation.CommandTypes]::Cmdlet)
#String variable to become the target command line
$scriptCmdPipeline = ''
# Add new parameter handling
#region Dmitry: Process and remove the Append parameter if it is present
if ($Append) {
$PSBoundParameters.Remove('Append') | Out-Null
if ($Path) {
if (Test-Path $Path) {
# Need to construct new command line
$AppendMode = $true
if ($Encoding.Length -eq 0) {
# ASCII is default encoding for Export-CSV
$Encoding = 'ASCII'
}
# For Append we use ConvertTo-CSV instead of Export
$scriptCmdPipeline += 'ConvertTo-Csv -NoTypeInformation '
# Inherit other CSV convertion parameters
if ( $UseCulture ) {
$scriptCmdPipeline += ' -UseCulture '
}
if ( $Delimiter ) {
$scriptCmdPipeline += " -Delimiter '$Delimiter' "
}
# Skip the first line (the one with the property names)
$scriptCmdPipeline += ' | Foreach-Object {$start=$true}'
$scriptCmdPipeline += '{if ($start) {$start=$false} else {$_}} '
# Add file output
$scriptCmdPipeline += " | Out-File -FilePath '$Path' -Encoding '$Encoding' -Append "
if ($Force) {
$scriptCmdPipeline += ' -Force'
}
if ($NoClobber) {
$scriptCmdPipeline += ' -NoClobber'
}
}
}
}
$scriptCmd = {& $wrappedCmd #PSBoundParameters }
if ( $AppendMode ) {
# redefine command line
$scriptCmd = $ExecutionContext.InvokeCommand.NewScriptBlock(
$scriptCmdPipeline
)
} else {
# execute Export-CSV as we got it because
# either -Append is missing or file does not exist
$scriptCmd = $ExecutionContext.InvokeCommand.NewScriptBlock(
[string]$scriptCmd
)
}
# standard pipeline initialization
$steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
$steppablePipeline.Begin($PSCmdlet)
} catch {
throw
}
}
process
{
try {
$steppablePipeline.Process($_)
} catch {
throw
}
}
end
{
try {
$steppablePipeline.End()
} catch {
throw
}
}
<#
.ForwardHelpTargetName Export-Csv
.ForwardHelpCategory Cmdlet
#>
}
###################################################################################################################################
# Script
###################################################################################################################################
# Get Start Time
$startDTM = (Get-Date)
$ADproperties = 'FirstName','LastName','userAccountControl','physicaldeliveryofficename','l','City','UserPrincipalName','NTAccountName','SamAccountName','ParentContainer','Description','msExchHomeServerName'
#$CSVdirectory = "C:\UserListBuilder\CSV\Exch2003\*.*" # Directory containing Exchange directory export CSV files, include *.*
$csv = "C:\UserListBuilder\CSV\Exch2003\ex03.csv"
$Outputfilename = "C:\UserListBuilder\Exchange2003-ADInfo.csv"
# Create a file of the legacy mailboxes
Get-Mailbox -ignoredefaultscope -ResultSize 'Unlimited' | where { $_.'RecipientTypeDetails' -eq [Microsoft.Exchange.Data.Directory.Recipient.RecipientTypeDetails]'LegacyMailbox' } | select 'DisplayName','SamAccountName','UserPrincipalName' | epcsv $csv -notype
$CurrentFile = Import-Csv $csv
foreach($Row in $CurrentFile)
{
$CurrentUser = $Row.'UserPrincipalName'
$CurrentUserADinfo = Get-QADUser -identity "$CurrentUser" -DontUseDefaultIncludedProperties -IncludedProperties $ADproperties | select-object $ADproperties
Merge-Object $Row $CurrentUserADinfo
$Row | Export-CSV -Path $Outputfilename -Append -NoTypeInformation
}
# Get End Time
$endDTM = (Get-Date)
# Echo Time elapsed
"Elapsed Time: $(($endDTM-$startDTM).totalseconds) seconds"