【问题标题】:Set-ADUser skip empty cells from xlsxSet-ADUser 跳过 xlsx 中的空单元格
【发布时间】:2019-11-05 05:12:35
【问题描述】:

我想从 .xlsx 批量更新我们在 DC 上的用户,但脚本应该跳过 xlsx 数据中的空值。

我已经尝试了几种方法,但都不起作用。

第一次尝试是用

hash.GetEnumerator() | foreach {
    if ($_.Value -eq "") {
        $hash.Remove($_.Key)
    }
}

第二次尝试如下代码:

foreach ($h in $hash.Keys) {
    if ($(hash.Item($h)) -eq "") {
        $hash.Remove($h)
try {
    Import-Module ActiveDirectory -ErrorAction Stop -WarningAction Stop
} catch {
    Write-Host "ActiveDirectory module not found!!" -ForegroundColor Red -BackgroundColor Black
    Write-Host "Script Aborted." -ForegroundColor Red -BackgroundColor Black
    # Abort the script.
    break
}

try {
    $credential = Get-Credential

    [Threading.Thread]::CurrentThread.CurrentCulture = 'en-US'
    #Declare file path and sheet name
    $file = "...\UpdateUsers_test.xlsx"
    #Create an Excel.Application instance and open that file
    $Excelobject = New-Object -ComObject Excel.Application
    $Workbook = $Excelobject.Workbooks.Open($file)
    $sheetName = "Sheet1"
    $sheet = $Workbook.Worksheets.Item($sheetName)
    #$objExcel.Visible=$true

    #Count max row
    $rowMax = ($sheet.UsedRange.Rows).Count
    #Count max column
    $colMax = ($sheet.UsedRange.Columns).Count
    $hash = @{}
    $server = "IP-Address"

    #Specify starting positions
    $row, $col = 1, 1
    $updatedCount = 0

    #loop for rows
    for ($i=1; $i -le $rowMax-1; $i++) {
        #loop for columns
        for ($c=0; $c -le $colMax-1; $c++) {
            #Get all columns values to a hash
            $hash += @{$sheet.Cells.Item($row, $col+$c).Text = $sheet.Cells.Item($row+$i, $col+$c).Text}

            foreach ($h in $hash.Keys) {
                if ($(hash.Item($h)) -eq "") {
                    $hash.Remove($h)
                }

                #Create an object and assign hash keys as object property
                $Object = New-Object -TypeName PSObject -Property $hash

                #Get User via SamAccountname
                $user = Get-ADUser -Filter "SamAccountName -eq '$($Object.UserName)'" -
SearchBase 'DC=Domain, DC=local' -Server $server -Credential $credential

                #Set Users attribute with matched object attribute
                $user | Set-ADUser -DisplayName $Object.Displayname `
                    -OfficePhone $Object.PhoneNumber `
                    -EmailAddress $Object.email `
                    -Postalcode $Object.Postalcode `
                    -City $Object.City `
                    -Streetaddress $Object.Streetaddress `
                    -Country $Object.Country `
                    -Office $Object.Office `
                    -Title $Object.Title `
                    -Company $Object.Company `
                    -Department $Object.Department `
                    -Manager $Object.Manager `
                    -Mobile $Object.Mobile `
                    -Fax $Object.Fax

                #If you want to edit Object common name, you can remove enable two lines
below.

                #$userguid = $user.ObjectGUID.Guid
                #$user | Rename-ADObject -NewName $Object.DisplayName -Server $server -
Credential $credential

                $hash = @{}
                Write-Host $User.Name "- User attributes have been updated." -
ForegroundColor Yellow
                Start-Sleep -s 1
                $updatedCount += 1
            }

            Write-Host $updatedCount "Users have been updated" -ForegroundColor Green

            #close excel file
            $Excelobject.Quit()
        }

catch {
    Write-Error $_.Exception.ToString()
    Read-Host -Prompt "The above error occured. Press Enter to exit."
}

【问题讨论】:

  • 您好,欢迎来到 Stack Overflow。我认为如果您将 Excel 导出为 CSV 文件并将其用于输入,会容易得多。 Powershell 具有出色的 cmdlet 可用于处理 CSV,而使用 COM 对象解析 Excel 工作表可能非常困难..
  • “不起作用”是一个不充分的问题描述。你期望代码做什么,它实际上做什么?此外,您发布的最后一个代码 sn-p 有几个语法错误(主要但不完全是由于不正确的换行)。请确保您问题中的代码不会引入实际代码中不存在的新错误。推荐的过程是创建一个minimal reproducible example,验证代码是否显示与您的真实代码相同(错误)的行为,然后发布该代码以及该代码引发的错误。

标签: powershell active-directory


【解决方案1】:

我认为更好的方法是通过 PSObject。有时一条记录可以有多个属性,使用 '' 搜索空值可能会很困难。

相反,您可以使用 PSObject 属性并搜索空值:

$_.PSObject.Properties | ForEach-Object {$_.Value}) -eq $null

【讨论】:

    【解决方案2】:

    我想我会建议您使用 splatting 而不是创建对象,这将涉及使用哈希表来指定 Set-ADUser 的参数。要完成这项工作,哈希表的键必须与 cmdlet 的参数相同。你的很接近,但有一些差异,所以首先我们需要制作一个哈希表来将你的电子表格映射到正确的参数。把它放在你的循环之前。

    $ParamMap = @{
        Displayname = 'DisplayName' 
        PhoneNumber = 'OfficePhone' 
        email = 'EmailAddress' 
        Postalcode = 'Postalcode' 
        City = 'City' 
        Streetaddress = 'Streetaddress' 
        Country = 'Country' 
        Office = 'Office' 
        Title = 'Title' 
        Company = 'Company' 
        Department = 'Department' 
        Manager = 'Manager' 
        Mobile = 'Mobile' 
        Fax = 'Fax'
    }
    

    现在我们稍微修改一下如何创建哈希表以使用它来查找键名(这将替换您的 $hast += 行):

                    $hash.add($ParamMap[$sheet.Cells.Item($row, $col+$c).Text], $sheet.Cells.Item($row+$i, $col+$c).Text)
    

    现在我们有了一个哈希表,我们可以检查 null 或空字符串,并删除它们。

                    $hash.keys | Where{ [string]::IsNullOrWhitespace($hash[$_]) } | ForEach-Object { $Hash.Remove($_) }
    

    该行枚举$hash 的键,并检查每个键的值以查看它是否包含空值或仅包含空格(空格、制表符、新行)。如果它是 null 或空格,它会从哈希表中删除该键。

    现在我们有一个哈希表,其中只有代表 cmdlet 参数的有效键,并且每个键都有一个值,我们将其分配给 Get-ADUser cmdlet,我们都设置好了。

                    $user | Set-ADUser @hash
    

    【讨论】:

      【解决方案3】:

      @TheMadTechnician
      谢谢!
      您的回答对我帮助很大。但我仍然无法将哈希表传递给 Set-ADUser cmdlet。
      不幸的是,我无法自己解决这些错误消息

      #loop for rows 
      for ($i=1; $i -le $rowMax-1; $i++)
      {
      
          #loop for columns
          for($c=0; $c -le $colMax-1; $c++)
          {
            #Get all columns values to a hash
      
            $hash += @{$sheet.Cells.Item($row, $col+$c).Text = $sheet.Cells.Item($row+$i, $col+$c).Text}
      
            $hash.keys.Clone() | Where{ [string]::IsNullOrWhitespace($hash[$_]) } | ForEach-Object { $Hash.Remove($_) }
            $hash | Out-String | Write-Host
      
          }
      
      
         #Create an object and assign hash keys as object property
         $Object = New-Object -TypeName PSObject -Property $hash
      
         #Get User via SamAccountname  
         $user = Get-ADUser -Filter "SamAccountName -eq '$($Object.SamAccountName)'" -SearchBase 'DC=domain, DC=local' -Server $server -Credential $credential 
      
      
      }
      
         #Set Users attribute with matched object attribute
         $user | Set-ADUser   -Replace EmailAddress = $Object.Email; `
                              -Postalcode $Object.Postalcode `
                              -City $Object.City `
                              -Streetaddress $Object.Streetaddress `
                              -Country $Object.Country `
                              -Office $Object.Office `
                              -Title $Object.Title `
                              -Company $Object.Company `
                              -Department $Object.Department `
                              -Manager $Object.Manager `
                              -Mobile $Object.Mobile `
                              -Fax $Object.Fax 
      

      System.Management.Automation.ParameterBindingException:无法绑定参数“替换”。无法转换 “System.String”类型的“EmailAddress”值键入“System.Collections.Hashtable”。 ---> System.Management.Automation.PSInvalidCastException:无法转换“System.String”类型的“EmailAddress”值 键入“System.Collections.Hashtable”。 在 System.Management.Automation.LanguagePrimitives.ThrowInvalidCastException(对象 valueToConvert,类型 resultType) 在 System.Management.Automation.LanguagePrimitives.ConvertNoConversion(对象 valueToConvert,类型 resultType, 布尔递归、PSObject originalValueToConvert、IFormatProvider formatProvider、TypeTable backupTable) 在 System.Management.Automation.LanguagePrimitives.ConversionData1.Invoke(Object valueToConvert, Type resultType, Boolean recurse, PSObject originalValueToConvert, IFormatProvider formatProvider, TypeTable backupTable) at System.Management.Automation.LanguagePrimitives.ConvertTo(Object valueToConvert, Type resultType, Boolean recursion, IFormatProvider formatProvider, TypeTable backupTypeTable) at System.Management.Automation.ParameterBinderBase.CoerceTypeAsNeeded(CommandParameterInternal argument, String parameterName, Type toType, ParameterCollectionTypeInformation collectionTypeInfo, Object currentValue) --- End of inner exception stack trace --- at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exception) at System.Management.Automation.Interpreter.ActionCallInstruction2.Run(InterpretedFrame 框架) 在 System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame 框架) 在 System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame 框架)

      【讨论】:

        猜你喜欢
        • 2021-12-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多