Скрипт PowerShell не работает при вставке записей

может кто-нибудь указать мне, где я допустил ошибку в сценарии 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.

Неясно, когда $severStageData и $diskDriveStageData заполняются. Возможно ли, что вы могли бы предоставить более минимальный минимальный воспроизводимый пример ?

lit 01.07.2024 01:52

@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

Ali 01.07.2024 03:41

Это большой пример кода, который нужно просмотреть. Я бы предложил начать со строки, которая выдает исключение, и добавить немного журналирования для проверки ваших предположений, а затем вернуться к цепочке вызовов, чтобы увидеть, где ваши ожидания не оправдываются. Например, начните с проверки того, что $updateCmd и $insertCmd содержат правильные значения команд и параметров sql — предположительно, там есть нулевое значение, которого вы не ожидаете, которое выдает ошибку, затем проверьте, что параметры $data и $columns заполнены правильно — промойте / повторяйте, пока не обнаружите что-то не так…

mclayton 01.07.2024 07:41
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
66
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в том, что ваш объект $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, который напрямую связан с реальными столбцами.

iRon 01.07.2024 10:39

@mjsqu Исправление имени столбца устранило эту ошибку, но теперь я получаю другую ошибку: Произошла ошибка: Исключение при вызове ".ctor" с аргументом(ами) "2": "Значение не попадает в ожидаемый диапазон".

Ali 01.07.2024 19:18

@Ali - Пожалуйста, задайте новый вопрос и попытайтесь точно определить ту часть кода, которая дает сбой. Как отмечали другие комментаторы, небольшое расследование с вашей стороны поможет вам получить нужные ответы самостоятельно или быстрее от участников этого сайта.

mjsqu 02.07.2024 00:45

Другие вопросы по теме