может кто-нибудь указать мне, где я допустил ошибку в сценарии PowerShell ниже? Я пытаюсь собрать информацию, связанную с SQL Server, и загрузить ее в базу данных Oracle, которая является нашим хранилищем для хранения информации, связанной со средой. Сценарий выдает ошибку, что столбец Server_Name не может быть нулевым во время обновления/вставки (см. журнал), но когда я повторяю переменную, она содержит значение столбца Server_Name. Возможно, у меня неправильный способ загрузки данных или где-то есть синтаксическая ошибка? Любая помощь будет оценена по достоинству.
#Import necessary modules
Import-Module DBAtools
# Path to the Oracle.ManagedDataAccess.dll file
$oracleDllPath = "D:\oracle\product\12.2.0\client_1\odp.net\managed\common\Oracle.ManagedDataAccess.dll"
# Load the assembly
Add-Type -Path $oracleDllPath
# Initialize logging
$logFile = "D:\PowerShell\log.txt"
Start-Transcript -Path $logFile
WRITE-HOST "WE ARE HERE-1"
try {
# Step 1: Get all instance names from Central Management Studio and place them in a variable called $Instances
#$CMSInstance = "CentralManagementServerInstanceName"
#$Instances = Get-DbaCmsRegServer -SqlInstance $CMSInstance -Group "" | Select-Object -ExpandProperty Name
$Instances = "SQLInst1","SQLInst2"
# Initialize arrays to hold accessible and inaccessible instances
$AccessibleInstances = @()
$InaccessibleInstances = @()
# Step 2: Ensure each instance is accessible
foreach ($Instance in $Instances) {
try {
# Check if the instance is accessible
Test-DbaConnection -SqlInstance $Instance -ErrorAction Stop
# If successful, add to AccessibleInstances
$AccessibleInstances += $Instance
} catch {
# If not accessible, add to InaccessibleInstances
$InaccessibleInstances += $Instance
}
}
WRITE-HOST "WE ARE HERE-2"
# Initialize arrays to hold data
$serverStageData = @()
$diskDriveStageData = @()
# Step 5: Loop through each entry in $AccessibleInstances and gather required information
foreach ($Instance in $AccessibleInstances) {
# Example DBAtools commands (replace with actual commands as needed)
$server = Connect-DbaInstance -SqlInstance $Instance
# Gathering Operating System Information
$os = Get-DbaOperatingSystem -ComputerName $server.ComputerName
$computerSystem = Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName $server.ComputerName
$cpu = Get-CimInstance -ClassName Win32_Processor -ComputerName $server.ComputerName
$networkConfig = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -ComputerName $server.ComputerName | Where-Object { $_.IPAddress -ne $null }
WRITE-HOST "WE ARE HERE-3"
# Creating the output object
$serverInfo = [PSCustomObject]@{
ServerName = $server.ComputerName
OSName = $os.OSVersion
OSVersionCode = $os.Version
OSVendorName = $os.Manufacturer
OSPatchLevelCode = $os.Build
CPUVendorName = $cpu.Name[0]
CPUManufacturerName = $cpu.Manufacturer[0]
CPUFrequencyMSR = $cpu.MaxClockSpeed[0]
PhysicalCoreCount = ($cpu | Measure-Object -Property NumberOfCores -Sum).Sum
TotalCoreCount = ($cpu | Measure-Object -Property NumberOfLogicalProcessors -Sum).Sum
PhysicalRAMGBMSR = [math]::round($computerSystem.TotalPhysicalMemory / 1GB, 2)
RAMGBMSR = [math]::round($computerSystem.TotalPhysicalMemory / 1GB, 2)
DomainName = $computerSystem.Domain
OperationalStatusCode = $computerSystem.Status
ManagedByServerName = 'CMS'
IPAddress = $networkConfig.IPAddress[0]
MANAGED_BY_DATABASE_NAME = 'DBAAdmin'
}
WRITE-HOST "WE ARE HERE-4"
#2.TABLE DISK_DRIVE_STAGE
$diskDriveInfo = Get-DbaDiskSpace -ComputerName $server.ComputerName | Select-Object @{label='SERVER_NAME';expression = {$_.ComputerName}}, @{label='DISK_DRIVE_NAME';expression = {$_.Label}}, @{label='CAPACITY_GB_MSR';expression = {$_.SizeInGB}}, @{label='USED_GB_MSR';expression = {$_.SizeInGB - $_.FreeInGB}}, @{label='FREE_SPACE_GB_MSR';expression = {$_.FreeInGB}}, @{label='DISK_DRIVE_LETTER_CODE';expression = {$_.Name}}, @{label='LINUX_MOUNT_POINT_PATH';expression = {'N/A'}}
# Store the gathered information in the respective variables
$serverStageData += $serverInfo
#$diskDriveStageData += $diskDriveInfo
}
# Step 6: Connect to the Oracle database
$oracleConnString = "User Id=myuser;Password=mypwd;Data Source=myoracledb"
$conn = New-Object Oracle.ManagedDataAccess.Client.OracleConnection($oracleConnString)
WRITE-HOST "WE ARE HERE-5"
try {
$conn.Open()
WRITE-HOST "WE ARE HERE-6"
Write-Host "Successfully connected to Oracle database."
} catch {
WRITE-HOST "WE ARE HERE-7"
Write-Host "Failed to connect to Oracle database. Exiting script."
Stop-Transcript
Exit 1
}
WRITE-HOST "WE ARE HERE-8"
# Step 7: Function to update or insert records in Oracle tables.
function Upsert-OracleTable {
param (
[string]$tableName,
[array]$data,
[array]$columns
)
foreach ($record in $data) {
# Ensure no null values are inserted by checking each value
foreach ($column in $columns) {
if ([string]::IsNullOrEmpty($record.$column)) {
Write-Host "Column $column cannot be null. Record: $record"
throw "Column $column cannot be null"
}
}
# Build the query to check if the record exists by comparing all columns
$whereClause = @()
foreach ($column in $columns) {
$whereClause += "$column = :$column"
}
$whereClause = $whereClause -join " AND "
$checkCmd = $conn.CreateCommand()
$checkCmd.CommandText = "SELECT COUNT(*) FROM $tableName WHERE $whereClause"
$checkCmd.Parameters.Clear()
foreach ($column in $columns) {
$checkCmd.Parameters.Add((New-Object Oracle.ManagedDataAccess.Client.OracleParameter($column, $record.$column)))
}
$exists = $checkCmd.ExecuteScalar()
if ($exists -ne 0) {
# Build the update clause
$updateClause = ""
$updateNeeded = $false
foreach ($column in $columns) {
$currentValueCmd = $conn.CreateCommand()
$currentValueCmd.CommandText = "SELECT $column FROM $tableName WHERE $whereClause"
$currentValueCmd.Parameters.Clear()
foreach ($col in $columns) {
$currentValueCmd.Parameters.Add((New-Object Oracle.ManagedDataAccess.Client.OracleParameter($col, $record.$col)))
}
$currentValue = $currentValueCmd.ExecuteScalar()
if ($currentValue -ne $record.$column) {
$updateClause += "$column = :$column, "
$updateNeeded = $true
}
}
if ($updateNeeded) {
# Remove the last comma
$updateClause = $updateClause.Substring(0, $updateClause.Length - 2)
# Build and execute the update command
$updateCmd = $conn.CreateCommand()
$updateCmd.CommandText = "UPDATE $tableName SET $updateClause WHERE $whereClause"
$updateCmd.Parameters.Clear()
foreach ($column in $columns) {
$updateCmd.Parameters.Add((New-Object Oracle.ManagedDataAccess.Client.OracleParameter($column, $record.$column)))
}
$updateCmd.ExecuteNonQuery()
}
} else {
# Build and execute the insert command
$columnsStr = ""
$valuesStr = ""
$insertCmd = $conn.CreateCommand()
foreach ($column in $columns) {
$columnsStr += "$column, "
$valuesStr += ":$column, "
$insertCmd.Parameters.Add((New-Object Oracle.ManagedDataAccess.Client.OracleParameter($column, $record.$column)))
}
# Remove the last commas
$columnsStr = $columnsStr.Substring(0, $columnsStr.Length - 2)
$valuesStr = $valuesStr.Substring(0, $valuesStr.Length - 2)
$insertCmd.CommandText = "INSERT INTO $tableName ($columnsStr) VALUES ($valuesStr)"
Write-Host "Insert Command: $insertCmd.CommandText"
foreach ($param in $insertCmd.Parameters) {
Write-Host "Parameter: $($param.ParameterName) = $($param.Value)"
}
$insertCmd.ExecuteNonQuery()
}
}
}
WRITE-HOST "WE ARE HERE-14"
# Update or insert records in Oracle tables with specific columns
$serverColumns = @("SERVER_NAME", "OPERATING_SYSTEM_NAME", "OPERATING_SYSTEM_VERSION_CODE", "OPERATING_SYSTEM_VENDOR_NAME", "OPERATING_SYSTEM_PTCH_LVL_CODE", "CPU_VENDOR_NAME", "CPU_MANUFACTURER_NAME", "CPU_FREQUENCY_MSR", "PHYSICAL_CORE_CNT", "TOTAL_CORE_CNT", "PHYSICAL_RAM_GB_MSR", "RAM_GB_MSR", "DOMAIN_NAME", "OPERATIONAL_STATUS_CODE", "MANAGED_BY_SERVER_NAME", "IP_ADDRESS", "MANAGED_BY_DATABASE_NAME")
#$diskDriveColumns = @("SERVER_NAME", "DISK_DRIVE_NAME", "CAPACITY_GB_MSR", "FREE_SPACE_GB_MSR", "DISK_DRIVE_LETTER_CODE", "LINUX_MOUNT_POINT_PATH")
WRITE-HOST "WE ARE HERE-15"
# Specify the schema name for each table
$serverTable = "MySchema.SERVER_STAGE_T"
# $diskDriveTable = "MyShema.DISK_DRIVE_STAGE_T"
WRITE-HOST "WE ARE HERE-16"
echo $serverColumns
echo $serverStageData
echo $serverTable
Upsert-OracleTable -tableName $serverTable -data $serverStageData -columns $serverColumns
#Upsert-OracleTable -tableName $diskDriveTable -data $diskDriveStageData -columns $diskDriveColumns
WRITE-HOST "WE ARE HERE-17"
} catch {
Write-Host "An error occurred: $_"
Stop-Transcript
Exit 1
} finally {
# Close the Oracle connection
$conn.Close()
Stop-Transcript
}
Соединение с оракулом работает нормально
Пользователь имеет достаточно прав для вставки/обновления данных в таблицу.
Ошибка: Столбец SERVER_NAME не может иметь значение NULL.
Record: @{ServerName=Server1; OSName=Microsoft Windows Server 2016 Standard; OSVersionCode=10.0.14393; OSVendorName=Microsoft Corporation; OSPatchLevelCode=14393; CPUVendorName=Intel(R) Xeon(R) Platinum 8170 CPU @ 2.10GHz; CPUManufacturerName=GenuineIntel; CPUFrequencyMSR=2095; PhysicalCoreCount=4; TotalCoreCount=4; PhysicalRAMGBMSR=48; RAMGBMSR=48; DomainName=my.domain; OperationalStatusCode=OK; ManagedByServerName=CMSServer; IPAddress=12.11.196.258; MANAGED_BY_DATABASE_NAME=DBAAdmin}
PS>TerminatingError(): "Column SERVER_NAME cannot be null"
Произошла ошибка: столбец SERVER_NAME не может иметь значение NULL.
@lit Я могу подтвердить, что переменная $serverStageData загружена: echo $serverStageData Server1 Microsoft Windows Server 2016 Standard 10.0.14393 Microsoft Corporation 14393 Intel(R) Xeon(R) Platinum 8170 CPU2,10 ГГц GenuineIntel 2095 4 4 48 48 my.domain OK CMSServer 10.10.152.125 DBAAdmin Я застрял именно в этой строке кода: Upsert-OracleTable -tableName $serverTable -data $serverStageData -columns $serverColumns
Это большой пример кода, который нужно просмотреть. Я бы предложил начать со строки, которая выдает исключение, и добавить немного журналирования для проверки ваших предположений, а затем вернуться к цепочке вызовов, чтобы увидеть, где ваши ожидания не оправдываются. Например, начните с проверки того, что $updateCmd
и $insertCmd
содержат правильные значения команд и параметров sql — предположительно, там есть нулевое значение, которого вы не ожидаете, которое выдает ошибку, затем проверьте, что параметры $data
и $columns
заполнены правильно — промойте / повторяйте, пока не обнаружите что-то не так…
Проблема в том, что ваш объект $serverStageData
состоит из элементов, содержащих следующие ключи:
$serverInfo = [PSCustomObject]@{
ServerName = $server.ComputerName
OSName = $os.OSVersion
OSVersionCode = $os.Version
OSVendorName = $os.Manufacturer
OSPatchLevelCode = $os.Build
CPUVendorName = $cpu.Name[0]
CPUManufacturerName = $cpu.Manufacturer[0]
CPUFrequencyMSR = $cpu.MaxClockSpeed[0]
PhysicalCoreCount = ($cpu | Measure-Object -Property NumberOfCores -Sum).Sum
TotalCoreCount = ($cpu | Measure-Object -Property NumberOfLogicalProcessors -Sum).Sum
PhysicalRAMGBMSR = [math]::round($computerSystem.TotalPhysicalMemory / 1GB, 2)
RAMGBMSR = [math]::round($computerSystem.TotalPhysicalMemory / 1GB, 2)
DomainName = $computerSystem.Domain
OperationalStatusCode = $computerSystem.Status
ManagedByServerName = 'CMS'
IPAddress = $networkConfig.IPAddress[0]
MANAGED_BY_DATABASE_NAME = 'DBAAdmin'
}
И вы пытаетесь вставить в таблицу, используя эти имена столбцов:
$serverColumns = @("SERVER_NAME",
"OPERATING_SYSTEM_NAME",
"OPERATING_SYSTEM_VERSION_CODE",
"OPERATING_SYSTEM_VENDOR_NAME",
"OPERATING_SYSTEM_PTCH_LVL_CODE",
"CPU_VENDOR_NAME",
"CPU_MANUFACTURER_NAME",
"CPU_FREQUENCY_MSR",
"PHYSICAL_CORE_CNT",
"TOTAL_CORE_CNT",
"PHYSICAL_RAM_GB_MSR",
"RAM_GB_MSR",
"DOMAIN_NAME",
"OPERATIONAL_STATUS_CODE",
"MANAGED_BY_SERVER_NAME",
"IP_ADDRESS",
"MANAGED_BY_DATABASE_NAME")
Код не работает, поскольку имена свойств объекта $serverInfo
не соответствуют предоставленным вами $serverColumns
. Обновите код, чтобы они совпадали, что может потребовать от вас также обновить базовую таблицу Oracle, в которую вы вставляете данные.
Ошибка, которую вы видите, связана с этой частью функции:
if ([string]::IsNullOrEmpty($record.$column)) {
Write-Host "Column $column cannot be null. Record: $record"
throw "Column $column cannot be null"
}
Ваше сообщение об ошибке показывает:
Record: @{ServerName=Server1;...
Column SERVER_NAME cannot be null
Другими словами:
"ServerName" <> "SERVER_NAME"
Следующий короткий фрагмент кода воспроизводит ошибку:
function Upsert-OracleTable {
param (
#[string]$tableName,
[array]$data,
[array]$columns
)
foreach ($record in $data) {
# Ensure no null values are inserted by checking each value
foreach ($column in $columns) {
if ([string]::IsNullOrEmpty($record.$column)) {
Write-Host "Column $column cannot be null. Record: $record"
throw "Column $column cannot be null"
}
}
}
}
$serverStageData = @([PSCustomObject]@{"ServerName" = "Server1"})
echo $serverStageData
Upsert-OracleTable `
-data $serverStageData `
-columns @("SERVER_NAME")
Хороший улов! В качестве решения я бы рекомендовал избавиться от параметра [array]$columns
и использовать массив $data[0].PSObject.Properties.Name
, который напрямую связан с реальными столбцами.
@mjsqu Исправление имени столбца устранило эту ошибку, но теперь я получаю другую ошибку: Произошла ошибка: Исключение при вызове ".ctor" с аргументом(ами) "2": "Значение не попадает в ожидаемый диапазон".
@Ali - Пожалуйста, задайте новый вопрос и попытайтесь точно определить ту часть кода, которая дает сбой. Как отмечали другие комментаторы, небольшое расследование с вашей стороны поможет вам получить нужные ответы самостоятельно или быстрее от участников этого сайта.
Неясно, когда
$severStageData
и$diskDriveStageData
заполняются. Возможно ли, что вы могли бы предоставить более минимальный минимальный воспроизводимый пример ?