Powershell incremental number at start of string - variables

Attempting to increment the start of a string with a number.
foreach ($var in $variables) {
New-EventLog -computername $PC -LogName $var -source $var
}
I wish to increment $var with a number, so the result is like so:
$var = 1Server
$var = 2Server
etc etc.
How do I add in incremental number at the beginning of $var in my foreach statement?
I tried with:
$a = 1
foreach ($var in $variables) {
New-EventLog -computername $PC -LogName ($a++, $var) -source $var
}
But no dice.

You can use the format operator -f to insert the value of $a in the parameter for the Logname
$a = 1
foreach ($var in $variables) {
New-EventLog -computername $PC -LogName ("{0}$var" -f $a++) -source $var
}

Related

Sending the results from a ForEach loop containing the Same SQL Query to 2 separate variables via PowerShell

Doing this query in sql server - it returns 3 rows of data. Running the script with the write-host $1_resultsDataTable and comment out the other variable $2_resultsDataTable- it returns only one row of the data array. Now if I reverse the comments so the $2_resultsDataTable is active for the write-host, it returns 6 rows of data.
How do I set this up so I would see the same 3 rows assigned to both $1_resultsDataTable and $2_resultsDataTable when I dump these variables to view the data results?
[string] $Server= "SERVER"
[string] $Database = "mvTest"
[string] $UserSqlQuery= $("select m.created_date, m.additional_data as ReasonDown from aeroscout.mv_audit m where m.created_date >= '2020-01-18' and m.additional_data like '%query-text%'")
#
$1_resultsDataTable, $2_resultsDataTable = foreach ($x in 1..2) {
$resultsDataTable = New-Object System.Data.DataTable
$resultsDataTable = ExecuteSqlQuery $Server $Database $UserSqlQuery
$resultsDataTable # first loop sends output to $1_resultsDataTable, second loop send to $2_resultsDataTable
Start-Sleep 3
}
# executes a query and populates the $datatable with the data
function ExecuteSqlQuery ($Server, $Database, $SQLQuery) {
$Datatable = New-Object System.Data.DataTable
$Connection = New-Object System.Data.SQLClient.SQLConnection
$Connection.ConnectionString = "server='$Server';database='$Database';Integrated Security=True;"
$Connection.Open()
$Command = New-Object System.Data.SQLClient.SQLCommand
$Command.Connection = $Connection
$Command.CommandText = $SQLQuery
$Reader = $Command.ExecuteReader()
If ($Reader.HasRows) {
while($Reader.Read()) {
$props = #{}
for($i = 0; $i -lt $Reader.FieldCount; $i+=1) {
$name = $Reader.GetName($i)
$value = $Reader.item($i)
$props.Add($name, $value)
}
$obj = new-object PSObject -Property $props
Write-Output $obj
}
}
return $obj
$SqlConnection.Close()
}
#validate we got data
write-host $1_resultsDataTable
Start-Sleep 3
write-host $2_resultsDataTable

How to return a reference value with a method from an extended Powershell object?

I'm trying to extend a Powershell object with a method that
returns a true or false to indicate success
outputs a value by reference ([ref])
I have in my module MyExtensions.psm1.
Update-TypeData -TypeName [MyType] -MemberType ScriptMethod -memberName TryGetValue -force -value `
{
param(
$myInput,
[ref]$myOutput
)
try
{
# do something with $myInput
$myOutput = …
return $true
}
catch
{
return $false
}
}
The goal is to be able to write in a script or in another module:
Import-Module MyExtensions
$myInput = …
$value = $null
if($myTypeItem.TryGetValue($myInput, $value)
{
# I know that the $value is good
}
Using argument by reference (you just miss $myOutput.Value ="")
function addition ([int]$x, [int]$y, [ref]$R)
{
$Res = $x + $y
$R.value = $Res
}
$O1 = 1
$O2 = 2
$O3 = 0
addition $O1 $O2 ([ref]$O3)
Write-Host "values from addition $o1 and $o2 is $o3"
A more comple answer here.

Building batch insert statement powershell to sql

I have a powershell script that writes every file and its attributes recursively starting from a specific directory. This works but the directories could have as many as 1,000,000 files. What I want to do is batch them at 1000 inserts per transaction. Here is the original PS:
$server = ""
$Database = ""
$Path = "C:\Test"
$Connection = New-Object System.Data.SQLClient.SQLConnection
$Connection.ConnectionString = "server='$Server';database='$Database';trusted_connection=true;"
$Connection.Open()
$Command = New-Object System.Data.SQLClient.SQLCommand
$Command.Connection = $Connection
foreach($file in Get-ChildItem -Verbose -Recurse -Path $Path | Select-Object Name,Length,Mode, Directory,CreationTime, LastAccessTime, LastWriteTime) {
$fileName = $file.Name
$fileSize = ([int]$file.Length)
$fileMode = $file.Mode
$fileDirectory = $file.Directory
$fileCreationTime = [datetime]$file.CreationTime
$fileLastAccessTime = [datetime]$file.LastAccessTime
$fileLastWriteTime = [datetime]$file.LastWriteTime
$sql = "
begin
insert TestPowerShell
select '$fileName', '$fileSize', '$fileMode', '$fileDirectory', '$fileCreationTime', '$fileLastAccessTime', '$fileLastWriteTime'
end
"
$Command.CommandText = $sql
echo $sql
$Command.ExecuteNonQuery()
}
$Connection.Close()
My thoughts are to implement some sort of counter that will keep appending the insert until it reaches 1000 and then jump out of the loop and execute. I cannot figure out with this current setup how to batch at 1000, execute and then pick back up with the get-childitem loop.
Something like this should do:
function Execute-SqlQuery($query){
Write-Host "Executing query:"
Write-Host $query;
}
$data = #(1,2,3,4,5,6,7,8,9,10,11);
$batchSize = 2;
$counter = 0;
$sql = "";
foreach($item in $data){
if($counter -eq $batchSize){
Execute-SqlQuery $sql;
$counter = 0;
$sql = "";
}
$sql += "insert into myTable(id) values($item) `n";
$counter += 1;
}
Execute-SqlQuery $sql;
$server = ""
$Database = ""
$Path = "C:\Test"
$Connection = New-Object System.Data.SQLClient.SQLConnection
$Connection.ConnectionString = "server='$Server';database='$Database';trusted_connection=true;"
$Connection.Open()
$Command = New-Object System.Data.SQLClient.SQLCommand
$Command.Connection = $Connection
# new variables to handle batching
$batchcounter=0
$batchsize=1000
$sqlValues = New-Object Collections.ArrayList
foreach($file in Get-ChildItem -Verbose -Recurse -Path $Path | Select-Object Name,Length,Mode, Directory,CreationTime, LastAccessTime, LastWriteTime) {
$fileName = $file.Name
$fileSize = ([int]$file.Length)
$fileMode = $file.Mode
$fileDirectory = $file.Directory
$fileCreationTime = [datetime]$file.CreationTime
$fileLastAccessTime = [datetime]$file.LastAccessTime
$fileLastWriteTime = [datetime]$file.LastWriteTime
$sqlValues.Add("('$fileName', '$fileSize', '$fileMode', '$fileDirectory', '$fileCreationTime', '$fileLastAccessTime', '$fileLastWriteTime')")
$batchcounter++
# if the counter hits batchsize, run the insert, using lots of:
# insert into table
# values (1,2,3)
# , (4,5,6)
# , (7,8,9)
if ($batchcounter % $batchsize -eq 0) {
$sql = "insert TestPowerShell values {0}" -f ($sqlValues.ToArray() -join "`r`n,")
$Command.CommandText = $sql
Write-Host $sql
$Command.ExecuteNonQuery()
$sqlValues.Clear()
}
}
# catch any remaining files
if ($batchcounter -gt 0) {
$sql = "insert TestPowerShell values {0}" -f ($sqlValues.ToArray() -join "`r`n,")
$Command.CommandText = $sql
Write-Host $sql
$Command.ExecuteNonQuery()
$sqlValues.Clear()
}
$Connection.Close()
For anyone interested - this is one way to do it:
function WriteBatch {
echo $sql
$Command.CommandText = $sql
$Command.ExecuteNonQuery()
}
$server = ""
$Database = ""
$Path = ""
$Counter = 0
$Connection = New-Object System.Data.SQLClient.SQLConnection
$Connection.ConnectionString = "server='$Server';database='$Database';trusted_connection=true;"
$Connection.Open()
$Command = New-Object System.Data.SQLClient.SQLCommand
$Command.Connection = $Connection
[string]$sql = "
begin
insert into TestPowerShell(NameString, FileSize, Mode, Directory, CreationTime, LastAccessTime, LastWriteTime)
values "
foreach($file in Get-ChildItem -Verbose -Recurse -Path $Path | Select-Object Name, Length, Mode, Directory, CreationTime, LastAccessTime, LastWriteTime) {
$fileName = $file.Name
$fileSize = ([int]$file.Length)
$fileMode = $file.Mode
$fileDirectory = $file.Directory
$fileCreationTime = [datetime]$file.CreationTime
$fileLastAccessTime = [datetime]$file.LastAccessTime
$fileLastWriteTime = [datetime]$file.LastWriteTime
$sql = $sql + "('$fileName', '$fileSize', '$fileMode', '$fileDirectory', '$fileCreationTime', '$fileLastAccessTime', '$fileLastWriteTime'),"
$sql += "`n"
$Counter++
If($Counter -eq 900) {
$sql = $sql.Trim().Trim(',')
$sql = $sql + " End"
WriteBatch
$Counter = 0
$sql = "
begin
insert into TestPowerShell(NameString, FileSize, Mode, Directory, CreationTime, LastAccessTime, LastWriteTime)
values "
}
}
if ($Counter -gt 0){
$sql = $sql.Trim().Trim(',')
$sql = $sql + " End"
WriteBatch
}
$Connection.Close()

Formatting a text file when importing into SQL

I can't seem to get a txt file to import correctly to a sql table. Here is a sample from my txt file:
Split/Skill:;File
;Agent Name;Login ID;Extn;AUX Reason;State;Split/Skill;Time;VDN Name
2;Smith, Joe;13429;64629;;AVAIL;0;93;
2;Gates, Bill;13458;64658;;AVAIL;0;85;
First I need to ignore the first line, the second line will be column names. Then I would like it to treat the line breaks as new rows and the semi-colons as new columns.
Here is as close as I could get:
$location = "path"
$file = "file"
$extension = ".txt"
$full = $location + $file + $extension
$all = Get-Content $full
$columns = Get-Content $full
$columns = $columns.Replace("`n`r",",")
   $table = "CREATE TABLE " + $file + "([" + $columns + "] VARCHAR(255))"
Write-Host $table
$Connection = New-Object System.Data.SqlClient.SqlConnection
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$Connection.ConnectionString = "Server=server;Database=db;Integrated Security=True"
$SqlCmd.CommandText = $table
$SqlCmd.Connection = $connection
$Connection.Open()
$sqlCmd.ExecuteNonQuery()
$Connection.Close()
Basically having the final output as:
Any advice is appreciated!
Lots of assumptions here, including assuming the file is trusted. Otherwise, there is a HUGE SQL injection vulnerability...
$location = "path"
$file = "file"
$extension = ".txt"
$full = $location + $file + $extension
$contents = (cat $full) -split "`r`n" | select -Skip 1
$columns = $contents | select -First 1 | % { $_ -split ";" } | % { if($_-eq ''){' '}else{$_} } | % { "[$_] VARCHAR(255)" }
$columns = $columns -join ","
$create = "CREATE TABLE [$file] ($columns)"
$rows = $contents | select -Skip 1 | % { ($_ -split ";" | % { "'$_'" }) -join "," }
$insert = $rows | % { "INSERT INTO [$file] VALUES($_)" }
$command = (#($create) + $insert) -join [Environment]::NewLine
$Connection = New-Object System.Data.SqlClient.SqlConnection
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$Connection.ConnectionString = "Server=server;Database=db;Integrated Security=True"
$SqlCmd.CommandText = $command
$SqlCmd.Connection = $connection
$Connection.Open()
$sqlCmd.ExecuteNonQuery()
$Connection.Close()
It first reads the file (skipping the first line) into $contents. Then, it gets the column definitions from the second line, splitting on ;. It replaces any empty string with a single space. It then takes the remaining lines as the insert statements, again splitting on ;, and joins them to the create statement as a single command.

Powershell Error - Null/Empty Argument

I have a small powershell script that is meant to get column ServerName from a remote SQL database called, Hal0Test > from table, ServerList. However, I can not figure out this Powershell Error.
Newest Code:
Write-Output " `n Start of Hal0 `n";
$connectionString = "Server=QAUTILITYDB01;Database=Hal0Test;Integrated Security=True;"
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
$connection.Open()
$command = $connection.CreateCommand()
$ServerArray = [System.Collections.ArrayList]#()
$query = "SELECT ServerName FROM ServerList"
$command.CommandText = $query
$ServerNames = $command.ExecuteReader()
$table = new-object “System.Data.DataTable”
$table.Load($ServerNames)
$ServerArray = $table | select -Expand ServerName
$ServerArray | ForEach-Object {
# $Server returns each server name
$os = Get-WmiObject -Class Win32_OperatingSystem -Computer $_
$disks = Get-WmiObject -Class Win32_LogicalDisk -Computer $_ |
Where-Object {$_.DriveType -eq 3} |
ForEach-Object {
'{0} {1:D} MB Free/{2:D} MB Used' -f $_.DeviceID,
[int]($_.FreeSpace/1MB), [int]($_.Size/1MB)
}
New-Object -Type PSCustomObject -Property #{
'FQDN' = $_
'ServerName' = $os.PSComputerName
'OperatingSystem' = $os.Caption
'Disks' = $disks -join ' | '
}
$command.CommandText = "UPDATE ServerList SET FQDN = '$_', OS = '$os.Caption' WHERE ServerName = '$os.PSComputerName';"
$result = $command.ExecuteNonQuery()
} | Export-Csv 'C:\Users\king\Desktop\HalO\output.csv' -Delimiter '|' -NoType
Write-Output "`n End of Hal0";
SQL Table:
You changed my ForEach-Object loop to a foreach loop. If you want to use the latter you need to change the current object variable $_ to your loop variable $Server:
foreach ($Server in $ServerArray) {
$os = Get-WmiObject -Class Win32_OperatingSystem -Computer $Server
$disks = Get-WmiObject -Class Win32_LogicalDisk -Computer $Server | ...
...
}
otherwise you need to change the loop back to a ForEach-Object loop:
$ServerArray | ForEach-Object {
$os = Get-WmiObject -Class Win32_OperatingSystem -Computer $_
$disks = Get-WmiObject -Class Win32_LogicalDisk -Computer $_ | ...
...
}
Also, there's no pipe between } and Export-Csv:
$result = $command.ExecuteNonQuery()
} Export-Csv 'C:\Users\mdaraghmeh\Desktop\HalO\output.csv' -Delimiter '|' -NoType
^
here
And even if there were would the foreach loop still be unable to feed its output into the pipeline. If you want to use foreach with a pipeline you must assign the output to a variable:
$output = foreach ($Server in $ServerArray) { ... }
$output | Export-Csv ...
or run it in an expression:
(foreach ($Server in $ServerArray) { ... }) | Export-Csv ...
For direct pipeline processing you need a ForEach-Object loop:
$ServerArray | ForEach-Object { ... } | Export-Csv ...
You need to use a [datatable] to store the result of your select:
$connectionString = "Server=QAUTILITYDB01;Database=Hal0Test;Integrated Security=True;"
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
$connection.Open()
$command = $connection.CreateCommand()
$ServerArray = [System.Collections.ArrayList]#()
$query = "SELECT ServerName FROM ServerList"
$command.CommandText = $query
$ServerNames = $command.ExecuteReader()
$table = new-object "System.Data.DataTable"
$table.Load($ServerNames)
Now $table has your servers name list.