龙空技术网

PowerShell教程:9 结交大量用户!

启辰8 38

前言:

此刻大家对“winform非空验证”大概比较重视,你们都需要知道一些“winform非空验证”的相关知识。那么小编在网上汇集了一些有关“winform非空验证””的相关资讯,希望我们能喜欢,小伙伴们一起来学习一下吧!

本章涵盖:用于收集凭据对象和检查空值的其他参数选项构建 Windows 对话框以使用 GUI 浏览文件使用 While 循环检查空字符串或空字符串的新方法从逗号分隔值列表 (CSV) 读取数据

在最后一章中,我们在使生活更轻松方面向前迈出了一大步。我们现在有一个脚本,只需单击一下即可从头到尾在我们的域中创建用户,并带有一些简单的值。这太好了!但公司通常有某种入职程序来同时吸引一批员工。因此,作为 IT 专业人员,批量创建新用户的情况要普遍得多。

我们有一个脚本可以创建一个新用户,但是我们是否要一遍又一遍地运行它,也许是几十次?难道没有更简单的方法吗?有!

此脚本将:

接受特定类型的输入文件的路径:逗号分隔值 (CSV) 列表。接受用户名并提示输入 PSCredential 以在我们的 Exchange 服务器中进行身份验证。检查以确保用户名和密码不是简单的空。需要用户名和密码才能向 Exchange 服务器上的 PSSession 进行身份验证。检查是否已建立与 Exchange Server 的连接,如果没有,请使用提供的 PSCredentials 创建一个连接。检查是否提供了 CSV 文件的路径;如果没有,请创建一个 Windows 对话框以使用 Windows GUI 导航到该文件。读取每个CSV文件行,从特定标头中提取值,并将它们分配给脚本中的变量:FirstName,LastName和CopyFromUserSamAccountName。使用这些变量,脚本的功能与上一章中一样,创建唯一、有效的用户名、分配电子邮件地址,并为 CSV 中的每个用户复制相关的组成员身份。创建 CSV 中的最后一个用户后,脚本会将 PSSession 删除到 Exchange 服务器。9.1 项目代码

代码如下;像我们的其他脚本一样,我们将详细介绍它。以下是此脚本的一些特别注意事项。

param (    [Parameter(Mandatory=$false)]    #A    [string]$CSVLoc,    [Parameter(Mandatory=$true)]    [System.Management.Automation.PSCredential]$ExchangePassSecure    #B     )  function Connect-Exchange {    param (        $ExchangeServer,        $ExchangePassSecure    )    $Session = New-PSSession -ConfigurationName Microsoft.Exchange `        -ConnectionUri  `        -Authentication Kerberos -Credential $ExchangePassSecure    Import-PSSession $Session -DisableNameChecking    Return $Session}#Variable for the FQDN to your Exchange Server$ExchangeServer="exchange01.ForTheITPro.com" $Session=Get-PSSession|Where-Object {$.ConfigurationName -eq "Microsoft.Exchange"}if (-Not $Session){    $Session=Connect-Exchange $ExchangeServer $ExchangePassSecure} Function Get-File(){    #C  [System.Reflection.Assembly]::LoadWithPartialName(“System.windows.forms”)    | Out-Null    $FileDialogBox = New-Object System.Windows.Forms.OpenFileDialog    $FileDialogBox.filter = “csv (*.csv)| *.csv”    $FileDialogBox.ShowDialog() | Out-Null         return $FileDialogBox.filename    }    while ([string]::IsNullOrEmpty($CSVLoc){    #D    Write-Output "Navigate to the CSV file to create your users:"    $CSVLoc=Get-File   } $CSVInfo=Import-Csv -Path $CSVLoc    #E foreach ($user in $CSVInfo){    $LastName=$user.LastName    #F    $FirstName=$user.FirstName    $CopyFromUserSamAccountName=$user.CopyFromUser         $LastLength=$LastName.Length    if ($LastLength -ge 8){        $LastName=$LastName.Substring(0,7)    }    $UserName=$FirstName.Substring(0,1).ToLower()+$LastName.ToLower()    $dup=Get-ADUser -filter {SamAccountName -eq $UserName}    if ($null -ne $dup){        $i=1        do{            $TestName=$UserName+$i            $dup=Get-ADUser -filter {SamAccountName -eq $TestName}            $i++        }until ($null -eq $dup)    $UserName=$TestName        if ($UserName.Length -ge 8){            $UserName=$UserName.Substring(0,8)        }    }     $LogFile="C:\Logs\$UserName.log"    Write-Output "Creating user: $UserName"|Tee-Object $LogFile -Append    New-ADUser -Name $UserName -GivenName $FirstName -Surname $LastName `        -DisplayName $UserName -SamAccountName $UserName -Enabled $false        |Tee-Object $LogFile -Append    Start-Sleep 5    $Groups=(Get-ADUser -Identity $CopyFromUserSamAccountName -Properties MemberOf).MemberOf    $Groups|Add-ADGroupMember -Members $UserName    Write-Output "$UserName added to: $Groups"|Tee-Object $LogFile -Append    (Get-ADUser -Identity $UserName).SamAccountName|Enable-Mailbox    Write-Output "$(Get-Date) $UserName Account successfully created."|Tee-Object $LogFile -Append}Remove-PSSession $Session    #G
9.2 更多参数

我们在上一章中介绍了脚本参数。现在,我们将为脚本的这种非常强大的功能探索一些更有用的选项。

9.2.1 强制性

在上一章中,我们展示了如何使用 [参数(强制=$true)] 参数来提示用户输入必需的参数。但是,如果我们不希望参数是必需的,而是可选的,该怎么办?在这种情况下,我们可以将“强制”设置为 $false,这允许用户在运行脚本时预先提供或不预先提供该参数的值。例如,在本章的项目中,我们允许用户在调用脚本时选择输入其CSV文件的位置。这将节省用户的时间,因为他们不必导航到 CSV 文件。但是,如果他们不提供此参数,脚本仍然有效。

假设我们希望允许用户指定要存储日志的路径。我们可能希望将其创建为可以传递给脚本的参数。这样,如果我们的用户有一个他们喜欢保存所有日志的文件夹,则可以节省他们手动移动所有这些日志的时间。

param(    [Parameter (Mandatory=$true)]    $LogPath)Write-Output "All logs for this script will be sent to $LogPath"
图9.1 强制参数示例

9.2.2 使用 PSCredentials

这适用于路径,但是密码或凭据呢?

param(    [Parameter (Mandatory=$true)]    $Password)Write-Host "We'll use this $Password to login."
图9.2 明文密码示例

正如您在示例中所看到的,简单地将密码存储为字符串是一个不安全且糟糕的主意。幸运的是,使用 PowerShell,我们可以将用户名和密码存储为 PSCredential 对象,该对象永远不会以明文格式存储或传输我们的敏感登录信息。

9.2.3 系统.管理.自动化.PSCredential

我们可以通过在参数块中使用 System.Management.Automation.PSCredential 对象类型来解决这个不方便的问题。这将提示用户提供将成为 PSC redential 的有效用户名和密码。PSCredential 本质上是用户名和密码的占位符,用作处理此敏感信息的安全便捷方式。

param(    [Parameter (Mandatory=$true)]    [System.Management.Automation.PSCredential]$Password)Write-Host "We'll use this $Password to login."
图 9.3 使用 System.Management.Automation.PSCredential 方法可防止密码泄露。

9.2.4 我们如何在 Tiny PowerShell 脚本中使用它

现在,我们可以安全地请求并传递凭据,我们可以使用它与 Exchange Server 建立远程 PSSession 连接,以访问所有与 Exchange 相关的 cmdlet。

图 9.4 使用小型 PowerShell 项目代码中的参数。

但是,与上一章中所做的不同,我们不打算为计划添加到域的每个用户建立 Exchange 会话。通过将此功能置于循环之外,我们可以建立一次连接,为许多用户使用它,然后断开一次连接。

要了解其工作原理,让我们快速浏览一下此代码,其中包含循环内部和外部的语句。

$list=@(1,2,3,4,5)Write-Host "This is outside the loop."    #Aforeach ($number in $list){    Write-Host "This is within the loop"    #B}

通过了解哪些信息需要更改,以及哪些信息在脚本执行过程中可能不会更改,我们可以设计更智能的脚本,从而防止我们在使用此脚本创建批量用户时必须输入数十次、数百次甚至数千次相同的凭据。如果我们要将 Connect-Exchange 函数放在循环中,每次执行循环时,它都会尝试连接到交换服务器。通过将其保持在循环之外,我们可以通过连接一次,然后运行所有循环,最后在脚本结束时断开连接来防止这种行为。

9.3 为 GUI 创建对象

尽管我在命令行界面 (CLI) 中工作很舒服,但有时拥有图形用户界面 (GUI) 对象会使事情变得容易得多。在我们的脚本中,我们将使用逗号分隔值 (CSV) 表来帮助我们将大量用户添加到我们的系统。

完全可以提示用户输入此值的路径,并使用读取主机 cmdlet 读取响应。但是,如果返回的字符串有拼写错误怎么办?

我们可以添加一些错误检查以确保路径存在并包含文件。但是,如果用户键入另一个不正确的路径怎么办?在文件路径中出现两个小错误的想法可能位于远程共享或多个文件或几十个文件深度上,这并非太不可能。

我们可以循环访问我们的提示和错误检查,不断提示我们的用户输入路径。如果错误不是拼写错误,而只是混淆,用户键入 C:\tmp 而不是 C:\temp,该怎么办?或者,如果是断开连接或未映射的驱动器映射?J:\...如果没有映射“J”,对我们的脚本没有任何意义。这种缺乏可见性会增加很多挫败感和浪费时间。

如果我们不是执行所有这些操作,而是简单地构建了一个Windows对话框,允许用户浏览其系统并通过单击选择文件,该怎么办?此功能将立即清除上述一些问题,或者至少为我们的用户提供更好的位置来开始故障排除,而不是假设问题是脚本中的错误。

9.3.1 .网络程序集

还记得在前面的章节中,当我们讨论PowerShell语言的强大功能和灵活性时吗?PowerShell功能强大且灵活,因为它建立在.Net Framework上,就像其他Microsoft编码语言(如C#(C Sharp)一样)。

这意味着PowerShell可以像其他编程语言一样使用.Net Framework。我们将利用这种灵活性创建一个 Windows 对话框,并使用它来允许我们的用户选择他们需要的确切 CSV。

首先,我们首先需要加载程序集。

[System.Reflection.Assembly]::LoadWithPartialName(“System.windows.forms”)

从表面上看,这行代码并没有多大作用。但它做了什么?默认情况下,PowerShell不会加载很多.Net程序集。WinForms 程序集不是默认加载的少数程序集之一,因此我们必须告诉 PowerShell 我们要使用它。

什么是程序集?

程序集只是类型和资源的集合,旨在在 .Net 框架内作为一个单元协同工作。它是 .NET 中部署的基本单元。

9.3.2 对话框

加载此程序集后,我们可以开始使用与 WinForms 程序集关联的方法来创建对话框。

[System.Reflection.Assembly]::LoadWithPartialName(“System.windows.forms”)   #A$FileDialogBox = New-Object System.Windows.Forms.OpenFileDialog    #B$FileDialogBox.ShowDialog() | Out-Null#C

我们只需创建一个名为 $FileDialogBox 的新变量,并使用 WinForm 程序集的 OpenFileDialog 方法将其分配为 New-Object。这为我们节省了大量的时间和精力。我们可以使用 WinForm 程序集创建自定义表单和对象,其中包含按钮、边框、大小和表单的任何其他属性。

但是,我们的需求目前比这更简单。我们只是希望 Windows 为我们提供一个带有“打开”和“取消”框的标准对话框。这将满足我们目前的需求。

图 9.5 基本对话框示例。

9.3.3 我们如何在脚本中使用它

我们不要求用户输入文件的路径,而是利用 WinForms 程序集来创建一个简单的对话框。但是,由于我们的脚本使用非常特定的文件类型来帮助我们创建用户,即 CSV,因此我们希望确保用户仅选择 CSV 文件。

这可以通过“WinForms 程序集”对话框中的筛选方法完成。我们还希望确保将所选文件捕获为可以使用的变量。

在我们的脚本中,我们创建了一个函数来创建此对话框,过滤 .CSV 文件,然后将函数中的文件名返回到一个名为 $CSVLoc 的变量中

Function Get-File(){  [System.Reflection.Assembly]::LoadWithPartialName(“System.windows.forms”)    | Out-Null    $FileDialogBox = New-Object System.Windows.Forms.OpenFileDialog    $FileDialogBox.filter = “csv (*.csv)| *.csv”    #A    $FileDialogBox.ShowDialog() | Out-Null         return $FileDialogBox.filename    #B    }
9.4 更多循环

在这一点上,根据我们的PowerShell体验,我们对循环相当满意。自第4章以来,我们几乎在每个脚本中都使用了它们。但是有许多不同类型的循环。我们最熟悉的是foreach循环。我们可以使用 foreach 循环和 if 语句根据循环中项的值做出某种类型的决策。

例如,我们想让每一口大小达到 128 个:

$bits=(8,16,32,64,128,256,512)foreach ($size in $bits){    if ($size -le 128{        Write-Output $size    }}

如果我们不知道数组中值的顺序是什么,这种逻辑是一个很好的鉴别器。但是,在这种情况下,我们知道每次数字的大小都会翻倍。因此,与其拉入每个值并根据 if 语句的条件逻辑对其进行测试,不如将逻辑构建到循环本身中呢?

这就是 While 循环的用武之地。

9.4.1 while 循环

while 循环执行循环中的命令,而 while 语句中的条件逻辑计算为 true。它可以被认为是“当某事是真的时,做某事”。一旦 while 语句的条件逻辑不再计算为 true,循环就不再运行。

$byte=8    #Awhile ($byte -lt 256) {    #B    Write-Output $byte   #C    $byte=$byte*2    }

这种类型的逻辑对于数学很有用,但检查条件是否存在可能更有用。让我们看一些输入验证。

定义

输入验证只是我们用来测试应用程序收到的输入的合规性和兼容性的过程。输入验证可以帮助确保我们期望的数据类型是我们收到的。在许多情况下,我们收到的数据类型可能很重要。我们已经在前面的章节中讨论了字符串和整数等数据类型。输入验证可以帮助我们确保获得预期的数据类型,并可以防止代码后面出现重大错误。

我们可以使用 While 循环来确保用户输入路径供我们稍后在脚本中使用。

$path=Read-Host "What is the path to the file?"while ($path -eq ""){   Write-Output "Path cannot be empty."   $path=Read-Host "What is the path to the file?"}$path
图 9.6 非空字符串的输入验证示例。

9.4.2 我们如何在脚本中使用它。

因为我们需要CSV文件将我们的用户添加到Active Directory,所以我们需要确保我们的脚本指向我们的用户想要的CSV。我们已经了解了如何使用Windows对话框来帮助用户直接导航到文件。但是,该对话框同时包含“打开”按钮和“取消”。如果用户要单击“取消”,我们需要一种方法来检测它并重新提示用户输入正确的文件。

我们使用 While 循环在为 CSV 文件位置返回空值或空值时重新提示用户输入文件位置。

while ([string]::IsNullOrEmpty($CSVLoc)) {    #A    Write-Output "Navigate to the CSV file to create your users:"    $CSVLoc=Get-File    #B }
9.5 IsNull或Empty

正如您可能已经注意到的那样,在上面的 while 循环中,我们正在使用更多的 .Net。这一次,我们使用了一个字符串方法 IsNullOrEmpty。此方法将测试对象的字符串值是 null 还是空。

9.5.1 空和空的区别

当我们在前面的章节中讨论空值时,我们谈到了什么是空值。但是区分空值和空值可能会非常令人困惑。

空值是缺失或未知的值。它可以是有意设置为 $null 或根本不保存任何值的变量的值。

$valueif ($null -eq $value){    Write-Output '$value is $null.'}else{    Write-Output '$value is NOT $null.'}
图 9.7 空值示例。

但是,空值不是空值,而是空值。如果我们提示用户输入$value,则任何输入(即使是空白值)在技术上将不再为 null。

$value=Read-Host "What is the value you want?"if ($null -eq $value){    Write-Output '$value is $null.'}else{    Write-Output '$value is NOT $null.'}
图 9.8 非空示例。

我们可以在代码中使用另一个 if 语句检查空值:

$value=Read-Host "What is the value you want?"if ($null -eq $value){    Write-Output '$value is $null.'}else{    Write-Output '$value is NOT $null.'    if ($value -eq ""){        Write-Output '$value is empty.'    }else{        Write-Output '$value is NOT empty.'    }}
图 9.9 非空但为空的字符串示例。

9.5.2 检查空值和空值

通过对字符串值使用 “IsNullOrEmpty” 方法,我们可以使用单个检查来检查任一条件。这不仅减少了键入的代码,而且更容易理解。if/else 语句的嵌套逻辑可能会令人困惑且难以调试。

$value=$nullif ([string]::IsNullOrEmpty($value)){    Write-Output '$value is Null or Empty'}$value=Read-Host "What is the value you want?"if ([string]::IsNullOrEmpty($value)){    Write-Output '$value is Null or Empty'}
图 9.10 IsNullOrEmpty 查找空字符串和空字符串。

9.5.3 我们如何在脚本中使用它。

最初运行脚本时,可能不会定义 CSVLoc 变量。这将为变量生成一个$null值。由于脚本的其余部分需要此路径才能正常工作,因此我们希望触发 Get-File 函数以提示用户浏览到 CSV 文件位置。

但是,作为输入验证的一部分,如果用户在选择 CSV 之前关闭窗口或点击取消,会发生什么情况?在这种情况下,该值将为 null,但为空。

与其编写嵌套的 if/else 语句,我们可以在 While 循环中放置一个检查,以继续提示我们的用户输入有效的 CSV 位置,直到他们成功浏览到文件并单击“打开”。

while ([string]::IsNullOrEmpty($CSVLoc)) {    #A    Write-Output "Navigate to the CSV file to create your users:"    $CSVLoc=Get-File }
9.6 导入 CSV

在最简单的形式中,CSV 是一个包含以逗号分隔的值的文件。通过使用导入 CSV cmdlet,我们指示 PowerShell 从 CSV 文件创建自定义对象的集合。由于文件类型,打开 CSV 文件类型的程序可以识别结构化数据,而不是简单地显示原始数据(逗号分隔格式)。这允许轻松构造和操作表。

原始 CSV 文件可以在任何文本编辑器中读取,但文件类型的真正功能和灵活性是当您使用 Excel 等电子表格程序创建或修改它们时。

"President, Order, YearsGeorge Washington, 1, 8John Adams, 2, 4Thomas Jefferson, 3, 8James Madison, 4, 8"|out-file c:\temp\presidents.csv

通过编写输出并用逗号分隔值,用行分隔行,我们可以使用 PowerShell 创建 CSV。

图 9.11 我们创建的 CSV 文件可以在 Excel 中轻松打开。

图 9.12 在 Excel 中打开 CSV 的数据中不再包含任何逗号。

Excel 可用于操作数据、执行计算、分离文本、合并单元格以及人们每天使用 Excel 的所有许多强大功能。我能够通过复制和粘贴在国会图书馆找到的数据来更新我微薄的总统名单。然后,我将开始年份和结束年份分解为单独的列,并使用计算函数来生成术语。然后将数据重新保存为总统2.csv。

图 9.13 是 CSV 功能的示例。

即使包含所有链接、合并、计算和其他 Excel 操作,CSV 仍然只是一个逗号分隔值的文件。这些值可以使用 Import-CSV cmdlet 导入到 PowerShell 中,并且由于它是 CSV,因此 PowerShell 将数据作为结构化数据本机读取。

图 9.14 导入 CSV 会将数据结构引入 PowerShell。

9.6.1 我们如何在脚本中使用它

要生成一个新用户,我们需要为脚本提供三条基本信息:名字、姓氏和我们要从中复制权限的用户。由于 Excel 在当今的商业中无处不在,因此我们被要求创建的用户的名字和姓氏很可能已经采用 Excel 格式。

我们可以轻松地在Excel中创建CSV,其中包括我们将要创建的每个用户的名字,姓氏和CopyFromUser信息。

导入 CSV cmdlet 将用于帮助 PowerShell 了解此数据的结构,以便我们可以使用它来创建用户。

$CSVInfo=Import-Csv -Path $CSVLoc
9.7 CSV 中的定位

PowerShell 了解此结构化数据的好处之一是,我们可以使用标头信息来定位特定单元格。

图 9.15 PowerShell 按标头分解数据。

PowerShell 读取数据并为每个数据创建属性。“术语”、“名称”、“起始年份,...等都被视为我们集合中每个对象的属性。

我们可以使用点表示法仅引用单个列中的值。

$PresInfo=Import-Csv C:\temp\presidents2.csv$PresInfo.name
图 9.16 使用点表示法选择列。

当我们将对象集合分配给变量“PresInfo”时,我们可以使用点表示法来隔离该对象集合中每个对象的特定属性。

通过循环访问数据,我们可以隔离每个单元格并操作任何给定单元格的内容。例如,我们只关心总统的姓名和任期。我们可以修改 CSV 文件,删除这些列。但有时我们需要这些数据。或者我们可能没有修改原始文件的权限。使用 PowerShell,我们可以隔离和显示我们想要的值,并以我们希望的任何方式对它们进行排序。

$PresInfo=Import-Csv C:\temp\presidents2.csvforeach ($Row in $PresInfo){    $name=$Row.name    $term=$Row.term    Write-Output "$name served a term of $term years in office."}
9.17 使用 foreach 和点表示法来定位特定单元格。

9.7.1 我们如何在脚本中使用它

要创建我们的用户,我们需要三条信息:

一个名字一个姓氏要从中复制组成员身份的用户

通过为我们要创建的每个新用户收集此信息并将其存储在 CSV 文件中,我们可以使用此文件作为脚本此信息的输入源。

这使我们能够简单地将PowerShell指向信息的位置,PowerShell将导入CSV并使用点表示法来提取它为CSV中的每个条目创建用户所需的数据片段。请记住,这些标题需要与您用于引用它们的点表示法完全对应。

$CSVInfo=Import-Csv -Path $CSVLoc    #A foreach ($user in $CSVInfo){    $LastName=$user.LastName    #B    $FirstName=$user.FirstName    #B    $CopyFromUserSamAccountName=$user.CopyFromUser     
9.8 小结

在上一章中,我们开发了一个脚本,使我们能够轻松创建Windows域帐户。使用脚本需要操作员为脚本提供名字、姓氏和用户以从中复制组成员身份。这在创建单个用户时非常有用!但是,一遍又一遍地运行脚本并手动提供要从中复制的名字、姓氏和用户是很乏味的。我们可以利用 Excel 的许多强大的电子表格工具为要创建的每个用户创建一个包含此信息的 CSV 文件,其中包含此信息,而不是一次输入一个信息。通过使用包含名字、姓氏和用户从中复制权限的 CSV 文件,我们可以使用单个脚本在我们的域上创建数十、数百甚至数千个用户。

使用System.Management.Automation.PSCredentials允许我们在称为PSCredential对象的安全方便的存储对象中收集用户名和密码。使用.Net Assemblies,我们可以从头开始构造自定义对象,从而为PowerShell提供类似于C#的整个框架的灵活性。使用这些.Net程序集(WinForms)之一,我们可以制作Windows对话框,以允许用户浏览使用GUI输入文件While 循环在$True条件时执行循环中的指令。每次执行循环后,它都会测试条件,如果条件的计算结果不再为 $True,则循环退出。空值和空值之间存在差异。检查这两者通常需要两个单独的检查。我们学习了如何使用 .Net 检查 IsNullOrEmpty 条件,允许对这两个条件进行一次检查。使用导入 CSV cmdlet,我们可以导入具有从 CSV 结构中提取的属性的对象集合。这使我们能够轻松地定位集合中的特定属性,以便在脚本中使用。使用点表示法,我们可以定位从 CSV 文件导入的对象集合的特定属性。这使我们能够创建单个 CSV,以通过一次执行脚本来创建数十、数百甚至数千个用户。

标签: #winform非空验证