Script PowerShell update SQL Server with csv - powershell

I am trying to make a script that allows to update my SQL Server database from several CSV files with different names, example:
LOHNSJSHM_details.csv
ZULTNQNIW_details.csv
...
Once the data is updated, the file must be deleted automatically.
Here's what I started doing:
If ((Get-PSSnapin | where {$_.Name -match "SqlServerCmdletSnapin100"}) -eq $null)
{
Add-PSSnapin SqlServerCmdletSnapin100
}
If ((Get-PSSnapin | where {$_.Name -match "SqlServerProviderSnapin100"}) -eq $null)
{
Add-PSSnapin SqlServerProviderSnapin100
}
$sql_instance_name = 'ServerSQL01\LAB'
$db_name = 'testdb'
$impcsv = ".\Example.csv"
$data = import-csv $impcsv
$count = 1
foreach($i in $data){
$reference = $i.reference
$quantity = $i.quantite
$query = "UPDATE dbo.F_ARTSTOCK (reference,quantity)
SET quantity = '$quantity'
WHERE reference = '$reference'"
$impcsv = invoke-sqlcmd -Database $db_name -Query $query -serverinstance $sql_instance_name
write-host "Processing row ..........$count" -foregroundcolor green
$count = $count + 1
}
My file has 2 columns (Reference, Quantity) and I have to update a SAGE table based on the reference withdraw quantities from each line of my CSV
Thank you for help.

If ((Get-PSSnapin | where {$_.Name -match "SqlServerCmdletSnapin100"}) -eq $null)
{
Add-PSSnapin SqlServerCmdletSnapin100
}
If ((Get-PSSnapin | where {$_.Name -match "SqlServerProviderSnapin100"}) -eq $null)
{
Add-PSSnapin SqlServerProviderSnapin100
}
$sql_instance_name = 'ServerSQL01\LAB'
$db_name = 'testdb'
$csv_folder = 'C:\temp'
$csv_completed_folder = 'C:\done'
# assuming only csv-files you want to import are located in $csv_folder
$csv_files = Get-Childitem -Path $csv_folder -Filter '*.csv'
foreach($file in $csv_files) {
$impcsv = $file.FullName
write-host "Processing file ..........$impcsv" -foregroundcolor green
$data = import-csv $impcsv
$count = 1
foreach($i in $data) {
$reference = $i.reference
$quantity = $i.quantite
$query = "UPDATE dbo.F_ARTSTOCK (reference,quantity)
SET quantity = '$quantity'
WHERE reference = '$reference'"
$impcsv = invoke-sqlcmd -Database $db_name -Query $query -serverinstance $sql_instance_name
write-host "Processing row ..........$count" -foregroundcolor green
$count = $count + 1
}
}

Related

How to display the variable result as table in email body or console screen?

The below script to get the logon users and send as email was working great but only on the console output only.
I am trying to get the result as a table so the result in the console and the email body will be like:
Server, ConnectionType, User, ID, State
PRDSVR16, rdp-tcp#44, SVC-SQL, 4, Active
PRDSVR10, rdp-tcp#27, Admin.domain, 6, Disc
SVR25-VM,console,domain.admin,8,Active
Open in new window
This is the script:
$Today = Get-Date -Format 'F'
$SessionList = "`n`nRDP Session List - " + $Today + "`n`n"
$CurrentSN = 0
# Get a list of servers from Active Directory
write-progress -activity "Getting list of servers from Active Directory" -status "... please wait ..."
$Servers = (Get-ADComputer -Filter { Enabled -eq $True -and OperatingSystem -like "*Server*" } -Properties OperatingSystem -SearchBase "OU=Data Center,DC=Company,DC=com") |
Where-Object { Test-Connection $_.Name -Count 1 -Quiet } |
Select-Object -ExpandProperty Name
$NumberOfServers = $Servers.Count
# Iterate through the retrieved list to check RDP sessions on each machine
ForEach ($Server in $Servers)
{
Write-Host "Processing $Server ..." -ForegroundColor Yellow
Write-progress -activity "Checking RDP Sessions" -status "Querying $Server" -percentcomplete (($CurrentSN / $NumberOfServers) * 100)
try
{
$SessionList += qwinsta /server:$Server |
Select-Object -Skip 1 |
% {
[PSCustomObject] #{
Type = $_.Substring(1, 18).Trim()
User = $_.Substring(19, 20).Trim()
ID = $_.Substring(41, 5).Trim()
State = $_.Substring(48, 6).Trim()
}
} |
? { $_.Type -notin 'console', 'services', 'rdp-tcp' -and $_.User -ne $null -and $_.User -ne 65536 } |
% {
"`n$Server logged in by $($_.User) on $($_.Type), session id $($_.ID) $($_.state)"
}
}
catch
{
$SessionList += "`n Unable to query " + $Server
write-host "Unable to query $Server! `n $($Error[0].Exception)" -foregroundcolor Red
}
$CurrentSN++
}
# Send the output the screen.
$SessionList + "`n`n"
$sendMailArgs = #{
From = "$env:USERNAME#$env:userdnsdomain"
To = 'SOC#domain.com'
SmtpServer = 'SMTP.domain.com'
Priority = 'High'
Body = $SessionList | Select-Object #{ N = 'Server'; E = { $Server } },
#{ N = 'User'; E = { $_.User } },
#{ N = 'LogonType'; E = { $_.Type } },
#{ N = 'ID'; E = { $_.ID } },
#{ N = 'State'; E = { $_.State } }
Subject = "$($SessionList.Count) Logged On users from $($NumberOfServers) online servers as at $($Today)"
}
Send-MailMessage #sendMailArgs
Rendering collected information in different places is way easier if you keep strict separation between data and presentation (or formatting) of said data.
For the $SessionList for example, that means doing less than what you're currently trying to do inside the loop:
$ErrorList = #()
$SessionList = foreach($server in $servers){
try{
qwinsta /server:$Server |Select-Object -Skip 1 |ForEach-Object {
[PSCustomObject] #{
Server = $server
Type = $_.Substring(1, 18).Trim()
User = $_.Substring(19, 20).Trim()
ID = $_.Substring(41, 5).Trim()
State = $_.Substring(48, 6).Trim()
}
} |Where-Object { $_.Type -notin 'console', 'services', 'rdp-tcp' -and $_.User -ne $null -and $_.User -ne 65536 }
}
catch{
$ErrorList += [pscustomobject]#{
Server = $server
ErrorRecord = $_
}
}
}
Notice how I don't construct any strings - I just create the custom objects, filter them - and then leave them as-is.
Now it becomes much easier to format the data as desired for different output media:
# For console output, simply pipe to Format-Table
$SessionList |Format-Table
if($ErrorList.Count -gt 0){
Write-Warning "The following servers had errors, please inspect"
$ErrorList |Format-Table
}
# For email output we can use `ConvertTo-Html`
$Body = $SessionList |ConvertTo-Html -As Table -Fragment
if($ErrorList.Count -gt 0){
$ErrorTable = $ErrorList |ConvertTo-Html -As Table -Fragment
$Body = $Body,$ErrorTable -join '<br />'
}
$sendMailArgs = #{
# ...
Body = ConvertTo-Html -Body $Body -Title "Session list"
BodyAsHtml = $true
# ...
}

Unable to query remote server with Qwinsta command using Powershell?

The script below is currently configured to perform Qwinsta from multiple online servers, and then send the result as email.
$Today = Get-Date -Format 'F'
$SessionList = "`n`nRDP Session List - " + $Today + "`n`n"
$CurrentSN = 0
# Get a list of servers from Active Directory
write-progress -activity "Getting list of servers from Active Directory" -status "... please wait ..."
$Servers = Get-ADComputer -Filter { Enabled -eq $True -and OperatingSystem -like "*Server*" } -SearchBase "OU=servers,dc=dwlab02,dc=local" | Where-Object { Test-Connection $_.Name -Count 1 -Quiet } | Select-Object -ExpandProperty Name
$NumberOfServers = $Servers.Count
# Iterate through the retrieved list to check RDP sessions on each machine
ForEach ($Server in $Servers) {
$ServerName = $Server.Name
Write-progress -activity "Checking RDP Sessions" -status "Querying $ServerName" -percentcomplete (($CurrentSN / $NumberOfServers) * 100)
# Run qwinsta and grab the output
try {
$queryResults = (qwinsta /server:$ServerName | Select-Object -Skip 1 | ForEach-Object { (($_.trim() -replace "\s+", ",")) } | convertfrom-csv -ErrorAction Stop)
# get session info from the instance
ForEach ($QueryResult in $QueryResults) {
$RDPUser = $($QueryResult.substring(19, 22)).trim()
$SessionType = $($QueryResult.substring(1, 18)).trim()
$SessionID = $($QueryResult.substring(41, 5)).trim()
$ReturnedCurrentState = $($QueryResult.substring(48, 8)).trim()
$RDPUser = $QueryResult.USERNAME
$SessionType = $QueryResult.SESSIONNAME
$SessionID = $QueryResult.ID
$ReturnedCurrentState = $QueryResult.State
If ($ReturnedCurrentState -eq $null) { $CurrentState = "Disconnected" } Else { $CurrentState = "Active" }
# filter out the irrelevant information
If (($RDPUser -ne $NULL) -and ($SessionType -ne "console") -and ($SessionType -ne "services") -and ($SessionType -ne "rdp-tcp") -and ($RDPUser -ne "65536")) {
$SessionList = $SessionList + "`n" + $ServerName + " logged in by " + $RDPUser + " on " + $SessionType + ", session id $SessionID $CurrentState"
}
}
}
catch {
$SessionList = $SessionList + "`n Unable to query " + $ServerName
write-host "Unable to query $ServerName!" -foregroundcolor Red
}
$CurrentSN++
}
# Send the output the screen.
$SessionList + "`n`n"
$sendMailArgs = #{
From = 'sender#domain.com'
To = 'recipient#domain.com'
Subject = "$($SessionList.Count) Logged On users from $($NumberOfServers) online servers as at $($Today)"
SmtpServer = 'smtp.office365.com'
Port = 587
UseSsl = $true
Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Username, (ConvertTo-SecureString -String $Password)
}
Send-MailMessage #sendMailArgs -Body $SessionList
However, the result is always a blank email with the below content:
RDP Session List - Monday, 17 August 2020 12:28:19 PM
Unable to query Unable to query Unable to query Unable to query
Unable to query Unable to query Unable to query Unable to query
Unable to query
How can I fix the above script?

Invoke-sqlcmd not working when inserting csv data

Below mentioned code is generating CSV files successfully, but not inserting into database. Code was working previously, but not now:
Doesn't give error, data is not generating
$DestinationFileName = $DestinationFile
$SourceFileName = $SourceFile
$tableNum = $tableNumber
$DatabaseTable = $DatabaseTableName
$delimiter = ','
$objWord = New-Object -Com Word.Application
$objWord.Visible = $false # $false
$objDocument = $objWord.Documents.Open($SourceFileName,$false,$true)
$LETable = $objDocument.Tables.Item($tableNum)
$LETableCols = $LETable.Columns.Count
$LETableRows = $LETable.Rows.Count
$RawCSV = for($r=1; $r -le $LETableRows; $r++) {
$content= #()
for($c=1; $c -le $LETableCols; $c++) {
$content += ("`"{0}`"" -f $LETable.Cell($r,$c).Range.Text -replace "(`r|`n|`t)|$([char]7)?")
}
$Content -join $delimiter
}
$Csv = $RawCSV | ConvertFrom-Csv
$objDocument.Close()
$objWord.Quit()
# Stop Winword Process
$rc = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($objWord)
$Csv
$Csv | Export-Csv $DestinationFileName -NoTypeInformation
$database = 'Test'
$server = '.'
$table = 'ScanDoc'
Invoke-Sqlcmd -Database $database -ServerInstance $server -Query "Trun
Import-CSV $DestinationFile -Header Col1, Col2 | Select-Object -Skip 1 | ForEach-Object { Invoke-Sqlcmd -Database $database -ServerInstance $server -Query "insert into $table VALUES ('$($SourceFileName)','$($_.Col1)','$($_.Col2)')"}

having trouble with powershell using Out-File to append results to existing file

so I m having this issue with getting my results to write out to an Out-file.
The problem I m having is, if new file item does exist, the error message I m getting is saying the path is null.
Please review the script and let me know your thoughts
thanks
$sScriptVersion = "1.0"
$dir = $PSScriptRoot
$svrlist += $dir + '\' + 'serverlist.txt'
$folder = 'search'
$computername = Get-Content $svrlist
$drv_array = #()
$new_drv_array =#()
$SearchStr = "error"
$log_pth = 'ProgramData\something\something\something\logs'
$file_logs = #()
$log_pth = #()
$log_nme = #()
$srchpath = #()
foreach($server in $computername)
{
$disks = Get-WmiObject -ComputerName $server -Class Win32_LogicalDisk -Filter "DriveType = 3";
foreach($disk in $disks)
{
$drv_array += $disk.DeviceID;
}
$driv =Foreach-Object {$drv_array -replace ":", "$"}
foreach($drv in $driv)
{
$new_drv_array += '\\'+ $server + '\'+ $drv +'\'+ $log_pth
}
}
Foreach($tst_pth in $new_drv_array )
{
$dvr_testpath = test-path $tst_pth
$srchpath += $tst_pth + '\'+ "*.*"
if ($dvr_testpath -eq $false)
{
write-host "This path does not exist " $tst_pth
}
else
{
write-host "This path does exist" $tst_pth
$Sel = Select-String -pattern $SearchStr -Context 2, 3 -path $srchpath
$out_file = New-item -ErrorAction ignore -itemtype File (join-path $dir1 $log_nme)
This is the part I'm having the issues with
$tst = Test-Path $out_file
if($tst -eq $false)
{
write-host "writing out parsed log file"
if($Sel -ne $null)
{
$Sel| Out-File $out_file
}
}
else
{
write-host " parsed log file does exist"
if($Sel -ne $null)
{
$Sel| Out-File -Append $out_file
}
}
}
}

Export table to file twice due to incorrect format

I'm using this code:
Function Main
{
$domain = "LDAP://www.example.com"
$outfile = 'C:\Scripts\Tests\usersDump.csv'
$properties = "SamAccountName", "lastLogonTimestamp", "AccountExpires", "FirstName", "LastName", "distinguishedName", "employeeNumber", "employeeID", "description", "extensionattribute8", "userAccountControl"
Write-Host "Searching AD..."
$dn = New-Object System.DirectoryServices.DirectoryEntry($domain)
$ds = New-Object System.DirectoryServices.DirectorySearcher($dn)
$ds.Filter = '(&(objectCategory=User)(samAccountType:1.2.840.113556.1.4.803:=805306368))'
$ds.PageSize=1000
$ds.PropertiesToLoad.AddRange($properties)
$list = $ds.FindAll()
Write-Host "Complete"
# The AD results are converted to an array of hashtables.
Write-Host "Exporting User Attributes to table..."
$table = #()
$garbageCounter = 0
foreach($item in $list) {
$hash = #{}
foreach($name in $properties){
if ($item.Properties[$name]) {
$hash.$name = $item.Properties[$name][0]
} else {
$hash.$name = $null
}
}
$table += New-Object PSObject -Property $hash
$garbageCounter++
if ($garbageCounter -eq 1000)
{
[System.GC]::Collect()
$garbageCounter = 0
}
}
[System.GC]::Collect()
Write-Host "Complete."
$listOfBadDateValues = '9223372036854775807', '9223372036854770000', '0'
$maxDateValue = '12/31/1600 5:00 PM'
Write-Host "fixing table values for `"lastLogonTimestamp`" and `"AccountExpires`""
$tableFixedValues = $table | % {
if ($_.lastLogonTimestamp) {
$_.lastLogonTimestamp = ([datetime]::FromFileTime($_.lastLogonTimestamp)).ToString('g')
}; if (($_.AccountExpires) -and ($listOfBadDateValues -contains $_.AccountExpires)) {
$_.AccountExpires = $null
} else {
if (([datetime]::FromFileTime($_.AccountExpires)).ToString('g') -eq $maxDateValue) {
$_.AccountExpires = $null
} Else {
$_.AccountExpires = ([datetime]::FromFileTime($_.AccountExpires)).ToString('g')
}
};$_}
Write-Host "Complete"
Write-Host "Exporting table to csv file $outfile"
$tableFixedValues | Export-Csv $outfile –encoding "unicode" -NoTypeInformation -Force
Write-Host "Complete"
Write-Host "Done."
}
Main
The problem is the file is written so everything is in 1 column. In order to make the properties in their own column, I use this code...
Write-Host "Converting $outfile to csv file $OutputResultsFile"
$outFileFixed = 'C:\Scripts\Tests\usersDumpFixed.csv'
Import-Csv $outfile | Export-Csv $outFileFixed -NoTypeInformation -Force
Write-Host "Complete"
Is there a way I can do this Without having to open-close it again?
Remove the -Encoding Unicode Parameter from the Export-csv then it will not be in one column