Utilizing MySQL query results - mysql

Need help with solving this problem:
I need to get table data from MySQL DB for further use in script. I'm using this code for accessing MySQL data:
[void][System.Reflection.Assembly]::LoadFrom("C:\Program Files (x86)\MySQL\MySQL Connector Net 6.7.4\Assemblies\v2.0\MySql.Data.dll")
$Connection = New-Object MySql.Data.MySqlClient.MySqlConnection
$Connection.ConnectionString = $ConnectionString
$Connection.Open()
$Command = New-Object MySql.Data.MySqlClient.MySqlCommand($Query, $Connection)
$DataAdapter = New-Object MySql.Data.MySqlClient.MySqlDataAdapter($Command)
$DataSet = New-Object System.Data.DataSet
$RecordCount = $dataAdapter.Fill($dataSet,"data") | Out-Null
$Command.Dispose()
$Table=$DataSet.Tables["data"] | FT -auto
$Connection.Close()
$Table
and it gives me my precious piece of junk:
TASKID TASKTYPE fistNAME secNAME STATUS
------ -------- -------- ------- ------
1111 1 Dep1 0
2222 2 User321 Dep1 0
BUT when I try to, for example export results to CSV:
Export-Csv -Path "c:\test.csv" -InputObject $Table
all I get is:
#TYPE System.Object[]
"Count","Length","LongLength","Rank","SyncRoot","IsReadOnly","IsFixedSize","IsSynchronized"
"6","6","6","1","System.Object[]","False","True","False"
so when I try to parse data in variable like this:
Write-Host $Table
foreach ($Task in $Table) {
Write-Host $Task.TASKID
}
all I get is:
Microsoft.PowerShell.Commands.Internal.Format.FormatStartData
Microsoft.PowerShell.Commands.Internal.Format.GroupStartData
Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData
Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData
Microsoft.PowerShell.Commands.Internal.Format.GroupEndData
Microsoft.PowerShell.Commands.Internal.Format.FormatEndData
Can anyone help me to resove this problem?

This line
$Table=$DataSet.Tables["data"] | FT -auto
transforms your data into an array of FormatStartData objects.
Don't pipe your data into Format-Table when you want to export it. Try this instead:
$DataSet.Tables["data"] | Export-Csv "c:\test.csv"

Related

Powershell and filenames with non-ASCII characters (e.g. Æ)

I am attempting to index my movie collection and in doing so have run across an issue where at least one title is skipped in the import phase due to special characters. The code skips over "Æon Flux" due to it starting with Æ. Would anyone know how to correct this, please?
Clear-Host
# Variables:
$movie_dir = "K:\Movies"
# Because reasons...
$PSDefaultParameterValues['*:Encoding'] = 'utf8'
# Connect to the library MySQL.Data.dll
Add-Type -Path 'C:\Program Files (x86)\MySQL\Connector NET 8.0\Assemblies\v4.8\MySql.Data.dll'
# Create a MySQL Database connection variable that qualifies:
$Connection = [MySql.Data.MySqlClient.MySqlConnection]#{ConnectionString='server=127.0.0.1;uid=username;pwd=password;database=media'}
$Connection.Open()
# Drop the table to clear all entries.
$sql_drop_table = New-Object MySql.Data.MySqlClient.MySqlCommand
$sql_drop_table.Connection = $Connection
$sql_drop_table.CommandText = 'DROP TABLE Movies'
$sql_drop_table.ExecuteNonQuery() | Out-Null
# (Re)create the table.
$sql_create_table = New-Object MySql.Data.MySqlClient.MySqlCommand
$sql_create_table.Connection = $Connection
$sql_create_table.CommandText = 'create table Movies(movie_id INT NOT NULL AUTO_INCREMENT, movie_title VARCHAR(255) NOT NULL, movie_file_date INT, movie_IMDB_id INT, PRIMARY KEY (movie_id))'
$sql_create_table.ExecuteNonQuery() | Out-Null
$movies = Get-ChildItem $movie_dir -File -include *.mp4 -Recurse -Depth 1 |
Select-Object -ExpandProperty FullName |
Sort-Object |
Get-Unique |
where{$_ -ne ""}
foreach ($movie in $movies)
{
# .net function to get just the filename (movie title).
$title = [System.IO.Path]::GetFileNameWithoutExtension($movie)
# Get the creation date of the movie and reformat it to yearmonthday.
$add_date = (Get-ChildItem $movie).CreationTime.toString("yyyyMMdd")
$query = "INSERT INTO Movies(movie_id, movie_title, movie_file_date) VALUES(NULL, #title, $add_date)"
$command = $connection.CreateCommand()
$command.CommandText = $query
# Sanatize single quotes in filenames for input.
$command.Parameters.AddWithValue("#title", $title) | Out-Null
$command.ExecuteNonQuery() | Out-Null
}
# Close the MySQL connection.
$Connection.Close()
Write-Host
Write-Host("Added") $movies.Count ("movies.")
I don't think it is the Get-ChildItem that skips the file with that special character. More likely, you need to tell your MySql to use UTF-8.
For that, have a look at How to make MySQL handle UTF-8 properly
As for your code, I would change this:
$movies = Get-ChildItem $movie_dir -File -include *.mp4 -Recurse -Depth 1 |
Select-Object -ExpandProperty FullName |
Sort-Object |
Get-Unique |
where{$_ -ne ""}
into
$movies = Get-ChildItem -Path $movie_dir -File -Filter '*.mp4' -Recurse -Depth 1 | Sort-Object -Property FullName
and work with the FileInfo objects from there on:
foreach ($movie in $movies) {
$title = $movie.BaseName
# Get the creation date of the movie and reformat it to yearmonthday.
$add_date = '{0}:yyyyMMdd}' -f $movie.CreationTime
. . .
}
Though Æ is not an ASCII character it is not otherwise "special", so I edited the question title and tags to reflect that.
ExecuteNonQuery() returns the number of rows affected by the command; in the case of $command, it's the number of rows inserted. You are discarding this value, however...
$command.ExecuteNonQuery() | Out-Null
...which masks the problem in the event the INSERT fails. Instead, test the result and respond appropriately...
if ($command.ExecuteNonQuery() -eq 1)
{
Write-Host -Message "Successfully inserted movie ""$title""."
}
else
{
Write-Warning -Message "Failed to insert movie ""$title""."
}
This will make it clear if the issue lies in interacting with the filesystem or the database.
Some other notes:
MySqlCommand implements the IDisposable interface and so each instance should be disposed when you're done using it...
$query = "INSERT INTO Movies(movie_id, movie_title, movie_file_date) VALUES(NULL, #title, $add_date)"
$command = $connection.CreateCommand()
try
{
$command.CommandText = $query
# Sanatize single quotes in filenames for input.
$command.Parameters.AddWithValue("#title", $title) | Out-Null
if ($command.ExecuteNonQuery() -eq 1)
{
Write-Host -Message "Successfully inserted movie ""$title""."
}
else
{
Write-Warning -Message "Failed to insert movie ""$title""."
}
}
finally
{
$command.Dispose()
}
...and the same for $sql_drop_table and $sql_create_table. The code in the finally block will run even if an error is thrown from within the try block.
See Difference with Parameters.Add and Parameters.AddWithValue and its links for why AddWithValue() can be problematic.
Instead of...
Write-Host("Added") $movies.Count ("movies.")
...a more typical way to build this message would be with string interpolation...
Write-Host "Added $($movies.Count) movies."
...or the format operator...
Write-Host ('Added {0} movies.' -f $movies.Count)
You can also incorporate numeric format strings, so if $movies.Count is 1234 and $PSCulture is 'en-US' then...
Write-Host "Added $($movies.Count.ToString('N0')) movies."
...and...
Write-Host ('Added {0:N0} movies.' -f $movies.Count)
...will both write...
Added 1,234 movies.

VmWare and Powershell multi-valued attributes

I have a question about multi-valued attributes and how to export them as csv.
While I know how to work with multi-valued attributes I've come to a dead end with this script that I am writing.
Here are the details:
I have to export a csv file that will contain VMName, HardDiskName, FileName etc.
At first I tried this approach (1):
$hdd = Get-HardDisk -VM "vmname" -DiskType RawPhysical| select Parent, Name
$props = #{'VMName' = $hdd.parent
'HDDName' = $hdd.name
}
$obj = New-Object -TypeName PSObject -Property $props
#Write-Output $obj
$obj | Export-Csv vm.csv -NoTypeInformation
I quickly realised that this approach won't work because I am dealing with multi-valued attributes and I won't be able to export them properly.
...than I tried this (approach 2)
$hdd = Get-HardDisk -VM "vmname" -DiskType RawPhysical| select #{Name='VmName';Expression={[string]::join(“;”, ($_.parent))}}, #{Name='HDDName';Expression={[string]::join(“;”, ($_.name))}}
$props = #{'VMName' = $hdd.parent
'HDDName' = $hdd.name
}
$obj = New-Object -TypeName PSObject -Property $props
#Write-Output $obj
$obj | Export-Csv vm.csv -NoTypeInformation
Needles to say that this did not work either.
Some attributes are not multi-valued and I could get them with approach 1 but I cannot get the multi-valued attributes.
if I do this
$hdd = Get-HardDisk -VM svwdbn21 -DiskType RawPhysical| select #{Name='VmName';Expression={[string]::join(“;”, ($_.parent))}}, #{Name='HDDName';Expression={[string]::join(“;”, ($_.name))}},`
#{Name='FileName';Expression={[string]::join(“;”, ($_.filename))}}, #{Name='DeviceName';Expression={[string]::join(“;”, ($_.devicename))}},`
#{Name='CanonicalName';Expression={[string]::join(“;”, ($_.ScsiCanonicalName))}}| Export-csv test.csv
I can get almost all details I need except LUN info which I am getting it with the following piece of code:
$hdd = Get-HardDisk -VM "vmname" -DiskType RawPhysical| select parent, name, filename, devicename, ScsiCanonicalName
$Lun = Get-SCSILun $hdd.SCSICanonicalName -VMHost $vm.vmhost
$lunpaths=$lun|Get-ScsiLunPath
$luns = $lunpaths | select name, sanid, State, Preferred
$luns
... and here is where I got really stuck.
I need a way to combine in one csv file all the multi-valued atributes and LUN info which right now is stored in $luns.
after more research i come up with this:
$vm = Get-VM "vnname"| select name,VMHost
$hdd = Get-HardDisk -VM "vmname" -DiskType RawPhysical| select Parent, Name, Filename, SCSICanonicalName, DeviceName
$Lun = Get-SCSILun $hdd.SCSICanonicalName -VMHost $vm.vmhost
$lunpaths=$lun|Get-ScsiLunPath
$luns = $lunpaths | select name, sanid, State, Preferred
$luns
$props = #{'VMName' = $hdd.parent -join ';'
'HDDName' = $hdd.name -join ';'
'FileName' = $hdd.filename -join ';'
'DeviceName' = $hdd.devicename -join ':'
'CanonicalName' = $hdd.scsicanonicalname -join';'
'LunName' = $luns.name -join ';'
'SANId' = $luns.sanid -join ';'
'State' = $luns.sate -join ';'
'Preferred' = $luns.preferred -join';'
}
$obj = New-Object -TypeName PSObject -Property $props
#Write-Output $obj
$obj | Export-Csv vm.csv -NoTypeInformation
and while I get all the info that I need the csv file looks like this:
HardDisk LunName FileName
Hdd1;hdd2; lun1;lun2;lun3 filename1;filename2
but what I really want is this
HardDisk LunName FileName
Hdd1 lun1 filename1
hdd2 lun2 filename2
hdd3 lun3 filename3
Is this possible?

Get AD distinguished name

I'm trying to take input from a CSV file, which has a list of group names (canonical names) and get the Distinguished Name from it, then output to another CSV file. The code:
#get input file if passed
Param($InputFile)
#Set global variable to null
$WasError = $null
#Prompt for file name if not already provided
If ($InputFile -eq $NULL) {
$InputFile = Read-Host "Enter the name of the input CSV file (file must have header of 'Group')"
}
#Import Active Directory module
Import-Module -Name ActiveDirectory -ErrorAction SilentlyContinue
$DistinguishedNames = Import-Csv -Path $InputFile -Header Group | foreach-Object {
$GN = $_.Group
$DN = Get-ADGroup -Identity $GN | Select DistinguishedName
}
$FileName = "RESULT_Get-DistinguishedNames" + ".csv"
#Export list to CSV
$DNarray | Export-Csv -Path $FileName -NoTypeInformation
I've tried multiple solutions, and none have seemed to work. Currently, it throws an error because
Cannot validate argument on parameter 'Identity'. The argument is null. Supply a non-null argument and try the command again.
I tried using -Filter also, and in a previous attempt I used this code:
Param($InputFile)
#Set global variable to null
$WasError = $null
#Prompt for file name if not already provided
If ($InputFile -eq $NULL) {
$InputFile = Read-Host "Enter the name of the input CSV file(file must have header of 'GroupName')"
}
#Import Active Directory module
Import-Module -Name ActiveDirectory -ErrorAction SilentlyContinue
$DistinguishedNames = Import-Csv -Path $InputFile | foreach {
$strFilter = "*"
$Root = [ADSI]"GC://$($objDomain.Name)"
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher($root)
$objSearcher.Filter = $strFilter
$objSearcher.PageSize = 1000
$objsearcher.PropertiesToLoad.Add("distinguishedname") | Out-Null
$objcolresults = $objsearcher.FindAll()
$objitem = $objcolresults.Properties
[string]$objDomain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
[string]$DN = $objitem.distinguishedname
[string]$GN = $objitem.groupname
#Get group info and add mgr ID and Display Name
$props = #{'Group Name'= $GN;'Domain' = $objDomain;'Distinguished Name' = $DN;}
$DNS = New-Object psobject -Property $props
}
$FileName = "RESULT_Get-DistinguishedNames" + ".csv"
#Export list to CSV
$DistinguishedNames | Sort Name | Export-Csv $FileName -NoTypeInformation
The filter isn't the same one I was using here, I can't find the one I was using, the I currently have is a broken attempt.
Anyway, the main issue I was having is that it will get the group name, but search for it in the wrong domain (it wouldn't include Organizational Units) which caused none of them to be found. When I search for a group in PowerShell though (using Get-ADGroup ADMIN) they show up with the correct DN and everything. Any hints or code samples are appreciated.
You seemingly miss the point of $variable = cmdlet|foreach {script-block} assignment. The objects to assign to $variable should be returned (passed through the script block) in order to end up in $variable. Both your main loops contain the structure of the line $somevar=expectedOutput where expectedOutput is either a New-Object psobject or Get-ADGroup call. The assignment to $someVar suppresses the output, so that the script block does not have anything to return, and $variable remains null. To fix, do not prepend the call that should return an object into outside variable with an assignment.
$DistinguishedNames = Import-Csv -Path $InputFile -Header Group | foreach-Object {
$GN = $_.Group
Get-ADGroup -Identity $GN | Select DistinguishedName # drop '$DN=`
}
$DistinguishedNames | Export-CSV -Path $FileName -NoTypeInformation
The same issue with the second script.

Powershell Storing sqlResults into an array

I have a power shell script that querys the database and returns two columns which are a key value pair. Let's call them a & b.
How do I store this in a map to be called at a later date? Below is mysql code, it runs and prints out columns out to the screen.
$Connection = New-Object MySql.Data.MySqlClient.MySqlConnection
$Connection.ConnectionString = $ConnectionString
$Connection.Open()
$Command = New-Object MySql.Data.MySqlClient.MySqlCommand($Query, $Connection)
$DataAdapter = New-Object MySql.Data.MySqlClient.MySqlDataAdapter($Command)
$DataSet = New-Object System.Data.DataSet
$RecordCount = $dataAdapter.Fill($dataSet, "data")
$DataSet.Tables[0]
Just not sure how to store the key value pair in an mapto be used later. Both columns are numeric.
Thanks.
You want to cycle through each object in the results?
$Records = $DataSet.Tables[0]
$Records.Keys | ForEach-Object {$Record.$_}
This will allow you to iterate through the objects and run some bit of code for each of them.
For instance, I've got a hashtable like this:
$Records = [hashtable]#{'Name'='Stephen';'Hair'='Red'}
The results:
$Records.Keys | ForEach-Object {"object `$Records.$_ = $($Records.$_)"}
>object $Records.Hair = Red
>object $Records.Name = Stephen
If this isn't what you're looking for, please comment so that I can try to help you to a solution.

Powershell SQL query result not fitting

Hi I have constructed a script that works fine except for one thing, sometimes the returned string is so long that it doesnt fit in the powershell console and when I later on send the text to a richtextbox I get all the ....... at the end and not the whole string
$username = "myaccount"
$sqlconnection = New-Object system.data.sqlclient.sqlconnection
$sqlconnection.ConnectionString ="server=myserver\sccm;database=sccm;trusted_connection=true;"
$sqlconnection.Open()
sqlcmd = New-Object system.data.sqlclient.sqlcommand
$sqlcmd = $sqlconnection.CreateCommand()
$sqlcmd.CommandText = "SELECT Info from SCCM.dbo.log WHERE Username = '$username'"
$sqlcmd.Connection = $sqlconnection
$data = New-Object system.data.sqlclient.sqldataadapter $sqlcmd
$dataset = New-Object system.data.dataset
$data.Fill($dataset)
$global:result = $dataset.Tables
I cannot specify the -Width parameter anywhere so I am lost on how to get the full length of the result?
Rather than display in powershell, you could save the dataset as a csv file:
#Fill the dataset with the SQL response. Using [void] redirects console output to null (don't display)
[void]$data.Fill($dataset)
#Pipe the contents of the dataset. Use Select to select all columns/properties excluding those that were created by the DataSet object (not actual data)
#Pipe to Export-CSV to create a CSV file, use -notypeinformation flag to skip Object type information from the file (e.g. System.String etc)
$dataset.Tables[0] | Select * -ExcludeProperty RowError, RowState, HasErrors, Table, ItemArray | Export-CSV -notypeinformation -path C:\Somedir\Somefile.csv