Confirm existence of subdirectories - powershell

I am writing a script to query a SQL server to aggregate data that I can use to search through various directories. If the folder does not exist it should write the path that does not exist to a text file at the end of the code.
I created an array to prefill the strings of the paths which are completed by using the SQL data. I'm coming into the issue of input sting was not in a correct format and the issue of it not correctly filling the text document. It will fill the text document with folders that both do and do not exist.
I have tried various configurations. I believe the array could be my issue but I am currently unsure.
Error is as follows:
Cannot convert value "Walker" to type "System.Int32". Error: "Input string was not in a correct format."
At \\cottonwood\users\C.B\My Documents\Untitled1.ps1:36 char:115
+ ... Address)#> + $($Row.'Last Name') + $array[$i]
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastFromStringToInteger
Code is as follows:
$SQLServer = "REDWOOD" #use Server\Instance for named SQL instances!
$SQLDBName = "MARS"
$SqlQuery = "select Account, IsActive, [Last Name] FROM vw_loans WHERE ( Account NOT IN ('100040A','100041A','100044A','100044B','100044C','100079A','100040A','100041A','100044A','100044B','100044C','100079A','100153B','100413B')) AND LEFT(Account,1)<>'_' AND (Account NOT like '%B%') AND (LoanStatus != 'PRELIM') ORDER BY Account"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server = $SQLServer; Database = $SQLDBName; Integrated Security = True"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $SqlQuery
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$SqlConnection.Close()
clear
$DataSet.Tables[0]
$array = "\I. Originations\Final Originations Package","\II. Servicing\A. Communications", "\II. Servicing\B. Foreclosure Documents","\II. Servicing\C. Bankruptcy Documents", "\II. Servicing\D. Amendments & Extensions", "\II. Servicing\E. Property", "\II. Servicing\F. Previous Servicer Data", "\III. Loan Documents", "\IV. Taxes, Insurance, HOA\HOA", "\IV. Taxes, Insurance, HOA\Insurance","\IV. Taxes, Insurance, HOA\Insurance\PMI","\IV. Taxes, Insurance, HOA\Taxes"
foreach ($Row in $dataset.Tables[0].Rows)
{
for($i=0;$i -lt $array.Length; $i++)
{
if($Row.IsActive -eq $True)
{
$CorrPath = "U:\Shared\Loan Documents - Active\" + $($Row.Account) + " - " + <#$(Row.Address)#> + $($Row.'Last Name') + $array[$i]
}
if($Row.IsActive -eq $False)
{
$CorrPath = "U:\Shared\Loan Documents - Inactive\" + $($Row.Account) + " - " + <#$(Row.Address)#> + $($Row.'Last Name') + $array[$i]
}
$FileExist = Test-Path $CorrPath
If($FileExist -eq $False)
{Add-Content $Corrpath -Path "\\cottonwood\users\IT\Missing Folder Location\MissingSubFolders.txt"}
}
}

Looks to me like the parser is confused by what the + operator is supposed to be doing. It's trying to add when it should be concatenating. Try forcing everything to a string:
if($Row.IsActive) {
$CorrPath = "U:\Shared\Loan Documents - Active\" + $($Row.Account.ToString()) + " - " + <#$(Row.Address)#> + $($Row.'Last Name'.ToString()) + $array[$i].ToString()
} else {
$CorrPath = "U:\Shared\Loan Documents - Inactive\" + $($Row.Account.ToString()) + " - " + <#$(Row.Address)#> + $($Row.'Last Name'.ToString()) + $array[$i].ToString()
}
Or else try formatting the filename differently:
$CorrPath = "U:\Shared\Loan Documents - Active\{0} - {1}{2}" -f $Row.Account,$Row.'Last Name',$array[$i]

Related

How to loop through column values from a table and create folders via powershell

I'm trying to achieve the following via powershell:
I have a table(TBL_DDL) with 5 columns (CATALOG,SCHEMA,OBJECT_TYPE,OBJECT_NAME,DDL)
Now, i'm extract data from this table and then trying to create a folder structure by concatenating first 4 columns (CATALOG,SCHEMA,OBJECT_TYPE,OBJECT_NAME) in C: drive and then exporting the data in DDL column in txt file.
For eg: C:\"CATALOG"\"SCHEMA"\"OBJECT_TYPE"\"OBJECT_NAME"\DDL.txt
I'm trying to achieve this via powershell. Can anyone help me please?
$SqlCmd = 'snowsql -c example -d tu_test -s public -q "select catalog,schema,OBJECT_TYPE,OBJECT_NAME,DDL from SF_TBL_DDL limit 2"'
$MultiArray = #(Invoke-Expression $SqlCmd)
$dt = New-Object System.Data.Datatable
[void]$dt.Columns.Add("CATALOG")
[void]$dt.Columns.Add("SCHEMA")
$Output = foreach ($Object in $MultiArray)
{
foreach ($SCHEMA in $Object.SCHEMA)
{
$someother = New-Object -TypeName psobject -Property #{CATALOG = $Object.CATALOG; SCHEMA = $SCHEMA}
$nRow = $dt.NewRow()
$nRow.CATALOG = $someother.CATALOG
$nRow.SCHEMA = $someother.SCHEMA
$dt.Rows.Add($nRow)
}
}
$dt.row.count
At the moment, i'm getting 0 rows in $dt.
Cheers
You can use System.Data.DataTable object the pull your result set and then loop through it to perform the required operation.
Here GetTableValues function will retrieve the table values and then use following cmdlet to create directory and file
New-Item -ItemType "directory" -Path $dirPath
New-Item -ItemType "file" -Path $filePath
Complete code looks like this
function GetTableValues(){
$DBConnectionString = "<Your DB connection string>";
$sqlConn = new-object System.Data.SqlClient.sqlConnection $DBConnectionString;
$sqlConn.Open();
$sqlCommand = $sqlConn.CreateCommand();
$sqlCommand.CommandText = "select catalog,[schema],OBJECT_TYPE,OBJECT_NAME,DDL from TBL_DDL"; ##Put your correct query here
$result = $sqlCommand.ExecuteReader();
$table = New-Object System.Data.DataTable;
$table.Load($result);
$sqlConn.Close();
return $table;
}
$tableValue = GetTableValues;
foreach ($Row in $tableValue)
{
$filePath = "C:\" + $Row.catalog.TrimEnd() + "\" + $Row.schema.TrimEnd() + "\" + $Row.OBJECT_TYPE.TrimEnd() + "\" + $Row.OBJECT_NAME.TrimEnd() + "\" + $Row.DDL.TrimEnd() + ".txt"
$dirPath = "C:\" + $Row.catalog.TrimEnd() + "\" + $Row.schema.TrimEnd() + "\" + $Row.OBJECT_TYPE.TrimEnd() + "\" + $Row.OBJECT_NAME.TrimEnd()
New-Item -ItemType "directory" -Path $dirPath ##Creates directory
New-Item -ItemType "file" -Path $filePath ##Creates file in $dirPath directory
}
This works perfectly fine for me.

Powershell: Foreach cmdlet overwriting dataset with results of last item

My output, will always contain the information from the second item (database), it seems that it is overwriting any values returned for the initial items? I can change the order of the items in to prove this. Please help...
$databaselist = Get-Content D:\AdvancedDB\Server2.txt
$servername = get-content D:\AdvancedDB\Server.txt
$dataSource = $servername
$myuserID = 'userid'
$mypassword = 'password'
$DatabaseIndexInfo =
"SELECT dbschemas.[name] as 'Schema',
dbtables.[name] as 'Table',
dbindexes.[name] as 'Index',
indexstats.avg_fragmentation_in_percent,
indexstats.page_count
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS indexstats
INNER JOIN sys.tables dbtables on dbtables.[object_id] = indexstats.[object_id]
INNER JOIN sys.schemas dbschemas on dbtables.[schema_id] = dbschemas.[schema_id]
INNER JOIN sys.indexes AS dbindexes ON dbindexes.[object_id] = indexstats.[object_id]
AND indexstats.index_id = dbindexes.index_id
WHERE indexstats.database_id = DB_ID()
ORDER BY indexstats.avg_fragmentation_in_percent desc"
$connectionDetails = "Provider=sqloledb; " + "Server=$dataSource; " + "Database=$database; " +
"User
ID=$myuserID; " + " Password=$mypassword; "
$frag16 = #()
foreach ($database in $databaselist) {
##Connect to the data source using the connection details and T-SQL command we provided above, and
open the connection
$connection = New-Object System.Data.OleDb.OleDbConnection $connectionDetails
$command16 = New-Object System.Data.OleDb.OleDbCommand $DatabaseIndexInfo,$connection
$connection.Open()
##Get the results of our command into a DataSet object, and close the connection
$dataAdapter = New-Object System.Data.OleDb.OleDbDataAdapter $command16
$dataSet16 = New-Object System.Data.DataSet
$dataAdapter.Fill($dataSet16)
$connection.Close()
}
$frag16 += $dataset16.Tables | Out-File 'd:\advanceddb\test5.txt'
You will need to move your connection details within the foreach loop. If you need to work with different databases, then you need to update your connection string as well.
foreach ($database in $databaselist) {
$connectionDetails = "Provider=sqloledb; " + "Server=$dataSource; " + "Database=$database; " +
"User ID=$myuserID; " + " Password=$mypassword; "
...
Since connectionDetails is not updated within your loop, you keep seeing the same data.

Script powershell import multiple CSV

I'm doing a script to import CSVs (commands) that update the stock in SQL Server. But I encounter this error when I run the following script:
Invoke-Sqlcmd : La conversion de la valeur varchar '2200100001' a dépassé une colonne int.
L'instruction a été arrêtée.
Au caractère C:\Users\admin\Desktop\updateDb.ps1:36 : 19
+ ... $impcsv = Invoke-Sqlcmd -Database $db_name -Query $query -ServerIns ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation : (:) [Invoke-Sqlcmd], SqlPowerShellSqlExecutionException
+ FullyQualifiedErrorId : SqlError,Microsoft.SqlServer.Management.PowerShell.GetScriptCommand
Here is my powershell script:
$sql_instance_name = 'SERVER\SAGE100'
$db_name = 'SERVER_DB'
$table = "dbo.F_ARTSTOCK"
$csv_folder = 'F:\EUR'
$csv_completed_folder = 'F:\EUR\done'
$batchsize = 50000
$csv_files = Get-Childitem -Path $csv_folder -Filter '*.csv'
$connectionstring = "Data Source=$sql_instance_name;Integrated Security=true;Initial Catalog=$db_name;"
$bulkcopy = New-Object Data.SqlClient.SqlBulkCopy($connectionstring, [System.Data.SqlClient.SqlBulkCopyOptions]::TableLock)
$bulkcopy.DestinationTableName = $table
$bulkcopy.bulkcopyTimeout = 0
$bulkcopy.batchsize = $batchsize
foreach($file in $csv_files) {
$impcsv = $file.FullName
write-host "Processing file ..........$impcsv" -foregroundcolor green
$data = import-csv -Delimiter ";" $impcsv
$count = 1
foreach($i in $data) {
Write-Host $i.Reference
$reference = $i.Reference
$quantity = $i.Quantity
$query = "UPDATE dbo.F_ARTSTOCK (AR_Ref,AS_QteSto)
SET dbo.F_ARTSTOCK.AS_QteSto = dbo.F_ARTSTOCK.AS_QteSto - $quantity
WHERE dbo.F_ARTSTOCK.AR_Ref = $reference"
Write-Host $query
$impcsv = invoke-sqlcmd -Database $db_name -Query $query -ServerInstance $sql_instance_name
write-host "Processing row ..........$count" -foregroundcolor green
$count = $count + 1
}
}
Do you have any idea where the problem would come from?
Thank you for your help.
The error message is in french. Translated it reads: The conversion of the '2200100001' varchar value has exceeded an int column. The instruction has been stopped.
Basically what that means is you have a 32-bit int column on that table and it needs to be of bigint type to handle a larger value... Or go through the data that you're trying to submit and verify that it is accurate (aka: remove that row from the csv. Depending on how sensitive of data you are working on).

Powershell connectivity to SQL server and count extract

I am trying to fetch count of table from SQL server by connecting using Powershell, but I am getting the below error message, but if I just do select on the table instead of count then the same code is returning results, please suggest as I am not getting a solution to this problem.
Error Message:
Exception calling "Fill" with "1" argument(s): "Execution Timeout
Expired. The timeout period elapsed prior to completion of the
operation or the server is not responding."
+ $DataAdapter.Fill($Dataset)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : SqlException
Script:
[string] $Server= "Server_nm"
[string] $Database = "DB_nm"
[string] $UserSqlQuery = $("SELECT count(1) AS cnt FROM [tbl]")
##$resultsDatatable = ExecuteSqlQuery $Server $Database $UserSqlQuery
function GenericSqlQuery ($Server, $Database, $SQLQuery) {
$Datatable = New-Object System.Data.DataTable
$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
$Command.CommandText = $SQLQuery
$DataAdapter = new-object System.Data.SqlClient.SqlDataAdapter $Command
$Dataset = new-object System.Data.Dataset
$DataAdapter.Fill($Dataset)
$Connection.Close()
return $Dataset.Tables[0]
} $resultsDatatable = GenericSqlQuery $Server $Database $UserSqlQuery
#validate we got data
Write-Host ("The table contains: " + $resultsDatatable.Rows.Count + " rows")
You can use the Invoke-Sqlcmd function instead.
# initialize Variables
[string] $Server= "Server_nm"
[string] $Database = "DB_nm"
[string] $UserSqlQuery = $("SELECT count(1) AS cnt FROM [tbl]")
# Invoke-SqlCmd
$resultsDatatable = Invoke-Sqlcmd -ServerInstance $Server -Database $Database -Query $UserSqlQuery
# validate we got data
Write-Host ("The table contains: " + $resultsDatatable.cnt + " rows")

Need help figuring out why Powershell is throwing error 16

I posted this script the other day in an effort to discover a good way to change file extensions when "saving as." I had the problem licked, but as of this morning, the script will not run without errors. Here's the error message I'm getting:
Processing : C:\users\xxx\Desktop\ht\Automatic_Post-Call_Survey.htm
Exception calling "SaveAs" with "16" argument(s): "This is not a valid file name.
Try one or more of the following:
* Check the path to make sure it was typed correctly.
* Select a file from the list of files and folders."
At C:\users\xxx\Desktop\hd.ps1:11 char:20
+ $opendoc.saveas <<<< ([ref]"$docpath\$doc.FullName.doc", [ref]$saveFormat);
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
if "16" is the error code, that represents an inability to delete the directory...but it doesn't appear as if I'm asking for that at all--unless there's some default parameter in place somewhere. I'm pretty much baffled.anyone have any other ideas I can try out?
$docpath = "c:\users\xxx\desktop\do"
$htmPath = "c:\users\xxx\desktop\ht"
$srcfiles = Get-ChildItem $htmPath -filter "*.htm*"
$saveFormat = [Enum]::Parse([Microsoft.Office.Interop.Word.WdSaveFormat], "wdFormatDocument");
$word = new-object -comobject word.application
$word.Visible = $False
$filename = ($_.fullname).substring(0,($_.FullName).lastindexOf("."))
function saveas-document {
$opendoc = $word.documents.open($doc.FullName);
$opendoc.saveas([ref]"$docpath\$filename", [ref]$saveFormat);
$opendoc.close();
}
ForEach ($doc in $srcfiles) {
Write-Host "Processing :" $doc.FullName
saveas-document
$doc = $null
}
$word.quit();
this should do what do you need, but is not the best design :)
$docpath = "c:\users\xxx\desktop\do"
$htmPath = "c:\users\xxx\desktop\ht"
$srcfiles = Get-ChildItem $htmPath -filter "*.htm*"
$saveFormat = [Enum]::Parse([Microsoft.Office.Interop.Word.WdSaveFormat], "wdFormatDocument");
$global:word = new-object -comobject word.application
$word.Visible = $False
#$filename = ($_.fullname).substring(0,($_.FullName).lastindexOf("."))
function saveas-document ($docs) {
$opendoc = $word.documents.open($docs);
$savepath = $docs -replace [regex]::escape($htmPath),"$docpath"
$savepath = $savepath -replace '\.html*', '.doc'
$opendoc.saveas([ref]"$savepath", [ref]$saveFormat);
$opendoc.close();
}
ForEach ($doc in $srcfiles) {
Write-Host "Processing :" $doc.FullName
saveas-document -doc $doc.FullName
$doc = $null
}
$word.quit();