I have the follow snippet a powershell script and the nested if statements are not being executed. Can you tell me why ? I've recently got back into the programming game so its probably something simple
$false.
$IgnoreThisLine = $false
$tmpString = "(DATUM CTR OF BLADE)"
$EndOfDescription = $null
$cncPrograms ="(165756 SIDE 1)"
if ($IgnoreThisLine = $false ) {
If ($tmpString -match '\(') {
$EndOfDescription = $false
$cncPrograms = $tmpString
}
else {
$EndOfDescription = $true
}
}
if ($IgnoreThisLine -eq $false)
"-eq" not "=" to test for equality with PowerShell.
Related
I need to load data table to ODBC driver connection with powershell.
With OLEDB and SQL server we can use Bulk Copy and insert data quickly.
Is there such posibility with ODBC ?
I'm using powershell because it shoud have the best support for these kind of opperations,
but my current code doesn't utillise an of the dlls.
So my code firstly needs to create an insert statements with two for loops and iterate on every row and hold it in its memory,
and then to construct INSERT INTO with 1000 rows, and then repeat same thing.
Am i doomed to something like this ?
$Datatable = New-Object System.Data.DataTable
$tabledump= $src_cmd.ExecuteReader()
$Datatable.Load($tabledump)
foreach ($item in $Datatable.Rows) {
$f +=1
for ($i = 0; $i -lt $item.ItemArray.Length; $i++) {
$items = $item[$i] -replace "'" , "''"
$val +="'"+ $items + "',"
}
$vals += $val
if ($f % 1000 -eq 0 -or $f -eq $row_cnt) {
$values = [system.String]::Join(" ", $vals)
$values = $values.TrimEnd(",")
$cols = [system.String]::Join(",", $columns)
$postgresCommand = "Insert Into $dst_schema.$dst_table ($cols) values $values"
$dest_cmd_.CommandText = $postgresCommand
$dest_cmd_.ExecuteNonQuery()
Bad code i admit, any advice on code compositions are welcomed.
You can use Get-ODBCDSN command to retrieve the values of the ODBC connections and use it with a query
$conn.ConnectionString= "DSN=$dsn;"
$cmd = new-object System.Data.Odbc.OdbcCommand($query,$conn)
$conn.open()
$cmd.ExecuteNonQuery()
$conn.close()
https://www.andersrodland.com/working-with-odbc-connections-in-powershell/
But the ODBC provider doesnt do bulk copy
https://learn.microsoft.com/en-us/sql/relational-databases/native-client-odbc-bulk-copy-operations/performing-bulk-copy-operations-odbc?view=sql-server-ver15
I know this post is not new, but i've been fiddeling around looking for a solution and also found nothing, however this post gave me a couple of insights.
First: There is no such thing as 'Bad Code'. If it works is not bad, heck even if it didn't worked, but helped with something..
Alright, what i did is not the best solution, but i'm trying to import Active Directory data on PostgreSQL, so...
I noticed that you're trying with pgsql as well, so you can use the COPY statement.
https://www.postgresql.org/docs/9.2/sql-copy.html
https://www.postgresqltutorial.com/import-csv-file-into-posgresql-table/
In my case i used it with a csv file:
*Assuming you have installed pgsql ODBC driver
$DBConn = New-Object System.Data.Odbc.OdbcConnection
$DBConnectionString = "Driver={PostgreSQL UNICODE(x64)};Server=$ServerInstance;Port=$Port;Database=$Database;Uid=$Username;Pwd=$(ConvertFrom-SecureString -SecureString $Password);"
$DBConn.ConnectionString = $DBConnectionString
try
{
$ADFObject = #()
$ADComputers = Get-ADComputer -Filter * -SearchBase "OU=Some,OU=OrgU,OU=On,DC=Domain,DC=com" -Properties Description,DistinguishedName,Enabled,LastLogonTimestamp,modifyTimestamp,Name,ObjectGUID | Select-Object Description,DistinguishedName,Enabled,LastLogonTimestamp,modifyTimestamp,Name,ObjectGUID
foreach ($ADComputer in $ADComputers) {
switch ($ADComputer.Enabled) {
$true {
$ADEnabled = 1
}
$false {
$ADEnabled = 0
}
}
$ADFObject += [PSCustomObject] #{
ADName = $ADComputer.Name
ADInsert_Time = Get-Date
ADEnabled = $ADEnabled
ADDistinguishedName = $ADComputer.DistinguishedName
ADObjectGUID = $ADComputer.ObjectGUID
ADLastLogonTimestamp = [datetime]::FromFileTime($ADComputer.LastLogonTimestamp)
ADModifyTimestamp = $ADComputer.modifyTimestamp
ADDescription = $ADComputer.Description
}
}
$ADFObject | Export-Csv $Env:TEMP\TempPsAd.csv -Delimiter ',' -NoTypeInformation
docker cp $Env:TEMP\TempPsAd.csv postgres_docker:/media/TempPsAd.csv
$DBConn.Open()
$DBCmd = $DBConn.CreateCommand()
$DBCmd.CommandText = #"
COPY AD_Devices (ADName,ADInsert_Time,ADEnabled,ADDistinguishedName,ADObjectGUID,ADLastLogonTimestamp,ADModifyTimestamp,ADDescription)
FROM '/media/TempPsAd.csv'
DELIMITER ','
CSV HEADER
"#
$DBCmd.ExecuteReader()
$DBConn.Close()
docker exec postgres_docker rm -rf /media/TempPsAd.csv
Remove-Item $Env:TEMP\TempPsAd.csv -Force
}
catch
{
Write-Error "$($_.Exception.Message)"
continue
}
Hope it helps!
Cheers!
is there any way to capture specific error message while this call to store that error message in sql table ?
function Get-SqlData {
param([string]$serverName=$(throw 'serverName is required.'), [string]$databaseName=$(throw 'databaseName is required.'),
[string]$query=$(throw 'query is required.'))
try {
Write-Verbose "Get-SqlData serverName:$serverName databaseName:$databaseName query:$query"
$connection = new-object system.data.sqlclient.sqlconnection( "Data Source=$serverName;Initial Catalog=$databaseName;Integrated Security=SSPI;")
$adapter = new-object system.data.sqlclient.sqldataadapter ($query, $connection)
$table = new-object system.data.datatable
[void]$adapter.Fill($table) #| out-null
$table
} catch {
write-host $Server
write-host 'Connection issue'
}
}
$Query = "set nocount on; SELECT CASE WHEN Is_Clustered = 1 THEN SQLClusterName ELSE ServerName END FROM Server_Master_List WHERE Is_Monitored = 1 "
$Servers = sqlcmd -b -S XYZ-XYZ -d DBA -h -1 -Q $Query -W
$sqltbl = #()
foreach($Server in $Servers) { $sqltbl += Get-SqlData $Server 'master' $qry }
#$sqltbl
<#Insert data from Powershell variable to SQL table #>
$connectionString = "Server=$env:ComputerName;Database=DBA;Integrated Security=SSPI;"
Yes. You can tell PowerShell to only catch certain types of exceptions.
For example...
$serverName = 'SOMERANDOMSERVER'
$databaseName = 'DoesntMatter'
$query = 'SELECT 1'
try {
$connection = New-Object System.Data.SqlClient.SqlConnection ("Data Source=$serverName;Initial Catalog=$databaseName;Integrated Security=SSPI;")
$adapter = New-Object System.Data.SqlClient.SqlDataAdapter ($query, $connection)
$table = New-Object System.Data.DataTable
[void]$adapter.Fill($table)
$table
} catch [System.Data.SqlClient.SqlException] {
'CAUGHT A SQL EXCEPTION!!'
} catch {
'Caught some other type of exception'
}
However, if you want to get further into the details, you'll need to start parsing the exceptions themselves.
And that's where this leads me to ask...why do you need to do this? A query with bad syntax, a query that throws an error, an unavailable server...those will all return a SqlException. Do you plan on implementing something which handles each of these exceptions in a particular way?
Personal opinion:
Any time I see someone starting to write code in PowerShell for running SQL queries, my first question is...Are you trying to build some sort of maintenance/utility script where it's okay to utilize existing community modules? If so, you need to look up dbatools. It's a PowerShell module that is packed with cmdlets that handle all this stuff for you. For example, you've basically just written their cmdlet called Invoke-DbaQuery
Another tip...learn about advanced parameters in PowerShell. You can add various checks against parameters to ensure they are mandatory, and even include verification checks to ensure the parameter values are valid prior to executing the script. That would allow you to properly implement required parameters, and you can remove the hack you've used here.
I'm facing something really strange when executing a little PowerShell script that fetches some information of a local Oralce DB and put the results into objects. The first execution of this scipt takes about 30 seconds, consecutive executions just as much as 2 seconds!
Does anybody have an explanation for this? (is it caching in the Oracle-DB? / any way to figure out what is causing the speed burst on the second run?)
function Get-SQLConnection
{
Add-Type -Path $(Join-Path $PSScriptRoot "libs/Oracle.ManagedDataAccess.dll")
$connectionString = 'User Id=FOO;Password=BAR;Data Source=TNSCONNID'
return New-Object Oracle.ManagedDataAccess.Client.OracleConnection($connectionString)
}
function Get-SQLIssueQuery($version)
{
$version = $version.ToString()
return "SELECT ...
FROM ... WHERE $version ..."
}
function Get-IssuesForVersion($dbconn, $version)
{
Write-Verbose "Get-IssuesForVersion $($version.ToString())..."
$issues = #{}
$command=$dbconn.CreateCommand()
$command.CommandText=$(Get-SQLIssueQuery $version)
$reader=$command.ExecuteReader()
while ($reader.Read()) {
$text = $reader[0]
[int]$key = $reader[2].Split("-")[1]
$type = $reader[6]
...
$issues[$key] = [Issue]::new($key, $type, ...)
}
Write-KSDetail "Get-IssuesForVersion '$($version.ToString())' returned $($issues.Count) issues..."
return $issues
}
$timestart = $(Get-Date)
$conn = Get-SQLConnection
$conn.open()
Get-IssuesForVersion $conn "Version XYZ"
$conn.close()
$timeend = $(Get-Date)
$duration = $timeend - $timestart # first run: approx 30 seconds
$timestart = $(Get-Date)
$conn = Get-SQLConnection
$conn.open()
Get-IssuesForVersion $conn "Version XYZ"
$conn.close()
$timeend = $(Get-Date)
$duration = $timeend - $timestart # second run: approx 2 seconds
thanks in advance!
I'm currently writing a script to prompt for user input, but want to continue prompting the user until a workstation\IP address or username is entered. This will be implemented into a larger more robust script but i can't get this portion working. Is my syntax off or am I misunderstanding the logic, probably both.
D????-* is our corporate workstation naming standard (ie DOUAW-7811652)
*-admin refers to administrator accounts that are not supported by the larger script
The code looks like this so far:
Function Admin{
Write-host "Admin Accounts are not supported" -ForegroundColor Red
}
Function Workstation{
Write-Host "Workstation $name"
$workstation = $true
}
Function UserName{
Write-Host "User Name $name"
$UserName = $true
}
DO {
$Name = Read-Host "Please enter the User Name or Workstation(or IP)"
switch -Wildcard ($name){
"*-admin" {Admin}
"D????-*"{Workstation}
"*.*.*.*"{Workstation}
Default {UserName}
}
}
until ($UserName -eq "$true" -or $workstation -eq "$true")
Read-Host "Press any key to exit"
(While I might not have written it like this, I just fixed code so you could get out of your infinite loop)
You might want something like
Function Workstation{
Write-Host "Workstation $name"
return $true
}
Function UserName{
Write-Host "User Name $name"
return $true
}
DO {
$Name = Read-Host "Please enter the User Name or Workstation(or IP)"
switch -Wildcard ($name){
"*-admin" {Admin}
"D????-*"{$workstation = Workstation}
"*.*.*.*"{$workstation = Workstation}
Default {$UserName = UserName}
}
} until ($UserName -eq "$true" -or $workstation -eq "$true")
Probably you mean:
until ($UserName -eq $true -or $workstation -eq $true)
(Note no quotes around $true.)
I just wanted to say that this would be a good use of an advanced function. Define your parameters in a way that they do all the validation and enforce requirements. Something like this would get you very close to what you are looking for.
Function Do-Something
{
[CmdletBinding(DefaultParameterSetName="Username")]
param(
[Parameter(
Mandatory = $true,
HelpMessage = "Please enter a username",
Position = 0,
ParameterSetName = "Username",
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true
)]
[string[]]$Username,
[Parameter(
Mandatory = $true,
HelpMessage = "Please enter a computername",
Position = 0,
ParameterSetName = "Computername",
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true
)]
[ValidatePattern('D\w\w\w\w-|(\d+\.){3}\d+')]
[string[]]$ComputerName
)
process
{
if($Username){Username}
if($ComputerName){Computername}
}
}
Show-Command Do-Something
For my job I often have to script out a table with all its keys, constraints and Triggers (basically a full script to recreate the table) from a Microsoft SQL 2008 server.I also have to do this for procedures and triggers.
What I do now is open SSMS right click the object and select script to and select to script it to a file. So if I have 3 procedures to do and 10 tables and 1 trigger I end up doing this 14 times .
What I would like is a powershell script that I could feed a list of objects to and then it would go and use SMO to script each on out to an individual file.
Thanks for the help
Here is a PowerShell function I use whenever I have to script a database. It should be easy to modify just to scripts the objects you need.
function SQL-Script-Database
{
<#
.SYNOPSIS
Script all database objects for the given database.
.DESCRIPTION
This function scripts all database objects (i.e.: tables, views, stored
procedures, and user defined functions) for the specified database on the
the given server\instance. It creates a subdirectory per object type under
the path specified.
.PARAMETER savePath
The root path where to save object definitions.
.PARAMETER database
The database to script (default = $global:DatabaseName)
.PARAMETER DatabaseServer
The database server to be used (default: $global:DatabaseServer).
.PARAMETER InstanceName
The instance name to be used (default: $global:InstanceName).
.EXAMPLE
SQL-Script-Database c:\temp AOIDB
#>
param (
[parameter(Mandatory = $true)][string] $savePath,
[parameter(Mandatory = $false)][string] $database = $global:DatabaseName,
[parameter(Mandatory = $false)][string] $DatabaseServer = $global:DatabaseServer,
[parameter(Mandatory = $false)][string] $InstanceName = $global:InstanceName
)
try
{
if (!$DatabaseServer -or !$InstanceName)
{ throw "`$DatabaseServer or `$InstanceName variable is not properly initialized" }
$ServerInstance = SQL-Get-Server-Instance $DatabaseServer $InstanceName
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
$s = New-Object Microsoft.SqlServer.Management.Smo.Server($ServerInstance)
$db = $s.databases[$database]
$objects = $db.Tables
$objects += $db.Views
$objects += $db.StoredProcedures
$objects += $db.UserDefinedFunctions
$scripter = New-Object ('Microsoft.SqlServer.Management.Smo.Scripter') ($s)
$scripter.Options.AnsiFile = $true
$scripter.Options.IncludeHeaders = $false
$scripter.Options.ScriptOwner = $false
$scripter.Options.AppendToFile = $false
$scripter.Options.AllowSystemobjects = $false
$scripter.Options.ScriptDrops = $false
$scripter.Options.WithDependencies = $false
$scripter.Options.SchemaQualify = $false
$scripter.Options.SchemaQualifyForeignKeysReferences = $false
$scripter.Options.ScriptBatchTerminator = $false
$scripter.Options.Indexes = $true
$scripter.Options.ClusteredIndexes = $true
$scripter.Options.NonClusteredIndexes = $true
$scripter.Options.NoCollation = $true
$scripter.Options.DriAll = $true
$scripter.Options.DriIncludeSystemNames = $false
$scripter.Options.ToFileOnly = $true
$scripter.Options.Permissions = $true
foreach ($o in $objects | where {!($_.IsSystemObject)})
{
$typeFolder=$o.GetType().Name
if (!(Test-Path -Path "$savepath\$typeFolder"))
{ New-Item -Type Directory -name "$typeFolder"-path "$savePath" | Out-Null }
$file = $o -replace "\[|\]"
$file = $file.Replace("dbo.", "")
$scripter.Options.FileName = "$savePath\$typeFolder\$file.sql"
$scripter.Script($o)
}
}
catch
{
Util-Log-Error "`t`t$($MyInvocation.InvocationName): $_"
}
}
Here's a script to backup an individual object. Simply pass the object name to the function:
http://sev17.com/2012/04/backup-database-object/